singleton.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 // $Id: singleton.h,v 3.3 2007/03/05 20:09:37 bjoo Exp $
00003 /*! @file
00004  * @brief Singleton support
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 // class template SingleThreaded
00021 // Implementation of the ThreadingModel policy used by various classes
00022 // Implements a single-threaded model; no synchronization
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 // class LifetimeTracker
00070 // Helper class for SetLongevity
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     // Definition required
00092     inline LifetimeTracker::~LifetimeTracker() {} 
00093         
00094     // Helper data
00095     typedef LifetimeTracker** TrackerArray;
00096     extern TrackerArray pTrackerArray;
00097     extern unsigned int elements;
00098 
00099     // Helper destroyer function
00100     template <typename T>
00101     struct Deleter
00102     {
00103       static void Delete(T* pObj)
00104         { delete pObj; }
00105     };
00106 
00107     // Concrete lifetime tracker for objects of type T
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(); // declaration needed below
00127     
00128   } // namespace Private
00129 
00130 ////////////////////////////////////////////////////////////////////////////////
00131 // function template SetLongevity
00132 // Assigns an object a longevity; ensures ordered destructions of objects 
00133 //     registered thusly during the exit sequence of the application
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     // Delayed assignment for exception safety
00150     pTrackerArray = pNewArray;
00151         
00152     // Insert a pointer to the object into the queue
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     // Register a call to AtExitFn
00166     std::atexit(Private::AtExitFn);
00167   }
00168 
00169 ////////////////////////////////////////////////////////////////////////////////
00170 // class template CreateUsingNew
00171 // Implementation of the CreationPolicy used by SingletonHolder
00172 // Creates objects using a straight call to the new operator 
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 // class template CreateUsingNew
00186 // Implementation of the CreationPolicy used by SingletonHolder
00187 // Creates objects using a call to std::malloc, followed by a call to the 
00188 //     placement new operator
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 // class template CreateStatic
00209 // Implementation of the CreationPolicy used by SingletonHolder
00210 // Creates an object in static memory
00211 // Implementation is slightly nonportable because it uses the MaxAlign trick 
00212 //     (an union of all types to ensure proper memory alignment). This trick is 
00213 //     nonportable in theory but highly portable in practice.
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 // class template DefaultLifetime
00246 // Implementation of the LifetimePolicy used by SingletonHolder
00247 // Schedules an object's destruction as per C++ rules
00248 // Forwards to std::atexit
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   // Copy to help with disambiguation
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   // Copy to help with disambiguation
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 // class template PhoenixSingleton
00285 // Implementation of the LifetimePolicy used by SingletonHolder
00286 // Schedules an object's destruction as per C++ rules, and it allows object 
00287 //    recreation by not throwing an exception from OnDeadReference
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 // class template Adapter
00321 // Helper for SingletonWithLongevity below
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 // class template SingletonWithLongevity
00336 // Implementation of the LifetimePolicy used by SingletonHolder
00337 // Schedules an object's destruction in order of their longevities
00338 // Assumes a visible function GetLongevity(T*) that returns the longevity of the
00339 //     object
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 // class template NoDestroy
00358 // Implementation of the LifetimePolicy used by SingletonHolder
00359 // Never destroys the object
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 // class template SingletonHolder
00374 // Provides Singleton amenities for a type T
00375 // To protect that type from spurious instantiations, you have to protect it
00376 //     yourself.
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     // Helpers
00390     static void MakeInstance();
00391     static void DestroySingleton();
00392         
00393     // Protection
00394     SingletonHolder();
00395         
00396     // Data
00397     typedef typename ThreadingModel<T*>::VolatileType PtrInstanceType;
00398     static PtrInstanceType pInstance_;
00399     static bool destroyed_;
00400   };
00401     
00402 ////////////////////////////////////////////////////////////////////////////////
00403 // SingletonHolder's data
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 // SingletonHolder::Instance
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 // SingletonHolder::MakeInstance (helper for Instance)
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 } // namespace Chroma
00479 
00480 
00481 #endif

Generated on Mon Mar 15 04:34:40 2010 for CHROMA by  doxygen 1.4.7