diff options
Diffstat (limited to 'dep/include/zthread/Singleton.h')
-rw-r--r-- | dep/include/zthread/Singleton.h | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/dep/include/zthread/Singleton.h b/dep/include/zthread/Singleton.h new file mode 100644 index 00000000000..b66c9d0898a --- /dev/null +++ b/dep/include/zthread/Singleton.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTSINGLETON_H__ +#define __ZTSINGLETON_H__ + +#include "zthread/Guard.h" +#include "zthread/FastMutex.h" +#include <assert.h> + +namespace ZThread { + +// +// This policy controls how an object is instantiated +// as well as how and when its destroyed. Phoenix-style +// singletons are not supported easily with type of policy, +// this is intentional since I do not believe that is in +// the true spirit of a singleton. +// +// InstantiationPolicContract { +// +// create(pointer_type&) +// +// } + +/** + * @class LocalStaticInstantiation + * @author Eric Crahen <http://www.code-foo.com> + * @date <2003-07-16T17:57:45-0400> + * @version 2.2.0 + * + * The LocalStaticInstantiation policy allows the creation + * and lifetime of an instance of a particular type + * to be managed using static local values. This will + * abide by the standard C++ rules for static objects + * lifetimes. + */ +class LocalStaticInstantiation { +protected: + + /** + * Create an instance of an object, using a local static. The + * object will be destroyed by the system. + * + * @param ptr reference to location to receive the address + * of the allocated object + */ + template <class T> + static void create(T*& ptr) { + + static T instance; + ptr = &instance; + + } + +}; + +//! Helper class +template <class T> +class StaticInstantiationHelper { + //! Friend class + friend class StaticInstantiation; + //! Holder + static T instance; + + }; + + template <class T> + T StaticInstantiationHelper<T>::instance; + +/** + * @class StaticInstantiation + * @author Eric Crahen <http://www.code-foo.com> + * @date <2003-07-16T17:57:45-0400> + * @version 2.2.0 + * + * The StaticInstantiation policy allows the creation + * and lifetime of an instance of a particular type + * to be managed using static instantiation. This will + * abide by the standard C++ rules for static objects + * lifetimes. + */ +class StaticInstantiation { +protected: + + /** + * Create an instance of an object using by simply allocating it statically. + * + * @param ptr reference to location to receive the address + * of the allocated object + */ + template <class T> + static void create(T*& ptr) { + ptr = &StaticInstantiationHelper<T>::instance; + } + +}; + +//! SingletonDestroyer +template <class T> +class Destroyer { + + T* doomed; + + public: + + Destroyer(T* q) : doomed(q) { + assert(doomed); + } + + ~Destroyer(); + +}; + +template <class T> +Destroyer<T>::~Destroyer() { + + try { + + if(doomed) + delete doomed; + + } catch(...) { } + + doomed = 0; + +} + + +/** + * @class LazyInstantiation + * @author Eric Crahen <http://www.code-foo.com> + * @date <2003-07-16T17:57:45-0400> + * @version 2.2.0 + * + * The LazyInstantiation policy allows the creation + * and lifetime of an instance of a particular type + * to be managed using dynamic allocation and a singleton + * destroyer. This will abide by the standard C++ rules + * for static objects lifetimes. + */ +class LazyInstantiation { +protected: + + /** + * Create an instance of an object, using new, that will be + * destroyed when an associated Destroyer object (allocated + * statically) goes out of scope. + * + * @param ptr reference to location to receive the address + * of the allocated object + */ + template <class T> + static void create(T*& ptr) { + + ptr = new T; + static Destroyer<T> destroyer(ptr); + + } + +}; + + +/** + * @class Singleton + * @author Eric Crahen <http://www.code-foo.com> + * @date <2003-07-16T17:57:45-0400> + * @version 2.2.0 + * + * Based on the work of John Vlissidles in his book 'Pattern Hatching' + * an article by Douglas Schmidtt on double-checked locking and policy + * templates described by Andrei Alexandrescu. + * + * This is a thread safe wrapper for creating Singleton classes. The + * synchronization method and instantiation methods can be changed + * easily by specifying different policy implementations as the + * templates parameters. + * + * @code + * + * // Most common Singleton + * Singletion<LonesomeType> + * + * // Singleton that uses static storage + * Singletion<LonesomeType, StaticInstantiation> + * + * // Single-threaded singleton that uses static storage (Meyers-like) + * Singletion<LonesomeType, LocalStaticInstantiation, NotLocked> + * + * @endcode + */ +template <class T, class InstantiationPolicy=LazyInstantiation, class LockType=FastMutex> +class Singleton : private InstantiationPolicy, private NonCopyable { +public: + + /** + * Provide access to the single instance through double-checked locking + * + * @return T* single instance + */ + static T* instance(); + +}; + +template <class T, class InstantiationPolicy, class LockType> +T* Singleton<T, InstantiationPolicy, LockType>::instance() { + + // Uses local static storage to avoid static construction + // sequence issues. (regaring when the lock is created) + static T* ptr = 0; + static LockType lock; + + if(!ptr) { + + Guard<LockType, LockedScope> g(lock); + if(!ptr) + InstantiationPolicy::create(ptr); + + } + + return const_cast<T*>(ptr); + + } + + +}; + +#endif + + |