]> git.tdb.fi Git - libs/core.git/blob - source/core/refptr.h
28666ea816380e0547205a1f6d83b14da0e13016
[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 *);
49
50         // Likewise for the assignment operator
51         RefPtr &operator=(const RefPtr &p) { return assign(p); }
52
53         template<typename U>
54         RefPtr &operator=(const RefPtr<U> &p) { return assign(p); }
55
56 private:
57         template<typename U>
58         RefPtr &assign(const RefPtr<U> &);
59
60 public:
61         /** Makes the RefPtr release its reference of the data without deleting it.
62         Note that if there are other RefPtrs left with the same data, it might
63         still get deleted automatically. */
64         T *release();
65
66         /** Marks the data to not be deleted.  This affects all RefPtrs with the
67         same data. */
68         void keep() { if(counts) counts->count |= RefCounts::KEEP; }
69
70         T *get() const { return data; }
71         T &operator*() const { return *data; }
72         T *operator->() const { return data; }
73         operator bool() const { return data!=0; }
74
75         unsigned refcount() const { return (data ? counts->count : 0); }
76
77         template<typename U>
78         static RefPtr<T> cast_dynamic(const RefPtr<U> &p)
79         { return RefPtr<T>(dynamic_cast<T *>(p.data), p.counts); }
80
81 private:
82         void incref() { if(counts) ++counts->count; }
83         void decref();
84 };
85
86
87 template<typename T>
88 RefPtr<T> &RefPtr<T>::operator=(T *d)
89 {
90         decref();
91         data = d;
92         counts = (d ? new RefCounts : 0);
93         incref();
94         return *this;
95 }
96
97 template<typename T>
98 template<typename U>
99 RefPtr<T> &RefPtr<T>::assign(const RefPtr<U> &p)
100 {
101         decref();
102         data = p.data;
103         counts = p.counts;
104         incref();
105         return *this;
106 }
107
108 template<typename T>
109 T *RefPtr<T>::release()
110 {
111         T *d = data;
112         data = 0;
113         decref();
114         counts = 0;
115         return d;
116 }
117
118 template<typename T>
119 void RefPtr<T>::decref()
120 {
121         if(!counts) return;
122         --counts->count;
123         if(!counts->count)
124         {
125                 delete data;
126                 delete counts;
127                 data = 0;
128                 counts = 0;
129         }
130         else if(counts->count==RefCounts::KEEP)
131         {
132                 delete counts;
133                 data = 0;
134                 counts = 0;
135         }
136 }
137
138 } // namespace Msp
139
140 #endif