00001
00002
00003
00004
00005
00006
00007 #ifndef __singleton_h__
00008 #define __singleton_h__
00009
00010 #include <algorithm>
00011 #include <stdexcept>
00012 #include <cassert>
00013 #include <cstdlib>
00014 #include <new>
00015
00016 namespace Chroma
00017 {
00018
00019
00020
00021
00022
00023
00024
00025 template <class Host>
00026 class SingleThreaded
00027 {
00028 public:
00029 struct Lock
00030 {
00031 Lock() {}
00032 Lock(const Host&) {}
00033 };
00034
00035 typedef Host VolatileType;
00036
00037 typedef int IntType;
00038
00039 static IntType AtomicAdd(volatile IntType& lval, IntType val)
00040 { return lval += val; }
00041
00042 static IntType AtomicSubtract(volatile IntType& lval, IntType val)
00043 { return lval -= val; }
00044
00045 static IntType AtomicMultiply(volatile IntType& lval, IntType val)
00046 { return lval *= val; }
00047
00048 static IntType AtomicDivide(volatile IntType& lval, IntType val)
00049 { return lval /= val; }
00050
00051 static IntType AtomicIncrement(volatile IntType& lval)
00052 { return ++lval; }
00053
00054 static IntType AtomicDivide(volatile IntType& lval)
00055 { return --lval; }
00056
00057 static void AtomicAssign(volatile IntType & lval, IntType val)
00058 { lval = val; }
00059
00060 static void AtomicAssign(IntType & lval, volatile IntType & val)
00061 { lval = val; }
00062 };
00063
00064
00065
00066 namespace Private
00067 {
00068
00069
00070
00071
00072
00073 class LifetimeTracker
00074 {
00075 public:
00076 LifetimeTracker(unsigned int x) : longevity_(x)
00077 {}
00078
00079 virtual ~LifetimeTracker() = 0;
00080
00081 static bool Compare(const LifetimeTracker* lhs,
00082 const LifetimeTracker* rhs)
00083 {
00084 return rhs->longevity_ > lhs->longevity_;
00085 }
00086
00087 private:
00088 unsigned int longevity_;
00089 };
00090
00091
00092 inline LifetimeTracker::~LifetimeTracker() {}
00093
00094
00095 typedef LifetimeTracker** TrackerArray;
00096 extern TrackerArray pTrackerArray;
00097 extern unsigned int elements;
00098
00099
00100 template <typename T>
00101 struct Deleter
00102 {
00103 static void Delete(T* pObj)
00104 { delete pObj; }
00105 };
00106
00107
00108 template <typename T, typename Destroyer>
00109 class ConcreteLifetimeTracker : public LifetimeTracker
00110 {
00111 public:
00112 ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d)
00113 : LifetimeTracker(longevity)
00114 , pTracked_(p)
00115 , destroyer_(d)
00116 {}
00117
00118 ~ConcreteLifetimeTracker()
00119 { destroyer_(pTracked_); }
00120
00121 private:
00122 T* pTracked_;
00123 Destroyer destroyer_;
00124 };
00125
00126 void AtExitFn();
00127
00128 }
00129
00130
00131
00132
00133
00134
00135
00136 template <typename T, typename Destroyer>
00137 void SetLongevity(T* pDynObject, unsigned int longevity,
00138 Destroyer d = Private::Deleter<T>::Delete)
00139 {
00140 using namespace Private;
00141
00142 TrackerArray pNewArray = static_cast<TrackerArray>(
00143 std::realloc(pTrackerArray, elements + 1));
00144 if (!pNewArray) throw std::bad_alloc();
00145
00146 LifetimeTracker* p = new ConcreteLifetimeTracker<T, Destroyer>(
00147 pDynObject, longevity, d);
00148
00149
00150 pTrackerArray = pNewArray;
00151
00152
00153 TrackerArray pos = std::upper_bound(
00154 pTrackerArray,
00155 pTrackerArray + elements,
00156 p,
00157 LifetimeTracker::Compare);
00158 std::copy_backward(
00159 pos,
00160 pTrackerArray + elements,
00161 pTrackerArray + elements + 1);
00162 *pos = p;
00163 ++elements;
00164
00165
00166 std::atexit(Private::AtExitFn);
00167 }
00168
00169
00170
00171
00172
00173
00174
00175 template <class T> struct CreateUsingNew
00176 {
00177 static T* Create()
00178 { return new T; }
00179
00180 static void Destroy(T* p)
00181 { delete p; }
00182 };
00183
00184
00185
00186
00187
00188
00189
00190
00191 template <class T> struct CreateUsingMalloc
00192 {
00193 static T* Create()
00194 {
00195 void* p = std::malloc(sizeof(T));
00196 if (!p) return 0;
00197 return new(p) T;
00198 }
00199
00200 static void Destroy(T* p)
00201 {
00202 p->~T();
00203 std::free(p);
00204 }
00205 };
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 template <class T> struct CreateStatic
00217 {
00218 union MaxAlign
00219 {
00220 char t_[sizeof(T)];
00221 short int shortInt_;
00222 int int_;
00223 long int longInt_;
00224 float float_;
00225 double double_;
00226 long double longDouble_;
00227 struct Test;
00228 int Test::* pMember_;
00229 int (Test::*pMemberFn_)(int);
00230 };
00231
00232 static T* Create()
00233 {
00234 static MaxAlign staticMemory_;
00235 return new(&staticMemory_) T;
00236 }
00237
00238 static void Destroy(T* p)
00239 {
00240 p->~T();
00241 }
00242 };
00243
00244
00245
00246
00247
00248
00249
00250
00251 template <class T>
00252 struct DefaultLifetime
00253 {
00254 static void ScheduleDestruction(T*, void (*pFun)())
00255 { std::atexit(pFun); }
00256
00257 static void OnDeadReference()
00258 { throw std::logic_error("Dead Reference Detected"); }
00259 };
00260
00261
00262 template <class T>
00263 struct DefaultLifetime1
00264 {
00265 static void ScheduleDestruction(T*, void (*pFun)())
00266 { std::atexit(pFun); }
00267
00268 static void OnDeadReference()
00269 { throw std::logic_error("Dead Reference Detected"); }
00270 };
00271
00272
00273 template <class T>
00274 struct DefaultLifetime2
00275 {
00276 static void ScheduleDestruction(T*, void (*pFun)())
00277 { std::atexit(pFun); }
00278
00279 static void OnDeadReference()
00280 { throw std::logic_error("Dead Reference Detected"); }
00281 };
00282
00283
00284
00285
00286
00287
00288
00289
00290 template <class T>
00291 class PhoenixSingleton
00292 {
00293 public:
00294 static void ScheduleDestruction(T*, void (*pFun)())
00295 {
00296 #ifndef ATEXIT_FIXED
00297 if (!destroyedOnce_)
00298 #endif
00299 std::atexit(pFun);
00300 }
00301
00302 static void OnDeadReference()
00303 {
00304 #ifndef ATEXIT_FIXED
00305 destroyedOnce_ = true;
00306 #endif
00307 }
00308
00309 private:
00310 #ifndef ATEXIT_FIXED
00311 static bool destroyedOnce_;
00312 #endif
00313 };
00314
00315 #ifndef ATEXIT_FIXED
00316 template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false;
00317 #endif
00318
00319
00320
00321
00322
00323
00324 namespace Private
00325 {
00326 template <class T>
00327 struct Adapter
00328 {
00329 void operator()(T*) { return pFun_(); }
00330 void (*pFun_)();
00331 };
00332 }
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342 template <class T>
00343 class SingletonWithLongevity
00344 {
00345 public:
00346 static void ScheduleDestruction(T* pObj, void (*pFun)())
00347 {
00348 Private::Adapter<T> adapter = { pFun };
00349 SetLongevity(pObj, GetLongevity(pObj), adapter);
00350 }
00351
00352 static void OnDeadReference()
00353 { throw std::logic_error("Dead Reference Detected"); }
00354 };
00355
00356
00357
00358
00359
00360
00361
00362 template <class T>
00363 struct NoDestroy
00364 {
00365 static void ScheduleDestruction(T*, void (*)())
00366 {}
00367
00368 static void OnDeadReference()
00369 {}
00370 };
00371
00372
00373
00374
00375
00376
00377
00378
00379 template <typename T,
00380 template <class> class CreationPolicy = CreateUsingNew,
00381 template <class> class LifetimePolicy = DefaultLifetime,
00382 template <class> class ThreadingModel = SingleThreaded>
00383 class SingletonHolder
00384 {
00385 public:
00386 static T& Instance();
00387
00388 private:
00389
00390 static void MakeInstance();
00391 static void DestroySingleton();
00392
00393
00394 SingletonHolder();
00395
00396
00397 typedef typename ThreadingModel<T*>::VolatileType PtrInstanceType;
00398 static PtrInstanceType pInstance_;
00399 static bool destroyed_;
00400 };
00401
00402
00403
00404
00405
00406 template <class T,
00407 template <class> class C,
00408 template <class> class L,
00409 template <class> class M>
00410 typename SingletonHolder<T, C, L, M>::PtrInstanceType
00411 SingletonHolder<T, C, L, M>::pInstance_;
00412
00413 template
00414 <
00415 class T,
00416 template <class> class C,
00417 template <class> class L,
00418 template <class> class M
00419 >
00420 bool SingletonHolder<T, C, L, M>::destroyed_;
00421
00422
00423
00424
00425
00426 template <class T,
00427 template <class> class CreationPolicy,
00428 template <class> class LifetimePolicy,
00429 template <class> class ThreadingModel>
00430 inline T& SingletonHolder<T, CreationPolicy,
00431 LifetimePolicy, ThreadingModel>::Instance()
00432 {
00433 if (!pInstance_)
00434 {
00435 MakeInstance();
00436 }
00437 return *pInstance_;
00438 }
00439
00440
00441
00442
00443
00444 template <class T,
00445 template <class> class CreationPolicy,
00446 template <class> class LifetimePolicy,
00447 template <class> class ThreadingModel>
00448 void SingletonHolder<T, CreationPolicy,
00449 LifetimePolicy, ThreadingModel>::MakeInstance()
00450 {
00451 typename ThreadingModel<T>::Lock guard;
00452 (void)guard;
00453
00454 if (!pInstance_)
00455 {
00456 if (destroyed_)
00457 {
00458 LifetimePolicy<T>::OnDeadReference();
00459 destroyed_ = false;
00460 }
00461 pInstance_ = CreationPolicy<T>::Create();
00462 LifetimePolicy<T>::ScheduleDestruction(pInstance_,
00463 &DestroySingleton);
00464 }
00465 }
00466
00467 template <class T,
00468 template <class> class CreationPolicy,
00469 template <class> class L,
00470 template <class> class M>
00471 void SingletonHolder<T, CreationPolicy, L, M>::DestroySingleton()
00472 {
00473 assert(!destroyed_);
00474 CreationPolicy<T>::Destroy(pInstance_);
00475 pInstance_ = 0;
00476 destroyed_ = true;
00477 }
00478 }
00479
00480
00481 #endif