|
|
@@ -25,12 +25,115 @@ namespace juce |
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/**
|
|
|
|
Macro to declare member variables and methods for a singleton class.
|
|
|
|
Used by the JUCE_DECLARE_SINGLETON macros to manage a static pointer
|
|
|
|
to a singleton instance.
|
|
|
|
|
|
|
|
You generally won't use this directly, but see the macros JUCE_DECLARE_SINGLETON,
|
|
|
|
JUCE_DECLARE_SINGLETON_SINGLETHREADED, JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL,
|
|
|
|
and JUCE_IMPLEMENT_SINGLETON for how it is intended to be used.
|
|
|
|
*/
|
|
|
|
template <typename Type, typename MutexType, bool onlyCreateOncePerRun>
|
|
|
|
struct SingletonHolder : private MutexType // (inherited so we can use the empty-base-class optimisation)
|
|
|
|
{
|
|
|
|
SingletonHolder() noexcept {}
|
|
|
|
|
|
|
|
~SingletonHolder()
|
|
|
|
{
|
|
|
|
/* The static singleton holder is being deleted before the object that it holds
|
|
|
|
has been deleted. This could mean that you've forgotten to call clearSingletonInstance()
|
|
|
|
in the class's destructor, or have failed to delete it before your app shuts down.
|
|
|
|
If you're having trouble cleaning up your singletons, perhaps consider using the
|
|
|
|
SharedResourcePointer class instead.
|
|
|
|
*/
|
|
|
|
jassert (instance == nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns the current instance, or creates a new instance if there isn't one. */
|
|
|
|
Type* get()
|
|
|
|
{
|
|
|
|
if (instance == nullptr)
|
|
|
|
{
|
|
|
|
typename MutexType::ScopedLockType sl (*this);
|
|
|
|
|
|
|
|
if (instance == nullptr)
|
|
|
|
{
|
|
|
|
if (onlyCreateOncePerRun)
|
|
|
|
{
|
|
|
|
static bool createdOnceAlready = false;
|
|
|
|
|
|
|
|
if (createdOnceAlready)
|
|
|
|
{
|
|
|
|
// This means that the doNotRecreateAfterDeletion flag was set
|
|
|
|
// and you tried to create the singleton more than once.
|
|
|
|
jassertfalse;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
createdOnceAlready = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool alreadyInside = false;
|
|
|
|
|
|
|
|
if (alreadyInside)
|
|
|
|
{
|
|
|
|
// This means that your object's constructor has done something which has
|
|
|
|
// ended up causing a recursive loop of singleton creation..
|
|
|
|
jassertfalse;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
alreadyInside = true;
|
|
|
|
getWithoutChecking();
|
|
|
|
alreadyInside = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns the current instance, or creates a new instance if there isn't one, but doesn't do
|
|
|
|
any locking, or checking for recursion or error conditions.
|
|
|
|
*/
|
|
|
|
Type* getWithoutChecking()
|
|
|
|
{
|
|
|
|
if (instance == nullptr)
|
|
|
|
{
|
|
|
|
auto newObject = new Type(); // (create into a local so that instance is still null during construction)
|
|
|
|
instance = newObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Deletes and resets the current instance, if there is one. */
|
|
|
|
void deleteInstance()
|
|
|
|
{
|
|
|
|
typename MutexType::ScopedLockType sl (*this);
|
|
|
|
auto old = instance;
|
|
|
|
instance = nullptr;
|
|
|
|
delete old;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Called by the class's destructor to clear the pointer if it is currently set to the given object. */
|
|
|
|
void clear (Type* expectedObject) noexcept
|
|
|
|
{
|
|
|
|
if (instance == expectedObject)
|
|
|
|
instance = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
To use this, add the line juce_DeclareSingleton (MyClass, doNotRecreateAfterDeletion)
|
|
|
|
Type* instance = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/**
|
|
|
|
Macro to generate the appropriate methods and boilerplate for a singleton class.
|
|
|
|
|
|
|
|
To use this, add the line JUCE_DECLARE_SINGLETON(MyClass, doNotRecreateAfterDeletion)
|
|
|
|
to the class's definition.
|
|
|
|
|
|
|
|
Then put a macro juce_ImplementSingleton (MyClass) along with the class's
|
|
|
|
Then put a macro JUCE_IMPLEMENT_SINGLETON(MyClass) along with the class's
|
|
|
|
implementation code.
|
|
|
|
|
|
|
|
It's also a very good idea to also add the call clearSingletonInstance() in your class's
|
|
|
@@ -42,12 +145,9 @@ namespace juce |
|
|
|
|
|
|
|
e.g. @code
|
|
|
|
|
|
|
|
class MySingleton
|
|
|
|
struct MySingleton
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MySingleton()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
MySingleton() {}
|
|
|
|
|
|
|
|
~MySingleton()
|
|
|
|
{
|
|
|
@@ -56,14 +156,15 @@ namespace juce |
|
|
|
clearSingletonInstance();
|
|
|
|
}
|
|
|
|
|
|
|
|
juce_DeclareSingleton (MySingleton, false)
|
|
|
|
JUCE_DECLARE_SINGLETON (MySingleton, false)
|
|
|
|
};
|
|
|
|
|
|
|
|
juce_ImplementSingleton (MySingleton)
|
|
|
|
// ..and this goes in a suitable .cpp file:
|
|
|
|
JUCE_IMPLEMENT_SINGLETON (MySingleton)
|
|
|
|
|
|
|
|
|
|
|
|
// example of usage:
|
|
|
|
MySingleton* m = MySingleton::getInstance(); // creates the singleton if there isn't already one.
|
|
|
|
auto* m = MySingleton::getInstance(); // creates the singleton if there isn't already one.
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
@@ -77,84 +178,38 @@ namespace juce |
|
|
|
objects being accidentally re-created during your app's shutdown code.
|
|
|
|
|
|
|
|
If you know that your object will only be created and deleted by a single thread, you
|
|
|
|
can use the slightly more efficient juce_DeclareSingleton_SingleThreaded() macro instead
|
|
|
|
can use the slightly more efficient JUCE_DECLARE_SINGLETON_SINGLETHREADED macro instead
|
|
|
|
of this one.
|
|
|
|
|
|
|
|
@see juce_ImplementSingleton, juce_DeclareSingleton_SingleThreaded
|
|
|
|
@see JUCE_IMPLEMENT_SINGLETON, JUCE_DECLARE_SINGLETON_SINGLETHREADED
|
|
|
|
*/
|
|
|
|
#define juce_DeclareSingleton(classname, doNotRecreateAfterDeletion) \
|
|
|
|
\
|
|
|
|
static classname* _singletonInstance; \
|
|
|
|
static juce::CriticalSection _singletonLock; \
|
|
|
|
\
|
|
|
|
static classname* JUCE_CALLTYPE getInstance() \
|
|
|
|
{ \
|
|
|
|
if (_singletonInstance == nullptr) \
|
|
|
|
{\
|
|
|
|
const juce::ScopedLock sl (_singletonLock); \
|
|
|
|
\
|
|
|
|
if (_singletonInstance == nullptr) \
|
|
|
|
{ \
|
|
|
|
static bool alreadyInside = false; \
|
|
|
|
static bool createdOnceAlready = false; \
|
|
|
|
\
|
|
|
|
const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
|
|
|
|
jassert (! problem); \
|
|
|
|
if (! problem) \
|
|
|
|
{ \
|
|
|
|
createdOnceAlready = true; \
|
|
|
|
alreadyInside = true; \
|
|
|
|
classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
|
|
|
|
alreadyInside = false; \
|
|
|
|
\
|
|
|
|
_singletonInstance = newObject; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
return _singletonInstance; \
|
|
|
|
} \
|
|
|
|
#define JUCE_DECLARE_SINGLETON(Classname, doNotRecreateAfterDeletion) \
|
|
|
|
\
|
|
|
|
static inline classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept\
|
|
|
|
{ \
|
|
|
|
return _singletonInstance; \
|
|
|
|
} \
|
|
|
|
static juce::SingletonHolder<Classname, juce::CriticalSection, doNotRecreateAfterDeletion> singletonHolder; \
|
|
|
|
friend decltype (singletonHolder); \
|
|
|
|
\
|
|
|
|
static void JUCE_CALLTYPE deleteInstance() \
|
|
|
|
{ \
|
|
|
|
const juce::ScopedLock sl (_singletonLock); \
|
|
|
|
if (_singletonInstance != nullptr) \
|
|
|
|
{ \
|
|
|
|
classname* const old = _singletonInstance; \
|
|
|
|
_singletonInstance = nullptr; \
|
|
|
|
delete old; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
void clearSingletonInstance() noexcept\
|
|
|
|
{ \
|
|
|
|
if (_singletonInstance == this) \
|
|
|
|
_singletonInstance = nullptr; \
|
|
|
|
}
|
|
|
|
static Classname* JUCE_CALLTYPE getInstance() { return singletonHolder.get(); } \
|
|
|
|
static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \
|
|
|
|
static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \
|
|
|
|
void clearSingletonInstance() noexcept { singletonHolder.clear (this); }
|
|
|
|
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/** This is a counterpart to the juce_DeclareSingleton macro.
|
|
|
|
/** This is a counterpart to the JUCE_DECLARE_SINGLETON macros.
|
|
|
|
|
|
|
|
After adding the juce_DeclareSingleton to the class definition, this macro has
|
|
|
|
After adding the JUCE_DECLARE_SINGLETON to the class definition, this macro has
|
|
|
|
to be used in the cpp file.
|
|
|
|
*/
|
|
|
|
#define juce_ImplementSingleton(classname) \
|
|
|
|
#define JUCE_IMPLEMENT_SINGLETON(Classname) \
|
|
|
|
\
|
|
|
|
classname* classname::_singletonInstance = nullptr; \
|
|
|
|
juce::CriticalSection classname::_singletonLock;
|
|
|
|
decltype (Classname::singletonHolder) Classname::singletonHolder;
|
|
|
|
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/**
|
|
|
|
Macro to declare member variables and methods for a singleton class.
|
|
|
|
|
|
|
|
This is exactly the same as juce_DeclareSingleton, but doesn't use a critical
|
|
|
|
This is exactly the same as JUCE_DECLARE_SINGLETON, but doesn't use a critical
|
|
|
|
section to make access to it thread-safe. If you know that your object will
|
|
|
|
only ever be created or deleted by a single thread, then this is a
|
|
|
|
more efficient version to use.
|
|
|
@@ -164,120 +219,61 @@ namespace juce |
|
|
|
object, getInstance() will refuse to create another one. This can be useful to stop
|
|
|
|
objects being accidentally re-created during your app's shutdown code.
|
|
|
|
|
|
|
|
See the documentation for juce_DeclareSingleton for more information about
|
|
|
|
how to use it, the only difference being that you have to use
|
|
|
|
juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton.
|
|
|
|
See the documentation for JUCE_DECLARE_SINGLETON for more information about
|
|
|
|
how to use it. Just like JUCE_DECLARE_SINGLETON you need to also have a
|
|
|
|
corresponding JUCE_IMPLEMENT_SINGLETON statement somewhere in your code.
|
|
|
|
|
|
|
|
@see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton, juce_DeclareSingleton_SingleThreaded_Minimal
|
|
|
|
@see JUCE_IMPLEMENT_SINGLETON, JUCE_DECLARE_SINGLETON, JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL
|
|
|
|
*/
|
|
|
|
#define juce_DeclareSingleton_SingleThreaded(classname, doNotRecreateAfterDeletion) \
|
|
|
|
\
|
|
|
|
static classname* _singletonInstance; \
|
|
|
|
\
|
|
|
|
static classname* getInstance() \
|
|
|
|
{ \
|
|
|
|
if (_singletonInstance == nullptr) \
|
|
|
|
{ \
|
|
|
|
static bool alreadyInside = false; \
|
|
|
|
static bool createdOnceAlready = false; \
|
|
|
|
\
|
|
|
|
const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
|
|
|
|
jassert (! problem); \
|
|
|
|
if (! problem) \
|
|
|
|
{ \
|
|
|
|
createdOnceAlready = true; \
|
|
|
|
alreadyInside = true; \
|
|
|
|
classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
|
|
|
|
alreadyInside = false; \
|
|
|
|
#define JUCE_DECLARE_SINGLETON_SINGLETHREADED(Classname, doNotRecreateAfterDeletion) \
|
|
|
|
\
|
|
|
|
_singletonInstance = newObject; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
static juce::SingletonHolder<Classname, juce::DummyCriticalSection, doNotRecreateAfterDeletion> singletonHolder; \
|
|
|
|
friend decltype (singletonHolder); \
|
|
|
|
\
|
|
|
|
return _singletonInstance; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static inline classname* getInstanceWithoutCreating() noexcept\
|
|
|
|
{ \
|
|
|
|
return _singletonInstance; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static void deleteInstance() \
|
|
|
|
{ \
|
|
|
|
if (_singletonInstance != nullptr) \
|
|
|
|
{ \
|
|
|
|
classname* const old = _singletonInstance; \
|
|
|
|
_singletonInstance = nullptr; \
|
|
|
|
delete old; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
void clearSingletonInstance() noexcept\
|
|
|
|
{ \
|
|
|
|
if (_singletonInstance == this) \
|
|
|
|
_singletonInstance = nullptr; \
|
|
|
|
}
|
|
|
|
static Classname* JUCE_CALLTYPE getInstance() { return singletonHolder.get(); } \
|
|
|
|
static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \
|
|
|
|
static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \
|
|
|
|
void clearSingletonInstance() noexcept { singletonHolder.clear (this); }
|
|
|
|
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/**
|
|
|
|
Macro to declare member variables and methods for a singleton class.
|
|
|
|
|
|
|
|
This is like juce_DeclareSingleton_SingleThreaded, but doesn't do any checking
|
|
|
|
This is like JUCE_DECLARE_SINGLETON_SINGLETHREADED, but doesn't do any checking
|
|
|
|
for recursion or repeated instantiation. It's intended for use as a lightweight
|
|
|
|
version of a singleton, where you're using it in very straightforward
|
|
|
|
circumstances and don't need the extra checking.
|
|
|
|
|
|
|
|
Just use the normal juce_ImplementSingleton_SingleThreaded as the counterpart
|
|
|
|
to this declaration, as you would with juce_DeclareSingleton_SingleThreaded.
|
|
|
|
Just use the normal JUCE_IMPLEMENT_SINGLETON_SINGLETHREADED as the counterpart
|
|
|
|
to this declaration, as you would with JUCE_DECLARE_SINGLETON_SINGLETHREADED.
|
|
|
|
|
|
|
|
See the documentation for juce_DeclareSingleton for more information about
|
|
|
|
See the documentation for JUCE_DECLARE_SINGLETON for more information about
|
|
|
|
how to use it, the only difference being that you have to use
|
|
|
|
juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton.
|
|
|
|
JUCE_IMPLEMENT_SINGLETON_SINGLETHREADED instead of JUCE_IMPLEMENT_SINGLETON.
|
|
|
|
|
|
|
|
@see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton
|
|
|
|
@see JUCE_IMPLEMENT_SINGLETON_SINGLETHREADED, JUCE_DECLARE_SINGLETON
|
|
|
|
*/
|
|
|
|
#define juce_DeclareSingleton_SingleThreaded_Minimal(classname) \
|
|
|
|
\
|
|
|
|
static classname* _singletonInstance; \
|
|
|
|
\
|
|
|
|
static classname* getInstance() \
|
|
|
|
{ \
|
|
|
|
if (_singletonInstance == nullptr) \
|
|
|
|
_singletonInstance = new classname(); \
|
|
|
|
#define JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL(Classname) \
|
|
|
|
\
|
|
|
|
return _singletonInstance; \
|
|
|
|
} \
|
|
|
|
static juce::SingletonHolder<Classname, juce::DummyCriticalSection, false> singletonHolder; \
|
|
|
|
friend decltype (singletonHolder); \
|
|
|
|
\
|
|
|
|
static inline classname* getInstanceWithoutCreating() noexcept\
|
|
|
|
{ \
|
|
|
|
return _singletonInstance; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static void deleteInstance() \
|
|
|
|
{ \
|
|
|
|
if (_singletonInstance != nullptr) \
|
|
|
|
{ \
|
|
|
|
classname* const old = _singletonInstance; \
|
|
|
|
_singletonInstance = nullptr; \
|
|
|
|
delete old; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
void clearSingletonInstance() noexcept\
|
|
|
|
{ \
|
|
|
|
if (_singletonInstance == this) \
|
|
|
|
_singletonInstance = nullptr; \
|
|
|
|
}
|
|
|
|
static Classname* JUCE_CALLTYPE getInstance() { return singletonHolder.getWithoutChecking(); } \
|
|
|
|
static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \
|
|
|
|
static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \
|
|
|
|
void clearSingletonInstance() noexcept { singletonHolder.clear (this); }
|
|
|
|
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/** This is a counterpart to the juce_DeclareSingleton_SingleThreaded macro.
|
|
|
|
|
|
|
|
After adding juce_DeclareSingleton_SingleThreaded or juce_DeclareSingleton_SingleThreaded_Minimal
|
|
|
|
to the class definition, this macro has to be used somewhere in the cpp file.
|
|
|
|
*/
|
|
|
|
#define juce_ImplementSingleton_SingleThreaded(classname) \
|
|
|
|
\
|
|
|
|
classname* classname::_singletonInstance = nullptr;
|
|
|
|
#ifndef DOXYGEN
|
|
|
|
// These are ancient macros, and have now been updated with new names to match the JUCE style guide,
|
|
|
|
// so please update your code to use the newer versions!
|
|
|
|
#define juce_DeclareSingleton(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON(Classname, doNotRecreate)
|
|
|
|
#define juce_DeclareSingleton_SingleThreaded(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON_SINGLETHREADED(Classname, doNotRecreate)
|
|
|
|
#define juce_DeclareSingleton_SingleThreaded_Minimal(Classname) JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL(Classname)
|
|
|
|
#define juce_ImplementSingleton(Classname) JUCE_IMPLEMENT_SINGLETON(Classname)
|
|
|
|
#define juce_ImplementSingleton_SingleThreaded(Classname) JUCE_IMPLEMENT_SINGLETON(Classname)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} // namespace juce
|