1 /*
2   ==============================================================================
3 
4    This file is part of the Water library.
5    Copyright (c) 2016 ROLI Ltd.
6    Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
7 
8    Permission is granted to use this software under the terms of the ISC license
9    http://www.isc.org/downloads/software-support-policy/isc-license/
10 
11    Permission to use, copy, modify, and/or distribute this software for any
12    purpose with or without fee is hereby granted, provided that the above
13    copyright notice and this permission notice appear in all copies.
14 
15    THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
16    TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17    FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
18    OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19    USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20    TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21    OF THIS SOFTWARE.
22 
23   ==============================================================================
24 */
25 
26 #ifndef WATER_REFERENCECOUNTEDOBJECT_H_INCLUDED
27 #define WATER_REFERENCECOUNTEDOBJECT_H_INCLUDED
28 
29 #include "Atomic.h"
30 
31 namespace water {
32 
33 //==============================================================================
34 /**
35     A base class which provides methods for reference-counting.
36 
37     To add reference-counting to a class, derive it from this class, and
38     use the ReferenceCountedObjectPtr class to point to it.
39 
40     e.g. @code
41     class MyClass : public ReferenceCountedObject
42     {
43         void foo();
44 
45         // This is a neat way of declaring a typedef for a pointer class,
46         // rather than typing out the full templated name each time..
47         typedef ReferenceCountedObjectPtr<MyClass> Ptr;
48     };
49 
50     MyClass::Ptr p = new MyClass();
51     MyClass::Ptr p2 = p;
52     p = nullptr;
53     p2->foo();
54     @endcode
55 
56     Once a new ReferenceCountedObject has been assigned to a pointer, be
57     careful not to delete the object manually.
58 
59     This class uses an Atomic<int> value to hold the reference count, so that it
60     the pointers can be passed between threads safely. For a faster but non-thread-safe
61     version, use SingleThreadedReferenceCountedObject instead.
62 
63     @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
64 */
65 class ReferenceCountedObject
66 {
67 public:
68     //==============================================================================
69     /** Increments the object's reference count.
70 
71         This is done automatically by the smart pointer, but is public just
72         in case it's needed for nefarious purposes.
73     */
incReferenceCount()74     void incReferenceCount() noexcept
75     {
76         ++refCount;
77     }
78 
79     /** Decreases the object's reference count.
80         If the count gets to zero, the object will be deleted.
81     */
decReferenceCount()82     void decReferenceCount() noexcept
83     {
84         wassert (getReferenceCount() > 0);
85 
86         if (--refCount == 0)
87             delete this;
88     }
89 
90     /** Decreases the object's reference count.
91         If the count gets to zero, the object will not be deleted, but this method
92         will return true, allowing the caller to take care of deletion.
93     */
decReferenceCountWithoutDeleting()94     bool decReferenceCountWithoutDeleting() noexcept
95     {
96         wassert (getReferenceCount() > 0);
97         return --refCount == 0;
98     }
99 
100     /** Returns the object's current reference count. */
getReferenceCount()101     int getReferenceCount() const noexcept       { return refCount.get(); }
102 
103 
104 protected:
105     //==============================================================================
106     /** Creates the reference-counted object (with an initial ref count of zero). */
ReferenceCountedObject()107     ReferenceCountedObject()
108         : refCount() {}
109 
110     /** Destructor. */
~ReferenceCountedObject()111     virtual ~ReferenceCountedObject()
112     {
113         // it's dangerous to delete an object that's still referenced by something else!
114         wassert (getReferenceCount() == 0);
115     }
116 
117     /** Resets the reference count to zero without deleting the object.
118         You should probably never need to use this!
119     */
resetReferenceCount()120     void resetReferenceCount() noexcept
121     {
122         refCount = 0;
123     }
124 
125 private:
126     //==============================================================================
127     Atomic<int> refCount;
128 
129     CARLA_DECLARE_NON_COPY_CLASS (ReferenceCountedObject)
130 };
131 
132 
133 //==============================================================================
134 /**
135     Adds reference-counting to an object.
136 
137     This is effectively a version of the ReferenceCountedObject class, but which
138     uses a non-atomic counter, and so is not thread-safe (but which will be more
139     efficient).
140     For more details on how to use it, see the ReferenceCountedObject class notes.
141 
142     @see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
143 */
144 class SingleThreadedReferenceCountedObject
145 {
146 public:
147     //==============================================================================
148     /** Increments the object's reference count.
149 
150         This is done automatically by the smart pointer, but is public just
151         in case it's needed for nefarious purposes.
152     */
incReferenceCount()153     void incReferenceCount() noexcept
154     {
155         ++refCount;
156     }
157 
158     /** Decreases the object's reference count.
159         If the count gets to zero, the object will be deleted.
160     */
decReferenceCount()161     void decReferenceCount() noexcept
162     {
163         wassert (getReferenceCount() > 0);
164 
165         if (--refCount == 0)
166             delete this;
167     }
168 
169     /** Decreases the object's reference count.
170         If the count gets to zero, the object will not be deleted, but this method
171         will return true, allowing the caller to take care of deletion.
172     */
decReferenceCountWithoutDeleting()173     bool decReferenceCountWithoutDeleting() noexcept
174     {
175         wassert (getReferenceCount() > 0);
176         return --refCount == 0;
177     }
178 
179     /** Returns the object's current reference count. */
getReferenceCount()180     int getReferenceCount() const noexcept       { return refCount; }
181 
182 
183 protected:
184     //==============================================================================
185     /** Creates the reference-counted object (with an initial ref count of zero). */
SingleThreadedReferenceCountedObject()186     SingleThreadedReferenceCountedObject() : refCount (0)  {}
187 
188     /** Destructor. */
~SingleThreadedReferenceCountedObject()189     virtual ~SingleThreadedReferenceCountedObject()
190     {
191         // it's dangerous to delete an object that's still referenced by something else!
192         wassert (getReferenceCount() == 0);
193     }
194 
195 private:
196     //==============================================================================
197     int refCount;
198 
199     CARLA_DECLARE_NON_COPY_CLASS (SingleThreadedReferenceCountedObject)
200 };
201 
202 
203 //==============================================================================
204 /**
205     A smart-pointer class which points to a reference-counted object.
206 
207     The template parameter specifies the class of the object you want to point to - the easiest
208     way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
209     or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
210     class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
211     decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
212     should behave.
213 
214     When using this class, you'll probably want to create a typedef to abbreviate the full
215     templated name - e.g.
216     @code
217     struct MyClass  : public ReferenceCountedObject
218     {
219         typedef ReferenceCountedObjectPtr<MyClass> Ptr;
220         ...
221     @endcode
222 
223     @see ReferenceCountedObject, ReferenceCountedObjectArray
224 */
225 template <class ReferenceCountedObjectClass>
226 class ReferenceCountedObjectPtr
227 {
228 public:
229     /** The class being referenced by this pointer. */
230     typedef ReferenceCountedObjectClass ReferencedType;
231 
232     //==============================================================================
233     /** Creates a pointer to a null object. */
ReferenceCountedObjectPtr()234     ReferenceCountedObjectPtr() noexcept
235         : referencedObject (nullptr)
236     {
237     }
238 
239     /** Creates a pointer to an object.
240         This will increment the object's reference-count.
241     */
ReferenceCountedObjectPtr(ReferencedType * refCountedObject)242     ReferenceCountedObjectPtr (ReferencedType* refCountedObject) noexcept
243         : referencedObject (refCountedObject)
244     {
245         incIfNotNull (refCountedObject);
246     }
247 
248     /** Copies another pointer.
249         This will increment the object's reference-count.
250     */
ReferenceCountedObjectPtr(const ReferenceCountedObjectPtr & other)251     ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept
252         : referencedObject (other.referencedObject)
253     {
254         incIfNotNull (referencedObject);
255     }
256 
257     /** Copies another pointer.
258         This will increment the object's reference-count (if it is non-null).
259     */
260     template <typename Convertible>
ReferenceCountedObjectPtr(const ReferenceCountedObjectPtr<Convertible> & other)261     ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<Convertible>& other) noexcept
262         : referencedObject (static_cast<ReferencedType*> (other.get()))
263     {
264         incIfNotNull (referencedObject);
265     }
266 
267     /** Changes this pointer to point at a different object.
268         The reference count of the old object is decremented, and it might be
269         deleted if it hits zero. The new object's count is incremented.
270     */
271     ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other)
272     {
273         return operator= (other.referencedObject);
274     }
275 
276     /** Changes this pointer to point at a different object.
277         The reference count of the old object is decremented, and it might be
278         deleted if it hits zero. The new object's count is incremented.
279     */
280     template <typename Convertible>
281     ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<Convertible>& other)
282     {
283         return operator= (static_cast<ReferencedType*> (other.get()));
284     }
285 
286     /** Changes this pointer to point at a different object.
287 
288         The reference count of the old object is decremented, and it might be
289         deleted if it hits zero. The new object's count is incremented.
290     */
291     ReferenceCountedObjectPtr& operator= (ReferencedType* const newObject)
292     {
293         if (referencedObject != newObject)
294         {
295             incIfNotNull (newObject);
296             ReferencedType* const oldObject = referencedObject;
297             referencedObject = newObject;
298             decIfNotNull (oldObject);
299         }
300 
301         return *this;
302     }
303 
304    #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS
305     /** Takes-over the object from another pointer. */
ReferenceCountedObjectPtr(ReferenceCountedObjectPtr && other)306     ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept
307         : referencedObject (other.referencedObject)
308     {
309         other.referencedObject = nullptr;
310     }
311 
312     /** Takes-over the object from another pointer. */
313     ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other)
314     {
315         std::swap (referencedObject, other.referencedObject);
316         return *this;
317     }
318    #endif
319 
320     /** Destructor.
321         This will decrement the object's reference-count, which will cause the
322         object to be deleted when the ref-count hits zero.
323     */
~ReferenceCountedObjectPtr()324     ~ReferenceCountedObjectPtr()
325     {
326         ReferencedType* const oldObject = referencedObject; // need to null the pointer before deleting the object
327         referencedObject = nullptr;                         // in case this ptr is itself deleted as a side-effect
328         decIfNotNull (oldObject);                           // of the destructor
329     }
330 
331     //==============================================================================
332     /** Returns the object that this pointer references.
333         The pointer returned may be null, of course.
334     */
335     operator ReferencedType*() const noexcept       { return referencedObject; }
336 
337     /** Returns the object that this pointer references.
338         The pointer returned may be null, of course.
339     */
get()340     ReferencedType* get() const noexcept            { return referencedObject; }
341 
342     /** Returns the object that this pointer references.
343         The pointer returned may be null, of course.
344     */
getObject()345     ReferencedType* getObject() const noexcept      { return referencedObject; }
346 
347     // the -> operator is called on the referenced object
348     ReferencedType* operator->() const noexcept
349     {
350         wassert (referencedObject != nullptr); // null pointer method call!
351         return referencedObject;
352     }
353 
354 private:
355     //==============================================================================
356     ReferencedType* referencedObject;
357 
incIfNotNull(ReferencedType * o)358     static void incIfNotNull (ReferencedType* o) noexcept
359     {
360         if (o != nullptr)
361             o->incReferenceCount();
362     }
363 
decIfNotNull(ReferencedType * o)364     static void decIfNotNull (ReferencedType* o) noexcept
365     {
366         if (o != nullptr && o->decReferenceCountWithoutDeleting())
367             delete o;
368     }
369 };
370 
371 
372 //==============================================================================
373 /** Compares two ReferenceCountedObjectPtrs. */
374 template <typename ReferenceCountedObjectClass>
375 bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) noexcept
376 {
377     return object1.get() == object2;
378 }
379 
380 /** Compares two ReferenceCountedObjectPtrs. */
381 template <typename ReferenceCountedObjectClass>
382 bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
383 {
384     return object1.get() == object2.get();
385 }
386 
387 /** Compares two ReferenceCountedObjectPtrs. */
388 template <typename ReferenceCountedObjectClass>
389 bool operator== (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
390 {
391     return object1 == object2.get();
392 }
393 
394 /** Compares two ReferenceCountedObjectPtrs. */
395 template <typename ReferenceCountedObjectClass>
396 bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectClass* object2) noexcept
397 {
398     return object1.get() != object2;
399 }
400 
401 /** Compares two ReferenceCountedObjectPtrs. */
402 template <typename ReferenceCountedObjectClass>
403 bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
404 {
405     return object1.get() != object2.get();
406 }
407 
408 /** Compares two ReferenceCountedObjectPtrs. */
409 template <typename ReferenceCountedObjectClass>
410 bool operator!= (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
411 {
412     return object1 != object2.get();
413 }
414 
415 }
416 
417 #endif // WATER_REFERENCECOUNTEDOBJECT_H_INCLUDED
418