|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- /*
- ==============================================================================
-
- This file is part of the Water library.
- Copyright (c) 2016 ROLI Ltd.
- Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
-
- Permission is granted to use this software under the terms of the ISC license
- http://www.isc.org/downloads/software-support-policy/isc-license/
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
- TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
- OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- OF THIS SOFTWARE.
-
- ==============================================================================
- */
-
- #ifndef WATER_REFERENCECOUNTEDOBJECT_H_INCLUDED
- #define WATER_REFERENCECOUNTEDOBJECT_H_INCLUDED
-
- #include "Atomic.h"
-
- namespace water {
-
- //==============================================================================
- /**
- A base class which provides methods for reference-counting.
-
- To add reference-counting to a class, derive it from this class, and
- use the ReferenceCountedObjectPtr class to point to it.
-
- e.g. @code
- class MyClass : public ReferenceCountedObject
- {
- void foo();
-
- // This is a neat way of declaring a typedef for a pointer class,
- // rather than typing out the full templated name each time..
- typedef ReferenceCountedObjectPtr<MyClass> Ptr;
- };
-
- MyClass::Ptr p = new MyClass();
- MyClass::Ptr p2 = p;
- p = nullptr;
- p2->foo();
- @endcode
-
- Once a new ReferenceCountedObject has been assigned to a pointer, be
- careful not to delete the object manually.
-
- This class uses an Atomic<int> value to hold the reference count, so that it
- the pointers can be passed between threads safely. For a faster but non-thread-safe
- version, use SingleThreadedReferenceCountedObject instead.
-
- @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
- */
- class ReferenceCountedObject
- {
- public:
- //==============================================================================
- /** Increments the object's reference count.
-
- This is done automatically by the smart pointer, but is public just
- in case it's needed for nefarious purposes.
- */
- void incReferenceCount() noexcept
- {
- ++refCount;
- }
-
- /** Decreases the object's reference count.
- If the count gets to zero, the object will be deleted.
- */
- void decReferenceCount() noexcept
- {
- jassert (getReferenceCount() > 0);
-
- if (--refCount == 0)
- delete this;
- }
-
- /** Decreases the object's reference count.
- If the count gets to zero, the object will not be deleted, but this method
- will return true, allowing the caller to take care of deletion.
- */
- bool decReferenceCountWithoutDeleting() noexcept
- {
- jassert (getReferenceCount() > 0);
- return --refCount == 0;
- }
-
- /** Returns the object's current reference count. */
- int getReferenceCount() const noexcept { return refCount.get(); }
-
-
- protected:
- //==============================================================================
- /** Creates the reference-counted object (with an initial ref count of zero). */
- ReferenceCountedObject() {}
-
- /** Destructor. */
- virtual ~ReferenceCountedObject()
- {
- // it's dangerous to delete an object that's still referenced by something else!
- jassert (getReferenceCount() == 0);
- }
-
- /** Resets the reference count to zero without deleting the object.
- You should probably never need to use this!
- */
- void resetReferenceCount() noexcept
- {
- refCount = 0;
- }
-
- private:
- //==============================================================================
- Atomic <int> refCount;
-
- CARLA_DECLARE_NON_COPY_CLASS (ReferenceCountedObject)
- };
-
-
- //==============================================================================
- /**
- Adds reference-counting to an object.
-
- This is effectively a version of the ReferenceCountedObject class, but which
- uses a non-atomic counter, and so is not thread-safe (but which will be more
- efficient).
- For more details on how to use it, see the ReferenceCountedObject class notes.
-
- @see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
- */
- class SingleThreadedReferenceCountedObject
- {
- public:
- //==============================================================================
- /** Increments the object's reference count.
-
- This is done automatically by the smart pointer, but is public just
- in case it's needed for nefarious purposes.
- */
- void incReferenceCount() noexcept
- {
- ++refCount;
- }
-
- /** Decreases the object's reference count.
- If the count gets to zero, the object will be deleted.
- */
- void decReferenceCount() noexcept
- {
- jassert (getReferenceCount() > 0);
-
- if (--refCount == 0)
- delete this;
- }
-
- /** Decreases the object's reference count.
- If the count gets to zero, the object will not be deleted, but this method
- will return true, allowing the caller to take care of deletion.
- */
- bool decReferenceCountWithoutDeleting() noexcept
- {
- jassert (getReferenceCount() > 0);
- return --refCount == 0;
- }
-
- /** Returns the object's current reference count. */
- int getReferenceCount() const noexcept { return refCount; }
-
-
- protected:
- //==============================================================================
- /** Creates the reference-counted object (with an initial ref count of zero). */
- SingleThreadedReferenceCountedObject() : refCount (0) {}
-
- /** Destructor. */
- virtual ~SingleThreadedReferenceCountedObject()
- {
- // it's dangerous to delete an object that's still referenced by something else!
- jassert (getReferenceCount() == 0);
- }
-
- private:
- //==============================================================================
- int refCount;
-
- CARLA_DECLARE_NON_COPY_CLASS (SingleThreadedReferenceCountedObject)
- };
-
-
- //==============================================================================
- /**
- A smart-pointer class which points to a reference-counted object.
-
- The template parameter specifies the class of the object you want to point to - the easiest
- way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
- or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
- class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
- decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
- should behave.
-
- When using this class, you'll probably want to create a typedef to abbreviate the full
- templated name - e.g.
- @code
- struct MyClass : public ReferenceCountedObject
- {
- typedef ReferenceCountedObjectPtr<MyClass> Ptr;
- ...
- @endcode
-
- @see ReferenceCountedObject, ReferenceCountedObjectArray
- */
- template <class ReferenceCountedObjectClass>
- class ReferenceCountedObjectPtr
- {
- public:
- /** The class being referenced by this pointer. */
- typedef ReferenceCountedObjectClass ReferencedType;
-
- //==============================================================================
- /** Creates a pointer to a null object. */
- ReferenceCountedObjectPtr() noexcept
- : referencedObject (nullptr)
- {
- }
-
- /** Creates a pointer to an object.
- This will increment the object's reference-count.
- */
- ReferenceCountedObjectPtr (ReferencedType* refCountedObject) noexcept
- : referencedObject (refCountedObject)
- {
- incIfNotNull (refCountedObject);
- }
-
- /** Copies another pointer.
- This will increment the object's reference-count.
- */
- ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept
- : referencedObject (other.referencedObject)
- {
- incIfNotNull (referencedObject);
- }
-
- /** Copies another pointer.
- This will increment the object's reference-count (if it is non-null).
- */
- template <typename Convertible>
- ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<Convertible>& other) noexcept
- : referencedObject (static_cast<ReferencedType*> (other.get()))
- {
- incIfNotNull (referencedObject);
- }
-
- /** Changes this pointer to point at a different object.
- The reference count of the old object is decremented, and it might be
- deleted if it hits zero. The new object's count is incremented.
- */
- ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other)
- {
- return operator= (other.referencedObject);
- }
-
- /** Changes this pointer to point at a different object.
- The reference count of the old object is decremented, and it might be
- deleted if it hits zero. The new object's count is incremented.
- */
- template <typename Convertible>
- ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<Convertible>& other)
- {
- return operator= (static_cast<ReferencedType*> (other.get()));
- }
-
- /** Changes this pointer to point at a different object.
-
- The reference count of the old object is decremented, and it might be
- deleted if it hits zero. The new object's count is incremented.
- */
- ReferenceCountedObjectPtr& operator= (ReferencedType* const newObject)
- {
- if (referencedObject != newObject)
- {
- incIfNotNull (newObject);
- ReferencedType* const oldObject = referencedObject;
- referencedObject = newObject;
- decIfNotNull (oldObject);
- }
-
- return *this;
- }
-
- #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS
- /** Takes-over the object from another pointer. */
- ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept
- : referencedObject (other.referencedObject)
- {
- other.referencedObject = nullptr;
- }
-
- /** Takes-over the object from another pointer. */
- ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other)
- {
- std::swap (referencedObject, other.referencedObject);
- return *this;
- }
- #endif
-
- /** Destructor.
- This will decrement the object's reference-count, which will cause the
- object to be deleted when the ref-count hits zero.
- */
- ~ReferenceCountedObjectPtr()
- {
- ReferencedType* const oldObject = referencedObject; // need to null the pointer before deleting the object
- referencedObject = nullptr; // in case this ptr is itself deleted as a side-effect
- decIfNotNull (oldObject); // of the destructor
- }
-
- //==============================================================================
- /** Returns the object that this pointer references.
- The pointer returned may be null, of course.
- */
- operator ReferencedType*() const noexcept { return referencedObject; }
-
- /** Returns the object that this pointer references.
- The pointer returned may be null, of course.
- */
- ReferencedType* get() const noexcept { return referencedObject; }
-
- /** Returns the object that this pointer references.
- The pointer returned may be null, of course.
- */
- ReferencedType* getObject() const noexcept { return referencedObject; }
-
- // the -> operator is called on the referenced object
- ReferencedType* operator->() const noexcept
- {
- jassert (referencedObject != nullptr); // null pointer method call!
- return referencedObject;
- }
-
- private:
- //==============================================================================
- ReferencedType* referencedObject;
-
- static void incIfNotNull (ReferencedType* o) noexcept
- {
- if (o != nullptr)
- o->incReferenceCount();
- }
-
- static void decIfNotNull (ReferencedType* o) noexcept
- {
- if (o != nullptr && o->decReferenceCountWithoutDeleting())
- delete o;
- }
- };
-
-
- //==============================================================================
- /** Compares two ReferenceCountedObjectPtrs. */
- template <typename ReferenceCountedObjectClass>
- bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) noexcept
- {
- return object1.get() == object2;
- }
-
- /** Compares two ReferenceCountedObjectPtrs. */
- template <typename ReferenceCountedObjectClass>
- bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
- {
- return object1.get() == object2.get();
- }
-
- /** Compares two ReferenceCountedObjectPtrs. */
- template <typename ReferenceCountedObjectClass>
- bool operator== (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
- {
- return object1 == object2.get();
- }
-
- /** Compares two ReferenceCountedObjectPtrs. */
- template <typename ReferenceCountedObjectClass>
- bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectClass* object2) noexcept
- {
- return object1.get() != object2;
- }
-
- /** Compares two ReferenceCountedObjectPtrs. */
- template <typename ReferenceCountedObjectClass>
- bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
- {
- return object1.get() != object2.get();
- }
-
- /** Compares two ReferenceCountedObjectPtrs. */
- template <typename ReferenceCountedObjectClass>
- bool operator!= (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
- {
- return object1 != object2.get();
- }
-
- }
-
- #endif // WATER_REFERENCECOUNTEDOBJECT_H_INCLUDED
|