moved the reference counter into its own class "refcounted"
authorChristian Bauer <Christian.Bauer@uni-mainz.de>
Fri, 29 Aug 2003 17:36:02 +0000 (17:36 +0000)
committerChristian Bauer <Christian.Bauer@uni-mainz.de>
Fri, 29 Aug 2003 17:36:02 +0000 (17:36 +0000)
ginac/basic.cpp
ginac/basic.h
ginac/ex.cpp
ginac/ptr.h
ginac/symbol.h

index b86900795d950c542bf5f0dc9e281c6c4063fc4e..01a29011152a9c9ff7b58620e7a0da71c7561d75 100644 (file)
@@ -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);
 }
index d50c7ca34eb73d916e9f93fb2c38d3d28e0a71e6..e4c4b09b53daa61e4a4e7f481a989a4185a75d08 100644 (file)
@@ -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> class ptr;
 
 typedef std::vector<ex> exvector;
 typedef std::map<ex, ex, ex_is_less> 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<basic>;
        
        // 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<basic>
 };
 
 
index 4a41ea8f00ae59c50b0cc3591db309fa2d5fae03..40a7de2fefe1a51cdabd570bdec8ff33297e7fd4 100644 (file)
@@ -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<basic> 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<basic> 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;
 }
 
index fd380506fdd6daaec5183e94f8557c7306f51f4c..93b16416f5471d9bd9eb165fd7d159767a3f2522 100644 (file)
@@ -23,6 +23,7 @@
 #ifndef __GINAC_PTR_H__
 #define __GINAC_PTR_H__
 
+#include <cstddef> // for size_t
 #include <functional>
 #include <iosfwd>
 
 
 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 T> class ptr {
        friend class std::less< ptr<T> >;
@@ -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<T> to enable ordering of ptr<T>
index bacd59fa370a9f49c2347e97c50be6d5d60aa2b9..ab2d52a5477f78ea93d2dd7e2c51f15ff63fb2ac 100644 (file)
@@ -43,14 +43,11 @@ class symbol : public basic
 // types
        
        /** Symbols as keys to expressions - only for ginsh. */
-       class assigned_ex_info {
-               friend class ptr<assigned_ex_info>;
+       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<assigned_ex_info>
        };
 
 // member functions