]> git.tdb.fi Git - libs/core.git/blob - source/core/refptr.h
Implement weak pointers
[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         unsigned weak_count;
15
16         RefCounts(): count(0), weak_count(0) { }
17 };
18
19 template<typename T>
20 class WeakPtr;
21
22
23 /**
24 A reference counting smart pointer.  When the last RefPtr for the data gets
25 destroyed, the data is deleted as well.
26 */
27 template<typename T>
28 class RefPtr
29 {
30         template<typename U> friend class RefPtr;
31         template<typename U> friend class WeakPtr;
32
33 private:
34         T *data;
35         RefCounts *counts;
36
37 public:
38         RefPtr(): data(0), counts(0) { }
39         RefPtr(T *d): data(d), counts(data ? new RefCounts : 0) { incref(); }
40 private:
41         RefPtr(T *d, RefCounts *c): data(d), counts(d ? c : 0) { incref(); }
42
43 public:
44         /* Must have this or the compiler will generate a default copy-c'tor despite
45         the template version */
46         RefPtr(const RefPtr &p): data(p.data), counts(p.counts) { incref(); }
47
48         template<typename U>
49         RefPtr(const RefPtr<U> &p): data(p.data), counts(p.counts) { incref(); }
50
51         template<typename U>
52         RefPtr(const WeakPtr<U> &p): data(p.get()), counts(data ? p.counts : 0) { incref(); }
53
54         ~RefPtr() { decref(); }
55
56         RefPtr &operator=(T *);
57
58         // Likewise for the assignment operator
59         RefPtr &operator=(const RefPtr &p) { return assign(p); }
60
61         template<typename U>
62         RefPtr &operator=(const RefPtr<U> &p) { return assign(p); }
63
64         template<typename U>
65         RefPtr &operator=(const WeakPtr<U> &p) { return assign(RefPtr(p)); }
66
67 private:
68         template<typename U>
69         RefPtr &assign(const RefPtr<U> &);
70
71 public:
72         /** Makes the RefPtr release its reference of the data without deleting it.
73         Note that if there are other RefPtrs left with the same data, it might
74         still get deleted automatically. */
75         T *release();
76
77         /** Marks the data to not be deleted.  This affects all RefPtrs with the
78         same data. */
79         void keep() { if(counts) counts->count |= RefCounts::KEEP; }
80
81         T *get() const { return data; }
82         T &operator*() const { return *data; }
83         T *operator->() const { return data; }
84         operator bool() const { return data!=0; }
85
86         unsigned refcount() const { return (data ? counts->count : 0); }
87
88         template<typename U>
89         static RefPtr<T> cast_dynamic(const RefPtr<U> &p)
90         { return RefPtr<T>(dynamic_cast<T *>(p.data), p.counts); }
91
92 private:
93         void incref() { if(counts) ++counts->count; }
94         void decref();
95 };
96
97
98 template<typename T>
99 class WeakPtr
100 {
101         template<typename U> friend class RefPtr;
102         template<typename U> friend class WeakPtr;
103
104 private:
105         T *data;
106         RefCounts *counts;
107
108 public:
109         WeakPtr(): data(0), counts(0) { }
110 private:
111         WeakPtr(T *d, RefCounts *c): data(d), counts(d ? c : 0) { incref(); }
112
113 public:
114         WeakPtr(const WeakPtr &p): data(p.get()), counts(data ? p.counts : 0) { incref(); }
115
116         template<typename U>
117         WeakPtr(const WeakPtr<U> &p): data(p.get()), counts(data ? p.counts : 0) { incref(); }
118
119         template<typename U>
120         WeakPtr(const RefPtr<U> &p): data(p.data), counts(p.counts) { incref(); }
121
122         WeakPtr &operator=(const WeakPtr &p) { return assign(p); }
123
124         template<typename U>
125         WeakPtr &operator=(const WeakPtr<U> &p) { return assign(p); }
126
127         template<typename U>
128         WeakPtr &operator=(const RefPtr<U> &p) { return assign(WeakPtr(p)); }
129
130 private:
131         template<typename U>
132         WeakPtr &assign(const WeakPtr<U> &);
133
134         T *get() const { return (counts && counts->count ? data : 0); }
135         void incref() { if(counts) ++counts->weak_count; }
136         void decref();
137 };
138
139
140 template<typename T>
141 RefPtr<T> &RefPtr<T>::operator=(T *d)
142 {
143         decref();
144         data = d;
145         counts = (d ? new RefCounts : 0);
146         incref();
147         return *this;
148 }
149
150 template<typename T>
151 template<typename U>
152 RefPtr<T> &RefPtr<T>::assign(const RefPtr<U> &p)
153 {
154         decref();
155         data = p.data;
156         counts = p.counts;
157         incref();
158         return *this;
159 }
160
161 template<typename T>
162 T *RefPtr<T>::release()
163 {
164         T *d = data;
165         data = 0;
166         decref();
167         counts = 0;
168         return d;
169 }
170
171 template<typename T>
172 void RefPtr<T>::decref()
173 {
174         if(!counts) return;
175         --counts->count;
176         if(!counts->count)
177         {
178                 delete data;
179                 data = 0;
180         }
181         else if(counts->count==RefCounts::KEEP)
182                 data = 0;
183         else
184                 return;
185
186         if(!counts->weak_count)
187         {
188                 delete counts;
189                 counts = 0;
190         }
191 }
192
193
194 template<typename T>
195 template<typename U>
196 WeakPtr<T> &WeakPtr<T>::assign(const WeakPtr<U> &p)
197 {
198         decref();
199         data = p.get();
200         counts = (data ? p.counts : 0);
201         incref();
202         return *this;
203 }
204
205 template<typename T>
206 void WeakPtr<T>::decref()
207 {
208         if(!counts) return;
209         --counts->weak_count;
210         if(!counts->weak_count && (!counts->count || counts->count==RefCounts::KEEP))
211         {
212                 delete counts;
213                 data = 0;
214                 counts = 0;
215         }
216 }
217
218 } // namespace Msp
219
220 #endif