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