diff --git a/source/modules/juce_core/memory/juce_SharedResourcePointer.h b/source/modules/juce_core/memory/juce_SharedResourcePointer.h new file mode 100644 index 000000000..d765af40c --- /dev/null +++ b/source/modules/juce_core/memory/juce_SharedResourcePointer.h @@ -0,0 +1,152 @@ +/* + ============================================================================== + + This file is part of the juce_core module of the JUCE library. + Copyright (c) 2013 - Raw Material Software Ltd. + + 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 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + NO EVENT SHALL THE AUTHOR 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. + + ------------------------------------------------------------------------------ + + NOTE! This permissive ISC license applies ONLY to files within the juce_core module! + All other JUCE modules are covered by a dual GPL/commercial license, so if you are + using any other modules, be sure to check that you also comply with their license. + + For more details, visit www.juce.com + + ============================================================================== +*/ + +#ifndef JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED +#define JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED + + +//============================================================================== +/** + A smart-pointer that automatically creates and manages the lifetime of a + shared static instance of a class. + + The SharedObjectType template type indicates the class to use for the shared + object - the only requirements on this class are that it must have a public + default constructor and destructor. + + The SharedResourcePointer offers a pattern that differs from using a singleton or + static instance of an object, because it uses reference-counting to make sure that + the underlying shared object is automatically created/destroyed according to the + number of SharedResourcePointer objects that exist. When the last one is deleted, + the underlying object is also immediately destroyed. This allows you to use scoping + to manage the lifetime of a shared resource. + + Note: the construction/deletion of the shared object must not involve any + code that makes recursive calls to a SharedResourcePointer, or you'll cause + a deadlock. + + Example: + @code + // An example of a class that contains the shared data you want to use. + struct MySharedData + { + // There's no need to ever create an instance of this class directly yourself, + // but it does need a public constructor that does the initialisation. + MySharedData() + { + sharedStuff = generateHeavyweightStuff(); + } + + Array sharedStuff; + }; + + struct DataUserClass + { + DataUserClass() + { + // Multiple instances of the DataUserClass will all have the same + // shared common instance of MySharedData referenced by their sharedData + // member variables. + useSharedStuff (sharedData->sharedStuff); + } + + // By keeping this pointer as a member variable, the shared resource + // is guaranteed to be available for as long as the DataUserClass object. + SharedResourcePointer sharedData; + }; + + @endcode + */ +template +class SharedResourcePointer +{ +public: + /** Creates an instance of the shared object. + If other SharedResourcePointer objects for this type already exist, then + this one will simply point to the same shared object that they are already + using. Otherwise, if this is the first SharedResourcePointer to be created, + then a shared object will be created automatically. + */ + SharedResourcePointer() + { + SharedObjectHolder& holder = getSharedObjectHolder(); + const SpinLock::ScopedLockType sl (holder.lock); + + if (++(holder.refCount) == 1) + holder.sharedInstance = new SharedObjectType(); + + sharedObject = holder.sharedInstance; + } + + /** Destructor. + If no other SharedResourcePointer objects exist, this will also delete + the shared object to which it refers. + */ + ~SharedResourcePointer() + { + SharedObjectHolder& holder = getSharedObjectHolder(); + const SpinLock::ScopedLockType sl (holder.lock); + + if (--(holder.refCount) == 0) + holder.sharedInstance = nullptr; + } + + /** Returns the shared object. */ + operator SharedObjectType*() const noexcept { return sharedObject; } + + /** Returns the shared object. */ + SharedObjectType& get() const noexcept { return *sharedObject; } + + /** Returns the object that this pointer references. + The pointer returned may be zero, of course. + */ + SharedObjectType& getObject() const noexcept { return *sharedObject; } + + SharedObjectType* operator->() const noexcept { return sharedObject; } + +private: + struct SharedObjectHolder : public ReferenceCountedObject + { + SpinLock lock; + ScopedPointer sharedInstance; + int refCount; + }; + + static SharedObjectHolder& getSharedObjectHolder() noexcept + { + static char holder [sizeof (SharedObjectHolder)] = { 0 }; + return *reinterpret_cast (holder); + } + + SharedObjectType* sharedObject; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedResourcePointer) +}; + + +#endif // JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED