/[svn]/linuxsampler/trunk/src/common/Ref.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/common/Ref.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2619 - (show annotations) (download) (as text)
Wed Jun 11 13:24:32 2014 UTC (9 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13429 byte(s)
* Implemented built-in instrument script function "abs()".
* Implemented built-in instrument script function "random()".
* Implemented built-in instrument script function "num_elements()".
* Disabled debug mode of RefPtr template class.
* Bumped version (1.0.0.svn51).

1 /*
2 * Copyright (c) 2014 Christian Schoenebeck
3 *
4 * http://www.linuxsampler.org
5 *
6 * This file is part of LinuxSampler and released under the same terms.
7 * See README file for details.
8 */
9
10 #ifndef LS_REF_H
11 #define LS_REF_H
12
13 #include <set>
14 #include <stdio.h>
15
16 // You may enable this while developing or at least when you encounter any kind
17 // of crashes or other misbehaviors in conjunction with Ref class guarded code.
18 // Enabling the following macro will add a bunch of sanity checks for easing
19 // debugging of such issues, however it comes with the cost that everything will
20 // be much slower.
21 #define LS_REF_ASSERT_MODE 0
22
23 #if LS_REF_ASSERT_MODE
24 # warning LS_REF_ASSERT_MODE is enabled which will decrease runtime efficiency!
25 #endif
26
27 // Enable this for VERY verbose debug messages for debbugging deep issues with
28 // Ref class.
29 #define LS_REF_VERBOSE_DEBUG_MSG 0
30
31 #if LS_REF_ASSERT_MODE
32 # include <assert.h>
33 #endif
34
35 namespace LinuxSampler {
36
37 //TODO: make reference count increment/decrement thread safe
38
39 template<typename T, typename T_BASE> class Ref;
40
41 extern std::set<void*> _allRefPtrs;
42
43 /**
44 * Exists just for implementation detail purpose, you cannot use it
45 * directly. Use its derived template class Ref instead.
46 *
47 * @see Ref
48 */
49 template<typename T_BASE>
50 class RefBase {
51 public:
52 template<typename T_BASE1>
53 class _RefCounter {
54 public:
55 _RefCounter(T_BASE1* p, int refs) :
56 references(refs), ptr(p)
57 {
58 #if LS_REF_VERBOSE_DEBUG_MSG
59 printf("Ref 0x%lx: new counter (refs=%d)\n", (long long)ptr, references);
60 #endif
61 #if LS_REF_ASSERT_MODE
62 assert(p);
63 assert(refs > 0);
64 assert(!_allRefPtrs.count(p));
65 _allRefPtrs.insert(p);
66 #endif
67 }
68
69 virtual ~_RefCounter() {
70 #if LS_REF_VERBOSE_DEBUG_MSG
71 printf("Ref 0x%lx: counter destructor (refs=%d)\n", (long long)ptr, references);
72 #endif
73 fflush(stdout);
74 }
75
76 void retain() {
77 references++;
78 #if LS_REF_VERBOSE_DEBUG_MSG
79 printf("Ref 0x%lx: retain (refs=%d)\n", (long long)ptr, references);
80 #endif
81 }
82
83 void release() {
84 if (!references) return;
85 references--;
86 #if LS_REF_VERBOSE_DEBUG_MSG
87 printf("Ref 0x%lx: release (refs=%d)\n", (long long)ptr, references);
88 #endif
89 if (!references) deletePtr();
90 }
91 //protected:
92 void deletePtr() {
93 #if LS_REF_VERBOSE_DEBUG_MSG
94 printf("RefCounter 0x%lx: deletePtr() (refs=%d)\n", (long long)ptr, references);
95 #endif
96 #if LS_REF_ASSERT_MODE
97 assert(!references);
98 _allRefPtrs.erase(ptr);
99 #endif
100 delete ptr;
101 delete this;
102 }
103
104 int references;
105 T_BASE1* ptr;
106 //friend class ... todo
107 };
108 typedef _RefCounter<T_BASE> RefCounter;
109
110 virtual ~RefBase() {
111 if (refCounter) refCounter->release();
112 refCounter = NULL;
113 }
114
115 //protected:
116 RefCounter* refCounter;
117 //friend class Ref<T_BASE, T_BASE>;
118
119 protected:
120 RefBase() : refCounter(NULL) {
121 #if LS_REF_VERBOSE_DEBUG_MSG
122 printf("(RefBase empty ctor)\n");
123 #endif
124 }
125 /*
126 RefBase(RefCounter* rc) {
127 refCounter = rc;
128 }
129
130 RefBase(const RefBase& r) {
131 refCounter = r.refCounter;
132 if (refCounter) refCounter->retain();
133 }
134 */
135 };
136
137 /**
138 * Replicates a std::shared_ptr template class, to avoid a build requirement
139 * of having a C++11 compliant compiler (std::shared_ptr was not part of the
140 * C++03 standard).
141 *
142 * In contrast to the STL implementation though this implementation here
143 * also supports copying references of derived, different types (in a type
144 * safe manner). You can achieve that by providing a second template
145 * argument (which is optional), for declaring a common subtype. For example
146 * the following code would not compile:
147 * @code
148 * void example(UILabel* pLabel) {
149 * Ref<UILabel> lbl = pLabel;
150 * Ref<UIWidget> w = lbl; // compile error, incompatible Ref types
151 * w->resize(16,300);
152 * }
153 * @endcode
154 * Whereas the following would work:
155 * @code
156 * void example(UILabel* pLabel) {
157 * Ref<UILabel,UIWidget> lbl = pLabel;
158 * Ref<UIWidget> w = lbl; // works (assuming that UILabel is a subclass of UIWidget)
159 * w->resize(16,300);
160 * }
161 * @endcode
162 * Like the STL's std::shared_ptr, this class also emulates raw pointer
163 * access and operators. With one addition: if used in the derived common
164 * subtype manner as shown above, access to the actual data and boolean
165 * operator will also check whether the underlying pointer (of the common
166 * subclass) can actually be casted safely to the objects main type (first
167 * template argument of this class). For example:
168 * @code
169 * void example(UILabel* pLabel) { // assuming pLabel is not NULL ...
170 * Ref<UILabel,UIWidget> lbl = pLabel;
171 * Ref<UIDialog,UIWidget> dlg = lbl;
172 * bool b1 = lbl; // will be true (assuming pLabel was not NULL)
173 * bool b2 = dlg; // will be false (assuming that UIDialog is not derived from UILabel)
174 * lbl->setText("foo"); // works
175 * dlg->showModal(); // would crash with -> operator providing a NULL pointer
176 * }
177 * @endcode
178 * Like with std::shared_ptr you must be @b very cautious that you
179 * initialize only one Ref class object directly with the same raw pointer.
180 * If you forget this fundamental rule somewhere, your code will crash!
181 * @code
182 * UIWidget* ptr = new UIWidget();
183 * Ref<UIWidget> w1 = ptr;
184 * Ref<UIWidget> w2 = w1; // this is OK, copy from a Ref object
185 * Ref<UIWidget> w3 = ptr; // illegal! 2nd direct init from same raw pointer. This will crash!
186 * @endcode
187 * It would be possible to write an implementation of the Ref class that
188 * could handle the case above as well without crashing, however it would be
189 * too slow for practice. Because it would require a global lookup table
190 * maintaining all memory pointers which are currently already guarded by
191 * this class. Plus it would need an expensive synchronization to prevent
192 * concurrent access on that global lookup table.
193 */
194 template<typename T, typename T_BASE = T>
195 class Ref : public RefBase<T_BASE> {
196 public:
197 typedef RefBase<T_BASE> RefBaseT;
198 typedef typename RefBase<T_BASE>::RefCounter RefCounter;
199
200 Ref() : RefBaseT() {
201 #if LS_REF_VERBOSE_DEBUG_MSG
202 printf("Ref empty ctor Ref:0x%lx\n", (long long)this);
203 #endif
204 }
205
206 Ref(const T_BASE* p) : RefBaseT() {
207 #if LS_REF_VERBOSE_DEBUG_MSG
208 printf("Ref base ptr ctor Ref:0x%lx <- p:0x%lx\n", (long long)this, (long long)p);
209 #endif
210 RefBaseT::refCounter = p ? new RefCounter((T_BASE*)p, 1) : NULL;
211 }
212
213 Ref(const T* p) : RefBaseT() {
214 #if LS_REF_VERBOSE_DEBUG_MSG
215 printf("Ref main ptr ctor Ref:0x%lx <- p:0x%lx\n", (long long)this, (long long)p);
216 #endif
217 RefBaseT::refCounter = p ? new RefCounter((T*)p, 1) : NULL;
218 }
219
220 Ref(const RefBaseT& r) : RefBaseT() {
221 #if LS_REF_VERBOSE_DEBUG_MSG
222 printf("Ref base ref ctor Ref:0x%lx <- Ref:0x%lx\n", (long long)this, (long long)&r);
223 #endif
224 RefBaseT::refCounter = r.refCounter;
225 if (RefBaseT::refCounter)
226 RefBaseT::refCounter->retain();
227 }
228
229 Ref(const Ref& r) : RefBaseT() {
230 #if LS_REF_VERBOSE_DEBUG_MSG
231 printf("Ref main ref ctor Ref:0x%lx <- Ref:0x%lx\n", (long long)this, (long long)&r);
232 #endif
233 RefBaseT::refCounter = r.refCounter;
234 if (RefBaseT::refCounter)
235 RefBaseT::refCounter->retain();
236 }
237
238 inline T* operator->() {
239 return dynamic_cast<T*>( RefBaseT::refCounter->ptr );
240 }
241
242 inline const T* operator->() const {
243 return dynamic_cast<const T*>( RefBaseT::refCounter->ptr );
244 }
245
246 inline T& operator*() {
247 return *dynamic_cast<T*>( RefBaseT::refCounter->ptr );
248 }
249
250 inline const T& operator*() const {
251 return *dynamic_cast<const T*>( RefBaseT::refCounter->ptr );
252 }
253
254 inline bool operator==(const RefBaseT& other) const {
255 return RefBaseT::refCounter == other.refCounter;
256 }
257
258 inline bool operator!=(const RefBaseT& other) const {
259 return RefBaseT::refCounter != other.refCounter;
260 }
261
262 inline operator bool() const {
263 return RefBaseT::refCounter && RefBaseT::refCounter->ptr &&
264 dynamic_cast<const T*>( RefBaseT::refCounter->ptr );
265 }
266
267 inline bool operator!() const {
268 return !( RefBaseT::refCounter && RefBaseT::refCounter->ptr &&
269 dynamic_cast<const T*>( RefBaseT::refCounter->ptr ) );
270 }
271
272 /*
273 inline operator RefBaseT&() {
274 return *this;
275 }
276
277 inline operator const RefBaseT&() const {
278 return *this;
279 }
280 */
281 inline bool isEquivalent(const RefBaseT& other) const {
282 if (static_cast<const RefBaseT*>(this) == &other)
283 return true;
284 return (RefBaseT::refCounter == other.refCounter);
285 }
286
287 inline bool isEquivalent(const T_BASE* const other) const {
288 if (!other) return !RefBaseT::refCounter;
289 if (!RefBaseT::refCounter) return false;
290 return other == RefBaseT::refCounter->ptr;
291 }
292
293 Ref<T,T_BASE>& operator=(const RefBaseT& other) {
294 #if LS_REF_VERBOSE_DEBUG_MSG
295 printf("Ref base ref assignment Ref:0x%lx <- Ref:0x%lx\n", (long long)this, (long long)&other);
296 #endif
297 if (isEquivalent(other)) {
298 #if LS_REF_VERBOSE_DEBUG_MSG
299 printf("Ref 0x%lx WRN: equivalent ref assignment ignored.\n", (long long)this);
300 #endif
301 return *this;
302 }
303 if (RefBaseT::refCounter) {
304 RefBaseT::refCounter->release();
305 RefBaseT::refCounter = NULL;
306 }
307 RefBaseT::refCounter = other.refCounter;
308 if (RefBaseT::refCounter)
309 RefBaseT::refCounter->retain();
310 return *this;
311 }
312
313 Ref<T,T_BASE>& operator=(const Ref<T,T_BASE>& other) {
314 #if LS_REF_VERBOSE_DEBUG_MSG
315 printf("Ref main ref assignment Ref:0x%lx <- Ref:0x%lx\n", (long long)this, (long long)&other);
316 #endif
317 if (isEquivalent(other)) {
318 #if LS_REF_VERBOSE_DEBUG_MSG
319 printf("Ref 0x%lx WRN: equivalent ref assignment ignored.\n", (long long)this);
320 #endif
321 return *this;
322 }
323 if (RefBaseT::refCounter) {
324 RefBaseT::refCounter->release();
325 RefBaseT::refCounter = NULL;
326 }
327 RefBaseT::refCounter = other.refCounter;
328 if (RefBaseT::refCounter)
329 RefBaseT::refCounter->retain();
330 return *this;
331 }
332
333 Ref<T,T_BASE>& operator=(const T* p) {
334 #if LS_REF_VERBOSE_DEBUG_MSG
335 printf("Ref main ptr assignment Ref:0x%lx <- p:0x%lx\n", (long long)this, p);
336 #endif
337 if (isEquivalent(p)) {
338 #if LS_REF_VERBOSE_DEBUG_MSG
339 printf("Ref 0x%lx WRN: equivalent ptr assignment ignored.\n", (long long)this);
340 #endif
341 return *this;
342 }
343 if (RefBaseT::refCounter) {
344 RefBaseT::refCounter->release();
345 RefBaseT::refCounter = NULL;
346 }
347 RefBaseT::refCounter = p ? new RefCounter((T*)p, 1) : NULL;
348 #if LS_REF_VERBOSE_DEBUG_MSG
349 printf("Ref main ptr assignment done\n");
350 #endif
351 return *this;
352 }
353
354 Ref<T,T_BASE>& operator=(const T_BASE* p) {
355 #if LS_REF_VERBOSE_DEBUG_MSG
356 printf("Ref base ptr assignment Ref:0x%lx <- p:0x%lx\n", (long long)this, p);
357 #endif
358 if (isEquivalent(p)) {
359 #if LS_REF_VERBOSE_DEBUG_MSG
360 printf("Ref 0x%lx WRN: equivalent ptr assignment ignored.\n", (long long)this);
361 #endif
362 return *this;
363 }
364 if (RefBaseT::refCounter) {
365 RefBaseT::refCounter->release();
366 RefBaseT::refCounter = NULL;
367 }
368 RefBaseT::refCounter = p ? new RefCounter((T*)p, 1) : NULL;
369 return *this;
370 }
371 };
372
373 } // namespace LinuxSampler
374
375 #endif // LS_REF_H

  ViewVC Help
Powered by ViewVC