X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?a=blobdiff_plain;f=ginac%2Fptr.h;h=a2e9d8fe61b70a629391e085e5d3eaf8cb34c17b;hb=761d1597532504762c1f9b438c7727c4f74d7da3;hp=fd380506fdd6daaec5183e94f8557c7306f51f4c;hpb=6eedac996204ebc3355807d7f887b0c366cb3c07;p=ginac.git diff --git a/ginac/ptr.h b/ginac/ptr.h index fd380506..a2e9d8fe 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-2017 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) throw() : 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) throw() : p(&t) { ++p->refcount; } + explicit ptr(T &t) noexcept : p(&t) { p->add_reference(); } - ptr(const ptr & other) throw() : 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 throw() { return *p; } - T *operator->() const throw() { return p; } + T &operator*() const noexcept { return *p; } + T *operator->() const noexcept { return p; } - friend inline T *get_pointer(const ptr & x) throw() { 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) throw() + 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 throw() { return p == get_pointer(rhs); } + bool operator==(const ptr & rhs) const noexcept { return p == get_pointer(rhs); } template - bool operator!=(const ptr & rhs) const throw() { 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) throw() { 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) throw() { 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) throw() { 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) throw() { 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_PTR_H__ +#endif // ndef GINAC_PTR_H