X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fptr.h;h=baf0f991c15271c25a0d1a4ad5c7d4d5b40d8e6c;hp=1d1b49d2c94e78ebbe430bb8e2d6ef10baec3ebe;hb=f2051c351d8f9791a4afcc8d03465bf100a8088d;hpb=68fdf425abf14d016d5f95ee7b9d06a19a3c5926 diff --git a/ginac/ptr.h b/ginac/ptr.h index 1d1b49d2..baf0f991 100644 --- a/ginac/ptr.h +++ b/ginac/ptr.h @@ -3,7 +3,7 @@ * Reference-counted pointer template. */ /* - * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,79 +17,98 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __GINAC_PTR_H__ -#define __GINAC_PTR_H__ +#ifndef GINAC_PTR_H +#define GINAC_PTR_H +#include "assertion.h" + +#include // for size_t #include #include -#include "assertion.h" - namespace GiNaC { +/** Base class for reference-counted objects. */ +class refcounted { +public: + refcounted() noexcept : refcount(0) {} + + unsigned int add_reference() noexcept { return ++refcount; } + unsigned int remove_reference() noexcept { return --refcount; } + unsigned int get_refcount() const noexcept { return refcount; } + void set_refcount(unsigned int r) noexcept { refcount = r; } + +private: + unsigned int refcount; ///< reference counter +}; + + /** Class of (intrusively) reference-counted pointers that support * copy-on-write semantics. * * Requirements for T: - * T::refcount member that supports ++refcount, --refcount, refcount = 1, - * refcount == 0 and refcount > 1 + * must support the refcounted interface (usually by being derived + * from refcounted) * T* T::duplicate() member function (only if makewriteable() is used) */ template class ptr { - friend class std::less< ptr >; + friend struct std::less>; // NB: This implementation of reference counting is not thread-safe. // The reference counter needs to be incremented/decremented atomically, // and makewritable() requires locking. public: - // no default ctor: a ptr is never unbound + // no default ctor: a ptr is never unbound /** Bind ptr to newly created object, start reference counting. */ - ptr(T *t) : p(t) { GINAC_ASSERT(p); p->refcount = 1; } + ptr(T *t) noexcept : p(t) { GINAC_ASSERT(p); p->set_refcount(1); } /** Bind ptr to existing reference-counted object. */ - explicit ptr(T &t) : p(&t) { ++p->refcount; } + explicit ptr(T &t) noexcept : p(&t) { p->add_reference(); } - ptr(const ptr & other) : p(other.p) { ++p->refcount; } + ptr(const ptr & other) noexcept : p(other.p) { p->add_reference(); } ~ptr() { - if (--p->refcount == 0) + if (p->remove_reference() == 0) delete p; } ptr &operator=(const ptr & other) { - // NB: must first increment other.p->refcount, since other might be *this. - ++other.p->refcount; - if (--p->refcount == 0) + // NB1: Must first add reference to "other", since other might be *this. + // NB2: Cache other.p, because if "other" is a subexpression of p, + // deleting p will also invalidate "other". + T *otherp = other.p; + otherp->add_reference(); + if (p->remove_reference() == 0) delete p; - p = other.p; + p = otherp; return *this; } - T &operator*() const { return *p; } - T *operator->() const { return p; } + T &operator*() const noexcept { return *p; } + T *operator->() const noexcept { return p; } - friend inline T *get_pointer(const ptr & x) { return x.p; } + friend inline T *get_pointer(const ptr & x) noexcept { return x.p; } /** Announce your intention to modify the object bound to this ptr. * This ensures that the object is not shared by any other ptrs. */ void makewritable() { - if (p->refcount > 1) { + if (p->get_refcount() > 1) { T *p2 = p->duplicate(); - p2->refcount = 1; - --p->refcount; + p2->set_refcount(1); + p->remove_reference(); p = p2; } } /** Swap the bound object of this ptr with another ptr. */ - void swap(ptr & other) + void swap(ptr & other) noexcept { T *t = p; p = other.p; @@ -102,26 +121,27 @@ public: // to different (probably derived) types and raw pointers. template - bool operator==(const ptr & rhs) const { return p == get_pointer(rhs); } + bool operator==(const ptr & rhs) const noexcept { return p == get_pointer(rhs); } template - bool operator!=(const ptr & rhs) const { return p != get_pointer(rhs); } + bool operator!=(const ptr & rhs) const noexcept { return p != get_pointer(rhs); } template - inline friend bool operator==(const ptr & lhs, const U * rhs) { return lhs.p == rhs; } + inline friend bool operator==(const ptr & lhs, const U * rhs) noexcept { return lhs.p == rhs; } template - inline friend bool operator!=(const ptr & lhs, const U * rhs) { return lhs.p != rhs; } + inline friend bool operator!=(const ptr & lhs, const U * rhs) noexcept { return lhs.p != rhs; } template - inline friend bool operator==(const U * lhs, const ptr & rhs) { return lhs == rhs.p; } + inline friend bool operator==(const U * lhs, const ptr & rhs) noexcept { return lhs == rhs.p; } template - inline friend bool operator!=(const U * lhs, const ptr & rhs) { return lhs != rhs.p; } + inline friend bool operator!=(const U * lhs, const ptr & rhs) noexcept { return lhs != rhs.p; } inline friend std::ostream & operator<<(std::ostream & os, const ptr & rhs) { os << rhs.p; + return os; } private: @@ -130,12 +150,12 @@ private: } // namespace GiNaC + namespace std { /** Specialization of std::less for ptr to enable ordering of ptr * objects (e.g. for the use as std::map keys). */ -template struct less< GiNaC::ptr > - : public binary_function, GiNaC::ptr, bool> { +template struct less> { bool operator()(const GiNaC::ptr &lhs, const GiNaC::ptr &rhs) const { return less()(lhs.p, rhs.p); @@ -144,4 +164,4 @@ template struct less< GiNaC::ptr > } // namespace std -#endif // ndef __GINAC_UTILS_H__ +#endif // ndef GINAC_PTR_H