X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?a=blobdiff_plain;f=ginac%2Fptr.h;h=6460fe106990feac6e9a41bcbd6d41e98f80ee90;hb=5252d38313c423465b9bc37b0618cb8de96d0d4e;hp=fd380506fdd6daaec5183e94f8557c7306f51f4c;hpb=6eedac996204ebc3355807d7f887b0c366cb3c07;p=ginac.git diff --git a/ginac/ptr.h b/ginac/ptr.h index fd380506..6460fe10 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-2009 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,25 +17,41 @@ * * 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() throw() : refcount(0) {} + + unsigned int add_reference() throw() { return ++refcount; } + unsigned int remove_reference() throw() { return --refcount; } + unsigned int get_refcount() const throw() { return refcount; } + void set_refcount(unsigned int r) throw() { 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 >; @@ -48,26 +64,29 @@ public: // 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) throw() : 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) throw() : p(&t) { p->add_reference(); } - ptr(const ptr & other) throw() : p(other.p) { ++p->refcount; } + ptr(const ptr & other) throw() : 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; } @@ -80,10 +99,10 @@ public: * 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; } } @@ -122,6 +141,7 @@ public: inline friend std::ostream & operator<<(std::ostream & os, const ptr & rhs) { os << rhs.p; + return os; } private: @@ -130,6 +150,7 @@ private: } // namespace GiNaC + namespace std { /** Specialization of std::less for ptr to enable ordering of ptr @@ -144,4 +165,4 @@ template struct less< GiNaC::ptr > } // namespace std -#endif // ndef __GINAC_PTR_H__ +#endif // ndef GINAC_PTR_H