From 0a5049a0354466a88862c67b1b9c9e27e36cc309 Mon Sep 17 00:00:00 2001 From: Christian Bauer Date: Fri, 29 Aug 2003 17:36:02 +0000 Subject: [PATCH 1/1] moved the reference counter into its own class "refcounted" --- ginac/basic.cpp | 8 ++++---- ginac/basic.h | 16 ++++++---------- ginac/ex.cpp | 18 +++++++++--------- ginac/ptr.h | 42 ++++++++++++++++++++++++++++++------------ ginac/symbol.h | 5 +---- 5 files changed, 50 insertions(+), 39 deletions(-) diff --git a/ginac/basic.cpp b/ginac/basic.cpp index b8690079..01a29011 100644 --- a/ginac/basic.cpp +++ b/ginac/basic.cpp @@ -55,7 +55,7 @@ GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(basic, void, /** basic copy constructor: implicitly assumes that the other class is of * the exact same type (as it's used by duplicate()), so it can copy the * tinfo_key and the hash value. */ -basic::basic(const basic & other) : tinfo_key(other.tinfo_key), flags(other.flags & ~status_flags::dynallocated), hashvalue(other.hashvalue), refcount(0) +basic::basic(const basic & other) : tinfo_key(other.tinfo_key), flags(other.flags & ~status_flags::dynallocated), hashvalue(other.hashvalue) { GINAC_ASSERT(typeid(*this) == typeid(other)); } @@ -74,7 +74,7 @@ const basic & basic::operator=(const basic & other) hashvalue = other.hashvalue; } flags = fl; - refcount = 0; + set_refcount(0); return *this; } @@ -93,7 +93,7 @@ const basic & basic::operator=(const basic & other) ////////// /** Construct object from archive_node. */ -basic::basic(const archive_node &n, lst &sym_lst) : flags(0), refcount(0) +basic::basic(const archive_node &n, lst &sym_lst) : flags(0) { // Reconstruct tinfo_key from class name std::string class_name; @@ -866,7 +866,7 @@ const basic & basic::hold() const * is not the case. */ void basic::ensure_if_modifiable() const { - if (refcount > 1) + if (get_refcount() > 1) throw(std::runtime_error("cannot modify multiply referenced object")); clearflag(status_flags::hash_calculated | status_flags::evaluated); } diff --git a/ginac/basic.h b/ginac/basic.h index d50c7ca3..e4c4b09b 100644 --- a/ginac/basic.h +++ b/ginac/basic.h @@ -31,6 +31,7 @@ #include "flags.h" #include "tinfos.h" +#include "ptr.h" #include "assertion.h" #include "registrar.h" @@ -43,7 +44,6 @@ class numeric; class relational; class archive_node; class print_context; -template class ptr; typedef std::vector exvector; typedef std::map exmap; @@ -66,25 +66,23 @@ protected: }; -/** This class is the ABC (abstract base class) of GiNaC's class hierarchy. - * It is responsible for the reference counting. */ -class basic +/** This class is the ABC (abstract base class) of GiNaC's class hierarchy. */ +class basic : public refcounted { GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(basic, void) friend class ex; - friend class ptr; // default constructor, destructor, copy constructor and assignment operator protected: - basic() : tinfo_key(TINFO_basic), flags(0), refcount(0) {} + basic() : tinfo_key(TINFO_basic), flags(0) {} public: /** basic destructor, virtual because class ex will delete objects of * derived classes via a basic*. */ virtual ~basic() { - GINAC_ASSERT((!(flags & status_flags::dynallocated))||(refcount==0)); + GINAC_ASSERT((!(flags & status_flags::dynallocated)) || (get_refcount() == 0)); } basic(const basic & other); const basic & operator=(const basic & other); @@ -92,7 +90,7 @@ public: protected: /** Constructor with specified tinfo_key (used by derived classes instead * of the default constructor to avoid assigning tinfo_key twice). */ - basic(unsigned ti) : tinfo_key(ti), flags(0), refcount(0) {} + basic(unsigned ti) : tinfo_key(ti), flags(0) {} // new virtual functions which can be overridden by derived classes public: // only const functions please (may break reference counting) @@ -231,8 +229,6 @@ protected: unsigned tinfo_key; ///< typeinfo mutable unsigned flags; ///< of type status_flags mutable unsigned hashvalue; ///< hash value -private: - size_t refcount; ///< reference counter, managed by ptr }; diff --git a/ginac/ex.cpp b/ginac/ex.cpp index 4a41ea8f..40a7de2f 100644 --- a/ginac/ex.cpp +++ b/ginac/ex.cpp @@ -239,7 +239,7 @@ void ex::makewriteable() { GINAC_ASSERT(bp->flags & status_flags::dynallocated); bp.makewritable(); - GINAC_ASSERT(bp->refcount == 1); + GINAC_ASSERT(bp->get_refcount() == 1); } /** Share equal objects between expressions. @@ -249,7 +249,7 @@ void ex::share(const ex & other) const if ((bp->flags | other.bp->flags) & status_flags::not_shareable) return; - if (bp->refcount <= other.bp->refcount) + if (bp->get_refcount() <= other.bp->get_refcount()) bp = other.bp; else other.bp = bp; @@ -287,7 +287,7 @@ ptr ex::construct_from_basic(const basic & other) // it means that eval() hit case b) above. The original object is // no longer needed (it evaluated into something different), so we // delete it (because nobody else will). - if ((other.refcount==0) && (other.flags & status_flags::dynallocated)) + if ((other.get_refcount() == 0) && (other.flags & status_flags::dynallocated)) delete &other; // yes, you can apply delete to a const pointer // We can't return a basic& here because the tmpex is destroyed as @@ -310,7 +310,7 @@ ptr ex::construct_from_basic(const basic & other) // on the heap. basic *bp = other.duplicate(); bp->setflag(status_flags::dynallocated); - GINAC_ASSERT(bp->refcount == 0); + GINAC_ASSERT(bp->get_refcount() == 0); return bp; } } @@ -372,7 +372,7 @@ basic & ex::construct_from_int(int i) default: basic *bp = new numeric(i); bp->setflag(status_flags::dynallocated); - GINAC_ASSERT(bp->refcount == 0); + GINAC_ASSERT(bp->get_refcount() == 0); return *bp; } } @@ -409,7 +409,7 @@ basic & ex::construct_from_uint(unsigned int i) default: basic *bp = new numeric(i); bp->setflag(status_flags::dynallocated); - GINAC_ASSERT(bp->refcount == 0); + GINAC_ASSERT(bp->get_refcount() == 0); return *bp; } } @@ -470,7 +470,7 @@ basic & ex::construct_from_long(long i) default: basic *bp = new numeric(i); bp->setflag(status_flags::dynallocated); - GINAC_ASSERT(bp->refcount == 0); + GINAC_ASSERT(bp->get_refcount() == 0); return *bp; } } @@ -507,7 +507,7 @@ basic & ex::construct_from_ulong(unsigned long i) default: basic *bp = new numeric(i); bp->setflag(status_flags::dynallocated); - GINAC_ASSERT(bp->refcount == 0); + GINAC_ASSERT(bp->get_refcount() == 0); return *bp; } } @@ -516,7 +516,7 @@ basic & ex::construct_from_double(double d) { basic *bp = new numeric(d); bp->setflag(status_flags::dynallocated); - GINAC_ASSERT(bp->refcount == 0); + GINAC_ASSERT(bp->get_refcount() == 0); return *bp; } diff --git a/ginac/ptr.h b/ginac/ptr.h index fd380506..93b16416 100644 --- a/ginac/ptr.h +++ b/ginac/ptr.h @@ -23,6 +23,7 @@ #ifndef __GINAC_PTR_H__ #define __GINAC_PTR_H__ +#include // for size_t #include #include @@ -30,12 +31,28 @@ namespace GiNaC { + +/** Base class for reference-counted objects. */ +class refcounted { +public: + refcounted() throw() : refcount(0) {} + + size_t add_reference() throw() { return ++refcount; } + size_t remove_reference() throw() { return --refcount; } + size_t get_refcount() const throw() { return refcount; } + void set_refcount(size_t r) throw() { refcount = r; } + +private: + size_t 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,24 +65,24 @@ 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) + // NB: must first add reference to "other", since other might be *this. + other.p->add_reference(); + if (p->remove_reference() == 0) delete p; p = other.p; return *this; @@ -80,10 +97,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; } } @@ -130,6 +147,7 @@ private: } // namespace GiNaC + namespace std { /** Specialization of std::less for ptr to enable ordering of ptr diff --git a/ginac/symbol.h b/ginac/symbol.h index bacd59fa..ab2d52a5 100644 --- a/ginac/symbol.h +++ b/ginac/symbol.h @@ -43,14 +43,11 @@ class symbol : public basic // types /** Symbols as keys to expressions - only for ginsh. */ - class assigned_ex_info { - friend class ptr; + class assigned_ex_info : public refcounted { public: assigned_ex_info() throw(); ///< Default ctor bool is_assigned; ///< True if there is an expression assigned ex assigned_expression; ///< The actual expression - private: - size_t refcount; ///< Reference counter, managed by ptr }; // member functions -- 2.45.2