| @@ -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<SomeKindOfData> 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<MySharedData> sharedData; | |||
| }; | |||
| @endcode | |||
| */ | |||
| template <typename SharedObjectType> | |||
| 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<SharedObjectType> sharedInstance; | |||
| int refCount; | |||
| }; | |||
| static SharedObjectHolder& getSharedObjectHolder() noexcept | |||
| { | |||
| static char holder [sizeof (SharedObjectHolder)] = { 0 }; | |||
| return *reinterpret_cast<SharedObjectHolder*> (holder); | |||
| } | |||
| SharedObjectType* sharedObject; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedResourcePointer) | |||
| }; | |||
| #endif // JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED | |||