00001 #ifndef __LDK_SINGLETONS_HH__ 00002 #define __LDK_SINGLETONS_HH__ 00003 00005 // Copyright (C) 2003-2006 Lorien Dunn. 00006 // 00007 // Contact: loriendunn AT users DOT sourceforge DOT net 00008 // 00009 // This software is provided 'as-is', without any express or implied warranty. 00010 // In no event will the authors be held liable for any damages arising from 00011 // the use of this software. 00012 // 00013 // Permission is granted to anyone to use this software for any purpose, 00014 // including commercial applications, and to alter it and redistribute it 00015 // freely, subject to the following restrictions: 00016 // 00017 // 1. The origin of this software must not be misrepresented; you must not 00018 // claim that you wrote the original software. If you use this software in a 00019 // product, an acknowledgment in the product documentation would be 00020 // appreciated but is not required. 00021 // 00022 // 2. Altered source versions must be plainly marked as such, and must not be 00023 // misrepresented as being the original software. 00024 // 00025 // 3. This notice may not be removed or altered from any source distribution. 00026 // 00028 00033 00034 #include "LDK/ThreadLocalStorage.h" 00035 #include "LDK/STLMallocAllocator.h" 00036 #include <vector> 00037 #include <assert.h> 00038 00039 namespace LDK 00040 { 00041 00042 typedef void (*SingletonDtor) (); 00043 00044 #ifdef _MSC_VER 00045 #pragma warning (disable : 4251) 00046 #endif 00047 00049 00050 class LDK_API SingletonCleanup 00051 { 00052 private: 00053 00054 typedef std::vector<SingletonDtor,MallocAllocator<SingletonDtor> > CleanupVec; 00055 00056 static CleanupVec mToClean; 00057 static bool mInitialised; 00058 00059 static void callDtors(); 00060 00061 public: 00062 00063 static void initialise(); 00064 static void addInstance(SingletonDtor dtor); 00065 }; 00066 00067 class LDK_API ThreadLocalCleanup 00068 { 00069 private: 00070 00071 struct Pair //can't use std::pair because of const issues 00072 { 00073 ThreadLocalDtor mDtor; 00074 void* mInstance; 00075 Pair(ThreadLocalDtor dtor=NULL, void* instance=NULL) : 00076 mDtor(dtor), 00077 mInstance(instance) 00078 {} 00079 }; 00080 00081 typedef std::vector<Pair,MallocAllocator<Pair> > CleanupVec; 00082 00083 CleanupVec mToClean; 00084 static TLSKey mKey; 00085 static bool mInitialised; 00086 00087 static void callThreadDtors(void* s); 00088 static void callDtors(); 00089 00090 public: 00091 00092 static void initialise(); 00093 static void addInstance(ThreadLocalDtor dtor, void* instance); 00094 }; 00095 00104 template <class T> 00105 class SingletonStorage 00106 { 00107 public: 00108 typedef T Type; 00109 typedef T* PointerType; 00110 typedef T& ReferenceType; 00111 protected: 00112 static bool mInitialised; 00113 static PointerType mInstance; 00114 static void destroy() 00115 { 00116 if(mInstance) 00117 delete mInstance; 00118 } 00119 public: 00120 static void initialise() 00121 { 00122 if(!mInitialised) 00123 { 00124 SingletonCleanup::initialise(); 00125 try 00126 { 00127 mInstance = new T(); 00128 mInitialised = true; 00129 } 00130 catch(std::bad_alloc&) 00131 { 00132 throw LDK_BADALLOC_ERROR; 00133 } 00134 SingletonCleanup::addInstance(SingletonStorage::destroy); 00135 } 00136 } 00137 static ReferenceType instance() 00138 { 00139 assert(mInitialised); 00140 assert(mInstance); 00141 return *mInstance; 00142 } 00143 }; 00144 template <class T> 00145 bool SingletonStorage<T>::mInitialised = false; 00146 template <class T> 00147 T* SingletonStorage<T>::mInstance = NULL; 00148 00149 00150 00159 template <class T> 00160 class TLSSingletonStorage 00161 { 00162 public: 00163 typedef T Type; 00164 typedef T* PointerType; 00165 typedef T& ReferenceType; 00166 protected: 00167 static bool mInitialised; 00168 static TLSKey mKey; 00169 static void destroy(void* obj) 00170 { 00171 if(obj) 00172 delete reinterpret_cast<T*>(obj); 00173 } 00174 public: 00175 static void initialise() 00176 { 00177 if(!mInitialised) 00178 { 00179 ThreadLocalCleanup::initialise(); 00180 mKey = threadLocalCreateKey(); 00181 mInitialised = true; 00182 } 00183 } 00184 static ReferenceType instance() 00185 { 00186 assert(mInitialised); 00187 PointerType instance = reinterpret_cast<PointerType>(threadLocalGet(mKey)); 00188 if(instance) 00189 return *instance; 00190 try 00191 { 00192 instance = new T(); 00193 } 00194 catch(std::bad_alloc&) 00195 { 00196 throw LDK_BADALLOC_ERROR; 00197 } 00198 threadLocalSet(mKey, instance); 00199 ThreadLocalCleanup::addInstance(TLSSingletonStorage::destroy,instance); 00200 return *instance; 00201 } 00202 }; 00203 00204 template <class T> 00205 bool TLSSingletonStorage<T>::mInitialised = false; 00206 template <class T> 00207 TLSKey TLSSingletonStorage<T>::mKey = 0; 00208 00209 #define DEFAULT_SINGLETON_STORAGE TLSSingletonStorage 00210 00211 00226 template 00227 < 00228 class T, 00229 template <class> class StoragePolicy=DEFAULT_SINGLETON_STORAGE 00230 > 00231 class Singleton : public StoragePolicy<T> 00232 { 00233 public: 00234 typedef StoragePolicy<T> SP; 00235 typedef typename SP::Type Type; 00236 typedef typename SP::PointerType PointerType; 00237 typedef typename SP::ReferenceType ReferenceType; 00238 protected: 00239 inline Singleton () {} 00240 inline Singleton (const Singleton &) {} 00241 inline ~Singleton() {} 00242 inline void operator=(const Singleton&) {} 00243 public: 00244 inline static void initialise() 00245 { 00246 SP::initialise(); 00247 } 00248 inline static ReferenceType instance() 00249 { 00250 return SP::instance(); 00251 } 00252 }; 00253 00254 } //namespace LDK 00255 00256 #ifdef _MSC_VER 00257 #pragma warning (default : 4251) 00258 #endif 00259 00260 #endif //__LDK_SINGLETONS_HH__