// refptr.h:
// reference-counting "pointer" object for handling pointers
// to reference-counted objects implementing the following interface:
// void ref() increment refcount
// void deref() decrement refcount
// unsigned nref() get refcount
#ifndef INCL_REFPTR_H
#define INCL_REFPTR_H
#include "JLCast.h"
#include <assert.h>
////////////////////////////////////////////////////////////////////////////
// Generic reference-counter class. Inheriting from this is an easy way to
// get the functionality required by refcnt_ptr<T>. However, that is not
// necessary, since refcnt_ptr<T> is a template and you can implement the
// ref(), deref(), and nref() methods however you like. Note that ref() and
// deref() both must work for const objects.
////////////////////////////////////////////////////////////////////////////
class RefCount
{
public:
// default ctor
RefCount() : refcount(0) {}
// copy ctor *does not* copy refcount value
RefCount(const RefCount&) : refcount(0) {}
// assignment operator *does not* copy refcount
RefCount& operator=(const RefCount&) { return *this; }
// Public interface
// Allow refcount operations on const objects
void ref() const { ((RefCount*)this)->refcount++; }
void deref() const { ((RefCount*)this)->refcount--; }
unsigned short nref() const { return refcount; }
protected:
// Only let destruction occur via derived class, because
// this is not a virtual dtor
~RefCount() {}
private:
unsigned short refcount;
};
// Reference-counter base class with virtual dtor, so that objects
// may be deleted by pointer-to-VRefCount
class VRefCount : public RefCount
{
public:
// no need to implement ctor or operator=, as memberwise copy is sufficient
virtual ~VRefCount() {}
};
////////////////////////////////////////////////////////////////////////////
// Const reference-counted pointer
////////////////////////////////////////////////////////////////////////////
// forward declarations
template <class T> class refcnt_ptr;
template <class T> class refcnt_ptrI;
template <class T> class refcnt_cptrI;
////////////////////////////////////////////////////////////////////////////
// const ref-counted ptr
template<class T> class refcnt_cptr {
friend class refcnt_ptr<T>;
public:
// Basic ctor
refcnt_cptr(const T* ptr_ = 0);
// copy ctor
refcnt_cptr(const refcnt_cptr& rhs);
// dtor
~refcnt_cptr();
// Access to pointer
const T* get() const { return ptr; }
const T* operator->() const { return get(); }
const T& operator*() const { return *get(); }
// assignment from dumb pointer
refcnt_cptr& operator=(const T* rhs);
// Assignment from smart const pointer (also supports non-const)
refcnt_cptr& operator=(const refcnt_cptr& rhs);
// Comparison (also supports comparison to non-const ptr)
bool operator==(const refcnt_cptr& rhs) const
{
return ptr == rhs.get();
}
bool operator!=(const refcnt_cptr& rhs) const
{
return ptr != rhs.get();
}
// Used for ordering in maps
bool operator<(const refcnt_cptr& rhs) const
{
return ptr < rhs.get();
}
private:
// Decrement refcount on pointed-to object and delete if zero
void release();
void ref() const;
void deref() const;
const T* ptr;
};
//
// This are outside of the class because MSVC++ instantiates everything
// declared in the class even if it isn't used
//
template<class T>
inline refcnt_cptr<T>::refcnt_cptr(const T* ptr_) : ptr(ptr_)
{
if (ptr) ref();
}
template<class T>
inline refcnt_cptr<T>::refcnt_cptr(const refcnt_cptr& rhs) : ptr(rhs.get())
{
if (ptr) ref();
}
template<class T>
inline refcnt_cptr<T>::~refcnt_cptr()
{
release();
}
template<class T>
inline refcnt_cptr<T>& refcnt_cptr<T>::operator=(const T* rhs)
{
// works for this->ptr == rhs
if (rhs)
{
rhs->ref();
}
release();
ptr = rhs;
return *this;
}
template<class T>
inline refcnt_cptr<T>& refcnt_cptr<T>::operator=(const refcnt_cptr& rhs)
{
// works for rhs==this
if (rhs.get())
{
rhs.ref();
}
release();
ptr = rhs.get();
return *this;
}
template<class T>
inline void refcnt_cptr<T>::release()
{
if (ptr)
{
if (ptr->nref() == 1)
{
// allow deletion of const object
delete CONST_CAST(T*, ptr);
} else {
deref();
}
ptr = 0;
}
}
template<class T>
inline void refcnt_cptr<T>::ref() const
{
ptr->ref();
}
template<class T>
inline void refcnt_cptr<T>::deref() const
{
ptr->deref();
}
////////////////////////////////////////////////////////////////////////////
// non-const refcounted ptr -- note that a "const refcnt_ptr<T>" is *not* the
// same as a "refcnt_cptr<T>" -- the former still allows access to
// the non-const pointed-to object
////////////////////////////////////////////////////////////////////////////
template<class T> class refcnt_ptr : public refcnt_cptr<T>
{
public:
// basic ctor
refcnt_ptr(T* ptr_ = 0);
// copy ctor
// Don't allow construction from refcnt_cptr
refcnt_ptr(const refcnt_ptr& rhs);
// assignment operators
// Don't allow assignment from refcnt_cptr
refcnt_ptr& operator=(const refcnt_ptr& rhs);
refcnt_ptr& operator=(T* rhs);
// Access operators (non-const access to object)
T* get() const { return CONST_CAST(T*, ptr); }
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
};
//
// This are outside of the class because MSVC++ instantiates everything
// declared in the class even if it isn't used
//
template<class T>
inline refcnt_ptr<T>::refcnt_ptr(T* ptr_) :
refcnt_cptr<T>(ptr_)
{}
template<class T>
inline refcnt_ptr<T>::refcnt_ptr(const refcnt_ptr& rhs) :
refcnt_cptr<T>(rhs.get())
{}
template<class T>
inline refcnt_ptr<T>& refcnt_ptr<T>::operator=(const refcnt_ptr& rhs)
{
refcnt_cptr<T>::operator=(rhs);
return *this;
}
template<class T>
inline refcnt_ptr<T>& refcnt_ptr<T>::operator=(T* rhs)
{
refcnt_cptr<T>::operator=(rhs);
return *this;
}
////////////////////////////////////////////////////////////////////////////
// Implementation of "incomplete" ref-counted pointers. These are really
// ref-counted pointers to VRefCount, which implements rec-counting and
// and has a virtual destructor.
// These are used so that:
// 1) A refcounted pointer to an object can be used, passed by value,
// without knowing the object implementation.
// 2) Use of said incomplete refcounted pointer will still delete the
// object when the refcount drops to zero.
// 3) Casting between the incomplete type and the complete type can
// be done implicitly.
// 4) The types of incomplete refcounted pointers are distinct.
//
// Since casting between T and VRefCount is performed implicitly,
// T ***MUST*** be derived from VRefCount, and VRefCount must be the
// first base class, e.g.:
// class MyClass : public VRefCount, public OtherClass {};
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// "Incomplete" const refcounted pointer
// This implements the non-inherited methods and the conversions
// between complete and incomplete refcounted pointers.
////////////////////////////////////////////////////////////////////////////
template <class T>
class refcnt_cptrI : public refcnt_cptr<VRefCount>
{
private:
typedef refcnt_cptr<VRefCount> myBase;
public:
// basic ctor
refcnt_cptrI(const T* ptr_ = 0) :
myBase( REINTERPRET_CAST(const VRefCount*, ptr_) )
{}
// copy ctor
refcnt_cptrI(const refcnt_cptrI& rhs) :
myBase( REINTERPRET_CAST(const VRefCount*, rhs.get()) )
{}
// assignment operators
refcnt_cptrI& operator=(const refcnt_cptrI& rhs)
{
refcnt_cptr<VRefCount>::operator=(rhs);
return *this;
}
refcnt_cptrI& operator=(const T* rhs)
{
refcnt_cptr<VRefCount>::operator=(REINTERPRET_CAST(const VRefCount*, rhs));
return *this;
}
// Conversion to/from complete types
const T* get() const { return REINTERPRET_CAST(const T*, myBase::get()); }
operator const T* () const { return get(); }
const T* operator->() const;
const T& operator*() const { return *(operator const T*()); }
// The body of this is specified separately; otherwise MSVC++
// (and probably other compilers) instantiates it even if not called.
// ctor from complete refcounted ptr
refcnt_cptrI(const refcnt_cptr<T>&);
};
//
// This are outside of the class because MSVC++ instantiates everything
// declared in the class even if it isn't used
//
template <class T>
inline refcnt_cptrI<T>::refcnt_cptrI(
const refcnt_cptr<T>& rhs
) :
myBase((const VRefCount *)rhs.get())
{
}
template <class T>
inline const T*
refcnt_cptrI<T>::operator->() const
{
// Since operator-> is presumably only used when you have the complete
// type, then use STATIC_CAST here to enforce some type checking.
// Furthermore, we can add an assertion to make sure that the static
// cast matches the reinterpret cast used elsewhere.
assert(STATIC_CAST(const T*, myBase::get()) == REINTERPRET_CAST(const T*, myBase::get()));
return get();
}
////////////////////////////////////////////////////////////////////////////
// "Incomplete" non-const refcounted pointer
// This implements the non-inherited methods and the conversions
// between complete and incomplete refcounted pointers.
////////////////////////////////////////////////////////////////////////////
template <class T>
class refcnt_ptrI : public refcnt_ptr<VRefCount>
{
private:
typedef refcnt_ptr<VRefCount> myBase;
public:
// basic ctor
refcnt_ptrI(T* ptr_ = 0) :
myBase( REINTERPRET_CAST(VRefCount*, ptr_) )
{}
// copy ctor
refcnt_ptrI(const refcnt_ptrI& rhs) :
myBase( REINTERPRET_CAST(VRefCount*, rhs.get()) )
{}
// assignment operators
refcnt_ptrI& operator=(const refcnt_ptrI& rhs)
{
refcnt_ptr<VRefCount>::operator=(rhs);
return *this;
}
refcnt_ptrI& operator=(T* rhs)
{
refcnt_ptr<VRefCount>::operator=(REINTERPRET_CAST(VRefCount*, rhs));
return *this;
}
// Conversion to/from complete types
T* get() const { return REINTERPRET_CAST(T*, myBase::get()); }
operator T* () const { return get(); }
T* operator->() const;
T& operator*() const { return *(operator T*()); }
// The body of this is specified separately; otherwise MSVC++
// (and probably other compilers) instantiates it even if not called.
// ctor from complete refcounted ptr
refcnt_ptrI(const refcnt_ptr<T>&);
};
//
// This are outside of the class because MSVC++ instantiates everything
// declared in the class even if it isn't used
//
template <class T>
inline refcnt_ptrI<T>::refcnt_ptrI(
const refcnt_ptr<T>& rhs
) :
refcnt_ptr<VRefCount>((VRefCount *)rhs.get())
{
}
template <class T>
inline T*
refcnt_ptrI<T>::operator->() const
{
// Since operator-> is presumably only used when you have the complete
// type, then use STATIC_CAST here to enforce some type checking.
// Furthermore, we can add an assertion to make sure that the static
// cast matches the reinterpret cast used elsewhere.
assert(STATIC_CAST(T*, myBase::get()) == REINTERPRET_CAST(T*, myBase::get()));
return get();
}
#endif