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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2581 - (hide annotations) (download) (as text)
Fri May 30 12:48:05 2014 UTC (9 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13429 byte(s)
* (WIP) Implemented parser and VM for upcoming new real-time instrument
  script support. It needs yet to be integrated into the sampler's
  sampler engines. You can toy around for now with the command line tool
  "ls_instr_script" and i.e. examples showing the core language features
  under src/scriptvm/examples/.
* Bumped version (1.0.0.svn41).

1 schoenebeck 2581 /*
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 1
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