-/* $Id$
-
-This file is part of libmspcore
-Copyright © 2006-2007, 2010 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
#ifndef MSP_CORE_REFPTR_H_
#define MSP_CORE_REFPTR_H_
namespace Msp {
+struct RefCounts
+{
+ enum
+ {
+ KEEP = 1U<<(sizeof(unsigned)*8-1)
+ };
+
+ unsigned count;
+
+ RefCounts(): count(0) { }
+};
+
+
/**
A reference counting smart pointer. When the last RefPtr for the data gets
destroyed, the data is deleted as well.
template<typename T>
class RefPtr
{
+ template<typename U> friend class RefPtr;
+
private:
- enum
- {
- KEEP = 1U<<(sizeof(unsigned)*8-1)
- };
+ T *data;
+ RefCounts *counts;
public:
- RefPtr(): data(0), count(0) { }
- RefPtr(T *d): data(d), count(data ? new unsigned(1) : 0) { }
+ RefPtr(): data(0), counts(0) { }
+ RefPtr(T *d): data(d), counts(data ? new RefCounts : 0) { incref(); }
+private:
+ RefPtr(T *d, RefCounts *c): data(d), counts(d ? c : 0) { incref(); }
- // Must have this or the compiler will generate a default copy-c'tor
- RefPtr(const RefPtr &p): data(p.data), count(p.count) { incref(); }
+public:
+ /* Must have this or the compiler will generate a default copy-c'tor despite
+ the template version */
+ RefPtr(const RefPtr &p): data(p.data), counts(p.counts) { incref(); }
template<typename U>
- RefPtr(const RefPtr<U> &p): data(p.data), count(p.count) { incref(); }
+ RefPtr(const RefPtr<U> &p): data(p.data), counts(p.counts) { incref(); }
+
+ ~RefPtr() { decref(); }
RefPtr &operator=(T *d)
{
decref();
data = d;
- count = (d ? new unsigned(1) : 0);
+ counts = (d ? new RefCounts : 0);
+ incref();
return *this;
}
template<typename U>
RefPtr &operator=(const RefPtr<U> &p) { return assign(p); }
-
- ~RefPtr() { decref(); }
- /**
- Makes the RefPtr release its reference of the data. Note that if there are
- other RefPtrs left with the same data, it might still get deleted
- automatically.
- */
+private:
+ template<typename U>
+ RefPtr &assign(const RefPtr<U> &p)
+ {
+ decref();
+ data = p.data;
+ counts = p.counts;
+ incref();
+ return *this;
+ }
+
+public:
+ /** Makes the RefPtr release its reference of the data without deleting it.
+ Note that if there are other RefPtrs left with the same data, it might
+ still get deleted automatically. */
T *release()
{
T *d = data;
data = 0;
decref();
- count = 0;
+ counts = 0;
return d;
}
- /**
- Marks the data to not be deleted. This affects all RefPtrs with the same
- data.
- */
+ /** Marks the data to not be deleted. This affects all RefPtrs with the
+ same data. */
void keep()
{
- if(count)
- *count |= KEEP;
+ if(counts)
+ counts->count |= RefCounts::KEEP;
}
T *get() const { return data; }
T *operator->() const { return data; }
operator bool() const { return data!=0; }
+ unsigned refcount() const { return (data ? counts->count : 0); }
+
template<typename U>
static RefPtr<T> cast_dynamic(const RefPtr<U> &p)
- { return RefPtr<T>(dynamic_cast<T *>(p.data), p.count); }
+ { return RefPtr<T>(dynamic_cast<T *>(p.data), p.counts); }
- template<typename U> friend class RefPtr;
private:
- T *data;
- unsigned *count;
-
- RefPtr(T *d, unsigned *c): data(d), count(d ? c : 0) { incref(); }
-
- template<typename U>
- RefPtr &assign(const RefPtr<U> &p)
- {
- decref();
- data = p.data;
- count = p.count;
- incref();
- return *this;
- }
-
void incref()
{
- if(!count) return;
- ++*count;
+ if(!counts) return;
+ ++counts->count;
}
void decref()
{
- if(!count) return;
- --*count;
- if(!*count)
+ if(!counts) return;
+ --counts->count;
+ if(!counts->count)
{
delete data;
- delete count;
+ delete counts;
data = 0;
- count = 0;
+ counts = 0;
}
- else if(*count==KEEP)
+ else if(counts->count==RefCounts::KEEP)
{
- delete count;
+ delete counts;
data = 0;
- count = 0;
+ counts = 0;
}
}
};