8ab1b7cbfbdb6e752afd4b7634e807a8a836e10a
[libs/core.git] / source / core / refptr.h
1 #ifndef MSP_CORE_REFPTR_H_
2 #define MSP_CORE_REFPTR_H_
3
4 namespace Msp {
5
6 struct RefCounts
7 {
8         enum
9         {
10                 KEEP = 1U<<(sizeof(unsigned)*8-1)
11         };
12
13         unsigned count;
14
15         RefCounts(): count(0) { }
16 };
17
18
19 /**
20 A reference counting smart pointer.  When the last RefPtr for the data gets
21 destroyed, the data is deleted as well.
22 */
23 template<typename T>
24 class RefPtr
25 {
26         template<typename U> friend class RefPtr;
27
28 private:
29         T *data;
30         RefCounts *counts;
31
32 public:
33         RefPtr(): data(0), counts(0) { }
34         RefPtr(T *d): data(d), counts(data ? new RefCounts : 0) { incref(); }
35 private:
36         RefPtr(T *d, RefCounts *c): data(d), counts(d ? c : 0) { incref(); }
37
38 public:
39         /* Must have this or the compiler will generate a default copy-c'tor despite
40         the template version */
41         RefPtr(const RefPtr &p): data(p.data), counts(p.counts) { incref(); }
42
43         template<typename U>
44         RefPtr(const RefPtr<U> &p): data(p.data), counts(p.counts) { incref(); }
45
46         ~RefPtr() { decref(); }
47
48         RefPtr &operator=(T *d)
49         {
50                 decref();
51                 data = d;
52                 counts = (d ? new RefCounts : 0);
53                 incref();
54                 return *this;
55         }
56
57         // Likewise for the assignment operator
58         RefPtr &operator=(const RefPtr &p) { return assign(p); }
59
60         template<typename U>
61         RefPtr &operator=(const RefPtr<U> &p) { return assign(p); }
62
63 private:
64         template<typename U>
65         RefPtr &assign(const RefPtr<U> &p)
66         {
67                 decref();
68                 data = p.data;
69                 counts = p.counts;
70                 incref();
71                 return *this;
72         }
73
74 public:
75         /** Makes the RefPtr release its reference of the data without deleting it.
76         Note that if there are other RefPtrs left with the same data, it might
77         still get deleted automatically. */
78         T *release()
79         {
80                 T *d = data;
81                 data = 0;
82                 decref();
83                 counts = 0;
84                 return d;
85         }
86
87         /** Marks the data to not be deleted.  This affects all RefPtrs with the
88         same data. */
89         void keep()
90         {
91                 if(counts)
92                         counts->count |= RefCounts::KEEP;
93         }
94
95         T *get() const { return data; }
96         T &operator*() const { return *data; }
97         T *operator->() const { return data; }
98         operator bool() const { return data!=0; }
99
100         unsigned refcount() const { return (data ? counts->count : 0); }
101
102         template<typename U>
103         static RefPtr<T> cast_dynamic(const RefPtr<U> &p)
104         { return RefPtr<T>(dynamic_cast<T *>(p.data), p.counts); }
105
106 private:
107         void incref()
108         {
109                 if(!counts) return;
110                 ++counts->count;
111         }
112
113         void decref()
114         {
115                 if(!counts) return;
116                 --counts->count;
117                 if(!counts->count)
118                 {
119                         delete data;
120                         delete counts;
121                         data = 0;
122                         counts = 0;
123                 }
124                 else if(counts->count==RefCounts::KEEP)
125                 {
126                         delete counts;
127                         data = 0;
128                         counts = 0;
129                 }
130         }
131 };
132
133 } // namespace Msp
134
135 #endif