0328340eb242242b29fa614d0b7b815eddcc8f3b
[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         unsigned refcount() const { return (data ? *count : 0); }
92
93         template<typename U>
94         static RefPtr<T> cast_dynamic(const RefPtr<U> &p)
95         { return RefPtr<T>(dynamic_cast<T *>(p.data), p.count); }
96
97 private:
98         void incref()
99         {
100                 if(!count) return;
101                 ++*count;
102         }
103
104         void decref()
105         {
106                 if(!count) return;
107                 --*count;
108                 if(!*count)
109                 {
110                         delete data;
111                         delete count;
112                         data = 0;
113                         count = 0;
114                 }
115                 else if(*count==KEEP)
116                 {
117                         delete count;
118                         data = 0;
119                         count = 0;
120                 }
121         }
122 };
123
124 } // namespace Msp
125
126 #endif