1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    The code included in this file is provided under the terms of the ISC license
11    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12    To use, copy, modify, and/or distribute this software for any purpose with or
13    without fee is hereby granted provided that the above copyright notice and
14    this permission notice appear in all copies.
15 
16    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18    DISCLAIMED.
19 
20   ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 //==============================================================================
27 /**
28     A base class which provides methods for reference-counting.
29 
30     To add reference-counting to a class, derive it from this class, and
31     use the ReferenceCountedObjectPtr class to point to it.
32 
33     e.g. @code
34     class MyClass : public ReferenceCountedObject
35     {
36         void foo();
37 
38         // This is a neat way of declaring a typedef for a pointer class,
39         // rather than typing out the full templated name each time..
40         using Ptr = ReferenceCountedObjectPtr<MyClass>;
41     };
42 
43     MyClass::Ptr p = new MyClass();
44     MyClass::Ptr p2 = p;
45     p = nullptr;
46     p2->foo();
47     @endcode
48 
49     Once a new ReferenceCountedObject has been assigned to a pointer, be
50     careful not to delete the object manually.
51 
52     This class uses an Atomic<int> value to hold the reference count, so
53     the reference count can be updated on multiple threads. Note that
54     whilst it's thread-safe to create and delete a ReferenceCountedObjectPtr
55     to a ReferenceCountedObject shared between threads, it's not thread-safe
56     to modify or swap the ReferenceCountedObject.
57 
58     For a faster but non-thread-safe version, use SingleThreadedReferenceCountedObject
59     instead.
60 
61     @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
62 
63     @tags{Core}
64 */
65 class JUCE_API  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         jassert (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         jassert (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). */
107     ReferenceCountedObject() = default;
108 
109     /** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject(const ReferenceCountedObject &)110     ReferenceCountedObject (const ReferenceCountedObject&) noexcept {}
111     /** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject(ReferenceCountedObject &&)112     ReferenceCountedObject (ReferenceCountedObject&&) noexcept {}
113     /** Copying from another object does not affect this one's reference-count. */
114     ReferenceCountedObject& operator= (const ReferenceCountedObject&) noexcept  { return *this; }
115     /** Copying from another object does not affect this one's reference-count. */
116     ReferenceCountedObject& operator= (ReferenceCountedObject&&) noexcept       { return *this; }
117 
118     /** Destructor. */
~ReferenceCountedObject()119     virtual ~ReferenceCountedObject()
120     {
121         // it's dangerous to delete an object that's still referenced by something else!
122         jassert (getReferenceCount() == 0);
123     }
124 
125     /** Resets the reference count to zero without deleting the object.
126         You should probably never need to use this!
127     */
resetReferenceCount()128     void resetReferenceCount() noexcept
129     {
130         refCount = 0;
131     }
132 
133 private:
134     //==============================================================================
135     Atomic<int> refCount { 0 };
136     friend struct ContainerDeletePolicy<ReferenceCountedObject>;
137 };
138 
139 
140 //==============================================================================
141 /**
142     Adds reference-counting to an object.
143 
144     This is effectively a version of the ReferenceCountedObject class, but which
145     uses a non-atomic counter, and so is not thread-safe (but which will be more
146     efficient).
147     For more details on how to use it, see the ReferenceCountedObject class notes.
148 
149     @see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
150 
151     @tags{Core}
152 */
153 class JUCE_API  SingleThreadedReferenceCountedObject
154 {
155 public:
156     //==============================================================================
157     /** Increments the object's reference count.
158 
159         This is done automatically by the smart pointer, but is public just
160         in case it's needed for nefarious purposes.
161     */
162     void incReferenceCount() noexcept
163     {
164         ++refCount;
165     }
166 
167     /** Decreases the object's reference count.
168         If the count gets to zero, the object will be deleted.
169     */
170     void decReferenceCount() noexcept
171     {
172         jassert (getReferenceCount() > 0);
173 
174         if (--refCount == 0)
175             delete this;
176     }
177 
178     /** Decreases the object's reference count.
179         If the count gets to zero, the object will not be deleted, but this method
180         will return true, allowing the caller to take care of deletion.
181     */
182     bool decReferenceCountWithoutDeleting() noexcept
183     {
184         jassert (getReferenceCount() > 0);
185         return --refCount == 0;
186     }
187 
188     /** Returns the object's current reference count. */
189     int getReferenceCount() const noexcept       { return refCount; }
190 
191 
192 protected:
193     //==============================================================================
194     /** Creates the reference-counted object (with an initial ref count of zero). */
195     SingleThreadedReferenceCountedObject() = default;
196 
197     /** Copying from another object does not affect this one's reference-count. */
198     SingleThreadedReferenceCountedObject (const SingleThreadedReferenceCountedObject&) {}
199     /** Copying from another object does not affect this one's reference-count. */
200     SingleThreadedReferenceCountedObject (SingleThreadedReferenceCountedObject&&) {}
201     /** Copying from another object does not affect this one's reference-count. */
202     SingleThreadedReferenceCountedObject& operator= (const SingleThreadedReferenceCountedObject&) { return *this; }
203     /** Copying from another object does not affect this one's reference-count. */
204     SingleThreadedReferenceCountedObject& operator= (SingleThreadedReferenceCountedObject&&) { return *this; }
205 
206     /** Destructor. */
207     virtual ~SingleThreadedReferenceCountedObject()
208     {
209         // it's dangerous to delete an object that's still referenced by something else!
210         jassert (getReferenceCount() == 0);
211     }
212 
213 private:
214     //==============================================================================
215     int refCount = 0;
216     friend struct ContainerDeletePolicy<ReferenceCountedObject>;
217 };
218 
219 
220 //==============================================================================
221 /**
222     A smart-pointer class which points to a reference-counted object.
223 
224     The template parameter specifies the class of the object you want to point to - the easiest
225     way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
226     or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
227     class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
228     decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
229     should behave.
230 
231     When using this class, you'll probably want to create a typedef to abbreviate the full
232     templated name - e.g.
233     @code
234     struct MyClass  : public ReferenceCountedObject
235     {
236         using Ptr = ReferenceCountedObjectPtr<MyClass>;
237         ...
238     }
239     @endcode
240 
241     @see ReferenceCountedObject, ReferenceCountedObjectArray
242 
243     @tags{Core}
244 */
245 template <class ObjectType>
246 class ReferenceCountedObjectPtr
247 {
248 public:
249     /** The class being referenced by this pointer. */
250     using ReferencedType = ObjectType;
251 
252     //==============================================================================
253     /** Creates a pointer to a null object. */
254     ReferenceCountedObjectPtr() = default;
255 
256     /** Creates a pointer to a null object. */
257     ReferenceCountedObjectPtr (decltype (nullptr)) noexcept {}
258 
259     /** Creates a pointer to an object.
260         This will increment the object's reference-count.
261     */
262     ReferenceCountedObjectPtr (ReferencedType* refCountedObject) noexcept
263         : referencedObject (refCountedObject)
264     {
265         incIfNotNull (refCountedObject);
266     }
267 
268     /** Creates a pointer to an object.
269         This will increment the object's reference-count.
270     */
271     ReferenceCountedObjectPtr (ReferencedType& refCountedObject) noexcept
272         : referencedObject (&refCountedObject)
273     {
274         refCountedObject.incReferenceCount();
275     }
276 
277     /** Copies another pointer.
278         This will increment the object's reference-count.
279     */
280     ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept
281         : referencedObject (other.referencedObject)
282     {
283         incIfNotNull (referencedObject);
284     }
285 
286     /** Takes-over the object from another pointer. */
287     ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept
288         : referencedObject (other.referencedObject)
289     {
290         other.referencedObject = nullptr;
291     }
292 
293     /** Copies another pointer.
294         This will increment the object's reference-count (if it is non-null).
295     */
296     template <typename Convertible>
297     ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<Convertible>& other) noexcept
298         : referencedObject (other.get())
299     {
300         incIfNotNull (referencedObject);
301     }
302 
303     /** Changes this pointer to point at a different object.
304         The reference count of the old object is decremented, and it might be
305         deleted if it hits zero. The new object's count is incremented.
306     */
307     ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other)
308     {
309         return operator= (other.referencedObject);
310     }
311 
312     /** Changes this pointer to point at a different object.
313         The reference count of the old object is decremented, and it might be
314         deleted if it hits zero. The new object's count is incremented.
315     */
316     template <typename Convertible>
317     ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<Convertible>& other)
318     {
319         return operator= (other.get());
320     }
321 
322     /** Changes this pointer to point at a different object.
323 
324         The reference count of the old object is decremented, and it might be
325         deleted if it hits zero. The new object's count is incremented.
326     */
327     ReferenceCountedObjectPtr& operator= (ReferencedType* newObject)
328     {
329         if (newObject != nullptr)
330             return operator= (*newObject);
331 
332         reset();
333         return *this;
334     }
335 
336     /** Changes this pointer to point at a different object.
337 
338         The reference count of the old object is decremented, and it might be
339         deleted if it hits zero. The new object's count is incremented.
340     */
341     ReferenceCountedObjectPtr& operator= (ReferencedType& newObject)
342     {
343         if (referencedObject != &newObject)
344         {
345             newObject.incReferenceCount();
346             auto* oldObject = referencedObject;
347             referencedObject = &newObject;
348             decIfNotNull (oldObject);
349         }
350 
351         return *this;
352     }
353 
354     /** Resets this pointer to a null pointer. */
355     ReferenceCountedObjectPtr& operator= (decltype (nullptr))
356     {
357         reset();
358         return *this;
359     }
360 
361     /** Takes-over the object from another pointer. */
362     ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other) noexcept
363     {
364         std::swap (referencedObject, other.referencedObject);
365         return *this;
366     }
367 
368     /** Destructor.
369         This will decrement the object's reference-count, which will cause the
370         object to be deleted when the ref-count hits zero.
371     */
372     ~ReferenceCountedObjectPtr()
373     {
374         decIfNotNull (referencedObject);
375     }
376 
377     //==============================================================================
378     /** Returns the object that this pointer references.
379         The pointer returned may be null, of course.
380     */
381     ReferencedType* get() const noexcept                    { return referencedObject; }
382 
383     /** Resets this object to a null pointer. */
384     void reset() noexcept
385     {
386         auto oldObject = referencedObject;  // need to null the pointer before deleting the object
387         referencedObject = nullptr;         // in case this ptr is itself deleted as a side-effect
388         decIfNotNull (oldObject);           // of the destructor
389     }
390 
391     // the -> operator is called on the referenced object
392     ReferencedType* operator->() const noexcept
393     {
394         jassert (referencedObject != nullptr); // null pointer method call!
395         return referencedObject;
396     }
397 
398     /** Dereferences the object that this pointer references.
399         The pointer returned may be null, of course.
400     */
401     ReferencedType& operator*() const noexcept              { jassert (referencedObject != nullptr); return *referencedObject; }
402 
403     /** Checks whether this pointer is null */
404     bool operator== (decltype (nullptr)) const noexcept     { return referencedObject == nullptr; }
405     /** Checks whether this pointer is null */
406     bool operator!= (decltype (nullptr)) const noexcept     { return referencedObject != nullptr; }
407 
408     /** Compares two ReferenceCountedObjectPtrs. */
409     bool operator== (const ObjectType* other) const noexcept                 { return referencedObject == other; }
410     /** Compares two ReferenceCountedObjectPtrs. */
411     bool operator== (const ReferenceCountedObjectPtr& other) const noexcept  { return referencedObject == other.get(); }
412     /** Compares two ReferenceCountedObjectPtrs. */
413     bool operator!= (const ObjectType* other) const noexcept                 { return referencedObject != other; }
414     /** Compares two ReferenceCountedObjectPtrs. */
415     bool operator!= (const ReferenceCountedObjectPtr& other) const noexcept  { return referencedObject != other.get(); }
416 
417    #if JUCE_STRICT_REFCOUNTEDPOINTER
418     /** Checks whether this pointer is null */
419     explicit operator bool() const noexcept                 { return referencedObject != nullptr; }
420 
421    #else
422     /** Returns the object that this pointer references.
423         The pointer returned may be null, of course.
424         Note that this methods allows the compiler to be very lenient with what it allows you to do
425         with the pointer, it's safer to disable this by setting JUCE_STRICT_REFCOUNTEDPOINTER=1, which
426         increased type safety and can prevent some common slip-ups.
427     */
428     operator ReferencedType*() const noexcept               { return referencedObject; }
429    #endif
430 
431 
432     // This old method is deprecated in favour of the shorter and more standard get() method.
433     JUCE_DEPRECATED_WITH_BODY (ReferencedType* getObject() const, { return get(); })
434 
435 private:
436     //==============================================================================
437     ReferencedType* referencedObject = nullptr;
438 
439     static void incIfNotNull (ReferencedType* o) noexcept
440     {
441         if (o != nullptr)
442             o->incReferenceCount();
443     }
444 
445     static void decIfNotNull (ReferencedType* o) noexcept
446     {
447         if (o != nullptr && o->decReferenceCountWithoutDeleting())
448             ContainerDeletePolicy<ReferencedType>::destroy (o);
449     }
450 };
451 
452 
453 //==============================================================================
454 /** Compares two ReferenceCountedObjectPtrs. */
455 template <typename Type>
456 bool operator== (const Type* object1, const ReferenceCountedObjectPtr<Type>& object2) noexcept
457 {
458     return object1 == object2.get();
459 }
460 
461 /** Compares two ReferenceCountedObjectPtrs. */
462 template <typename Type>
463 bool operator!= (const Type* object1, const ReferenceCountedObjectPtr<Type>& object2) noexcept
464 {
465     return object1 != object2.get();
466 }
467 
468 } // namespace juce
469