/** 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));
}
hashvalue = other.hashvalue;
}
flags = fl;
- refcount = 0;
+ set_refcount(0);
return *this;
}
//////////
/** 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;
* 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);
}
#include "flags.h"
#include "tinfos.h"
+#include "ptr.h"
#include "assertion.h"
#include "registrar.h"
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;
};
-/** 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);
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)
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>
};
{
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.
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;
// 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
// 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;
}
}
default:
basic *bp = new numeric(i);
bp->setflag(status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount == 0);
+ GINAC_ASSERT(bp->get_refcount() == 0);
return *bp;
}
}
default:
basic *bp = new numeric(i);
bp->setflag(status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount == 0);
+ GINAC_ASSERT(bp->get_refcount() == 0);
return *bp;
}
}
default:
basic *bp = new numeric(i);
bp->setflag(status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount == 0);
+ GINAC_ASSERT(bp->get_refcount() == 0);
return *bp;
}
}
default:
basic *bp = new numeric(i);
bp->setflag(status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount == 0);
+ GINAC_ASSERT(bp->get_refcount() == 0);
return *bp;
}
}
{
basic *bp = new numeric(d);
bp->setflag(status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount == 0);
+ GINAC_ASSERT(bp->get_refcount() == 0);
return *bp;
}
#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> >;
// 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;
* 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;
}
}
} // namespace GiNaC
+
namespace std {
/** Specialization of std::less for ptr<T> to enable ordering of ptr<T>
// 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