Singleton.h

00001 
00002 // The Loki Library
00003 // Copyright (c) 2001 by Andrei Alexandrescu
00004 // This code accompanies the book:
00005 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design 
00006 //     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
00007 // Permission to use, copy, modify, distribute and sell this software for any 
00008 //     purpose is hereby granted without fee, provided that the above copyright 
00009 //     notice appear in all copies and that both that copyright notice and this 
00010 //     permission notice appear in supporting documentation.
00011 // The author or Addison-Wesley Longman make no representations about the 
00012 //     suitability of this software for any purpose. It is provided "as is" 
00013 //     without express or implied warranty.
00015 #ifndef LOKI_SINGLETON_INC_
00016 #define LOKI_SINGLETON_INC_
00017 
00018 // $Id: Singleton.h 747 2006-10-17 19:48:40Z syntheticpp $
00019 
00020 
00021 #include "LokiExport.h"
00022 #include "Threads.h"
00023 #include <algorithm>
00024 #include <stdexcept>
00025 #include <cassert>
00026 #include <cstdlib>
00027 #include <new>
00028 #include <vector>
00029 #include <list>
00030 #include <memory>
00031 
00032 #ifdef _MSC_VER
00033 #define LOKI_C_CALLING_CONVENTION_QUALIFIER __cdecl 
00034 #else
00035 #define LOKI_C_CALLING_CONVENTION_QUALIFIER 
00036 #endif
00037 
00050 
00051 
00052 
00053 namespace Loki
00054 {
00055     typedef void (LOKI_C_CALLING_CONVENTION_QUALIFIER *atexit_pfn_t)();
00056 
00057     namespace Private
00058     {
00059 
00060 #ifndef LOKI_MAKE_DLL
00061         void LOKI_C_CALLING_CONVENTION_QUALIFIER AtExitFn(); // declaration needed below   
00062 #else
00063         void LOKI_EXPORT AtExitFn();
00064 #endif
00065 
00066         class LifetimeTracker;
00067 
00068 #define LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL        
00069 #ifdef LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL
00070 
00071         // Helper data
00072         // std::list because of the inserts
00073         typedef std::list<LifetimeTracker*> TrackerArray;
00074         extern LOKI_EXPORT TrackerArray* pTrackerArray;
00075 #else
00076         // Helper data
00077         typedef LifetimeTracker** TrackerArray;
00078         extern TrackerArray pTrackerArray;
00079         extern unsigned int elements;
00080 #endif
00081 
00083         // class LifetimeTracker
00084         // Helper class for SetLongevity
00086 
00087         class LifetimeTracker
00088         {
00089         public:
00090             LifetimeTracker(unsigned int x) : longevity_(x) 
00091             {}
00092             
00093             virtual ~LifetimeTracker() = 0;
00094             
00095             static bool Compare(const LifetimeTracker* lhs,
00096                 const LifetimeTracker* rhs)
00097             {
00098                 return lhs->longevity_ > rhs->longevity_;
00099             }
00100             
00101         private:
00102             unsigned int longevity_;
00103         };
00104         
00105         // Definition required
00106         inline LifetimeTracker::~LifetimeTracker() {} 
00107 
00108         // Helper destroyer function
00109         template <typename T>
00110         struct Deleter
00111         {
00112             typedef void (*Type)(T*);
00113             static void Delete(T* pObj)
00114             { delete pObj; }
00115         };
00116 
00117         // Concrete lifetime tracker for objects of type T
00118         template <typename T, typename Destroyer>
00119         class ConcreteLifetimeTracker : public LifetimeTracker
00120         {
00121         public:
00122             ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d)
00123                 : LifetimeTracker(longevity)
00124                 , pTracked_(p)
00125                 , destroyer_(d)
00126             {}
00127             
00128             ~ConcreteLifetimeTracker()
00129             { destroyer_(pTracked_); }
00130             
00131         private:
00132             T* pTracked_;
00133             Destroyer destroyer_;
00134         };
00135 
00136     } // namespace Private
00137 
00144 
00145 #ifdef LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL
00146 
00147     template <typename T, typename Destroyer>
00148     void SetLongevity(T* pDynObject, unsigned int longevity,
00149         Destroyer d)
00150     {
00151         using namespace Private;
00152 
00153         // manage lifetime of stack manually
00154         if(pTrackerArray==0)
00155             pTrackerArray = new TrackerArray;
00156 
00157         // automatically delete the ConcreteLifetimeTracker object when a exception is thrown
00158         std::auto_ptr<LifetimeTracker> 
00159             p( new ConcreteLifetimeTracker<T, Destroyer>(pDynObject, longevity, d) );
00160 
00161         // Find correct position
00162         TrackerArray::iterator pos = std::upper_bound(
00163             pTrackerArray->begin(), 
00164             pTrackerArray->end(), 
00165             p.get(), 
00166             LifetimeTracker::Compare);
00167         
00168         // Insert the pointer to the ConcreteLifetimeTracker object into the queue
00169         pTrackerArray->insert(pos, p.get());
00170         
00171         // nothing has thrown: don't delete the ConcreteLifetimeTracker object
00172         p.release();
00173         
00174         // Register a call to AtExitFn
00175         std::atexit(Private::AtExitFn);
00176     }
00177 
00178 #else
00179     
00180     template <typename T, typename Destroyer>
00181     void SetLongevity(T* pDynObject, unsigned int longevity,
00182         Destroyer d)
00183     {
00184         using namespace Private;
00185         
00186         TrackerArray pNewArray = static_cast<TrackerArray>(
00187                 std::realloc(pTrackerArray, 
00188                     sizeof(*pTrackerArray) * (elements + 1)));
00189         if (!pNewArray) throw std::bad_alloc();
00190         
00191         // Delayed assignment for exception safety
00192         pTrackerArray = pNewArray;
00193         
00194         LifetimeTracker* p = new ConcreteLifetimeTracker<T, Destroyer>(
00195             pDynObject, longevity, d);
00196  
00197         // Insert a pointer to the object into the queue
00198         TrackerArray pos = std::upper_bound(
00199             pTrackerArray, 
00200             pTrackerArray + elements, 
00201             p, 
00202             LifetimeTracker::Compare);
00203         std::copy_backward(
00204             pos, 
00205             pTrackerArray + elements,
00206             pTrackerArray + elements + 1);
00207         *pos = p;
00208         ++elements;
00209         
00210         // Register a call to AtExitFn
00211         std::atexit(Private::AtExitFn);
00212     }
00213 
00214 #endif
00215 
00216     template <typename T>
00217     void SetLongevity(T* pDynObject, unsigned int longevity,
00218         typename Private::Deleter<T>::Type d = Private::Deleter<T>::Delete)
00219     {
00220         SetLongevity<T, typename Private::Deleter<T>::Type>(pDynObject, longevity, d);
00221     }
00222 
00230     template <class T> struct CreateUsingNew
00231     {
00232         static T* Create()
00233         { return new T; }
00234         
00235         static void Destroy(T* p)
00236         { delete p; }
00237     };
00238     
00247     template<template<class> class Alloc>
00248     struct CreateUsing
00249     {
00250         template <class T>
00251         struct Allocator
00252         {
00253             static Alloc<T> allocator;
00254 
00255             static T* Create()
00256             {
00257                 return new (allocator.allocate(1)) T;
00258             }
00259 
00260             static void Destroy(T* p)
00261             {
00262                 //allocator.destroy(p);
00263                 p->~T();
00264                 allocator.deallocate(p,1);
00265             }
00266         };
00267     };
00268     
00277     template <class T> struct CreateUsingMalloc
00278     {
00279         static T* Create()
00280         {
00281             void* p = std::malloc(sizeof(T));
00282             if (!p) return 0;
00283             return new(p) T;
00284         }
00285         
00286         static void Destroy(T* p)
00287         {
00288             p->~T();
00289             std::free(p);
00290         }
00291     };
00292     
00293 
00304     template <class T> struct CreateStatic
00305     {
00306         
00307 #ifdef _MSC_VER
00308 #pragma warning( push ) 
00309 #pragma warning( disable : 4121 )
00310 // alignment of a member was sensitive to packing
00311 #endif // _MSC_VER
00312 
00313         union MaxAlign
00314         {
00315             char t_[sizeof(T)];
00316             short int shortInt_;
00317             int int_;
00318             long int longInt_;
00319             float float_;
00320             double double_;
00321             long double longDouble_;
00322             struct Test;
00323             int Test::* pMember_;
00324             int (Test::*pMemberFn_)(int);
00325         };
00326         
00327 #ifdef _MSC_VER
00328 #pragma warning( pop )
00329 #endif // _MSC_VER
00330         
00331         static T* Create()
00332         {
00333             static MaxAlign staticMemory_;
00334             return new(&staticMemory_) T;
00335         }
00336         
00337         static void Destroy(T* p)
00338         {
00339             p->~T();
00340         }
00341     };
00342 
00351     template <class T>
00352     struct DefaultLifetime
00353     {
00354         static void ScheduleDestruction(T*, atexit_pfn_t pFun)
00355         { std::atexit(pFun); }
00356         
00357         static void OnDeadReference()
00358         { throw std::logic_error("Dead Reference Detected"); }
00359     };
00360 
00369     template <class T>
00370     class PhoenixSingleton
00371     {
00372     public:
00373         static void ScheduleDestruction(T*, atexit_pfn_t pFun)
00374         {
00375 #ifndef ATEXIT_FIXED
00376             if (!destroyedOnce_)
00377 #endif
00378                 std::atexit(pFun);
00379         }
00380         
00381         static void OnDeadReference()
00382         {
00383 #ifndef ATEXIT_FIXED
00384             destroyedOnce_ = true;
00385 #endif
00386         }
00387         
00388     private:
00389 #ifndef ATEXIT_FIXED
00390         static bool destroyedOnce_;
00391 #endif
00392     };
00393     
00394 #ifndef ATEXIT_FIXED
00395     template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false;
00396 #endif
00397 
00399     // Copyright (c) 2004 by Curtis Krauskopf - curtis@decompile.com
00416     template <class T>
00417     class DeletableSingleton
00418     {
00419     public:
00420 
00421         static void ScheduleDestruction(T*, atexit_pfn_t pFun)
00422         {
00423             static bool firstPass = true;
00424             isDead = false;
00425             deleter = pFun;
00426             if (firstPass || needCallback)
00427             {
00428                 std::atexit(atexitCallback);
00429                 firstPass = false;
00430                 needCallback = false;
00431             }
00432         }
00433     
00434         static void OnDeadReference()
00435         { 
00436         }
00438         static void GracefulDelete()
00439         {
00440             if (isDead)
00441                 return;
00442             isDead = true;
00443             deleter();
00444         }
00445     
00446     protected:
00447         static atexit_pfn_t deleter;
00448         static bool isDead;
00449         static bool needCallback;
00450         
00451         static void atexitCallback()
00452         {
00453 #ifdef ATEXIT_FIXED
00454             needCallback = true;
00455 #else
00456             needCallback = false;
00457 #endif
00458             GracefulDelete();
00459         }
00460     };
00461     
00462     template <class T>
00463     atexit_pfn_t DeletableSingleton<T>::deleter = 0;
00464     
00465     template <class T>
00466     bool DeletableSingleton<T>::isDead = true;
00467     
00468     template <class T>
00469     bool DeletableSingleton<T>::needCallback = true;
00470 
00472     // class template Adapter
00473     // Helper for SingletonWithLongevity below
00475 
00476     namespace Private
00477     {
00478         template <class T>
00479         struct Adapter
00480         {
00481             void operator()(T*) { return pFun_(); }
00482             atexit_pfn_t pFun_;
00483         };
00484     }
00485 
00495     template <class T>
00496     class SingletonWithLongevity
00497     {
00498     public:
00499         static void ScheduleDestruction(T* pObj, atexit_pfn_t pFun)
00500         {
00501             Private::Adapter<T> adapter = { pFun };
00502             SetLongevity(pObj, GetLongevity(pObj), adapter);
00503         }
00504         
00505         static void OnDeadReference()
00506         { throw std::logic_error("Dead Reference Detected"); }
00507     };
00508 
00516     template <class T>
00517     struct NoDestroy
00518     {
00519         static void ScheduleDestruction(T*, atexit_pfn_t)
00520         {}
00521         
00522         static void OnDeadReference()
00523         {}
00524     };
00525     
00526 
00537     namespace LongevityLifetime
00538     {
00549         template <unsigned int Longevity, class T>
00550         class SingletonFixedLongevity
00551         {
00552         public:
00553             virtual ~SingletonFixedLongevity() {}
00554             
00555             static void ScheduleDestruction(T* pObj, atexit_pfn_t pFun)
00556             {
00557                 Private::Adapter<T> adapter = { pFun };
00558                 SetLongevity(pObj, Longevity , adapter);
00559             }
00560             
00561             static void OnDeadReference()
00562             { throw std::logic_error("Dead Reference Detected"); }
00563         };
00564 
00568         template <class T>
00569         struct DieLast  : SingletonFixedLongevity<0xFFFFFFFF ,T>
00570         {};
00571 
00575         template <class T>
00576         struct DieDirectlyBeforeLast  : SingletonFixedLongevity<0xFFFFFFFF-1 ,T>
00577         {};
00578 
00582         template <class T>
00583         struct DieFirst : SingletonFixedLongevity<0,T>
00584         {};
00585     
00586     }//namespace LongevityLifetime
00587 
00606     class FollowIntoDeath
00607     {
00608         template<class T>
00609         class Followers
00610         {
00611             typedef std::vector<atexit_pfn_t> Container;
00612             typedef typename Container::iterator iterator;
00613             static Container* followers_;
00614         
00615         public:
00616             static void Init()
00617             {
00618                 static bool done = false;
00619                 if(!done)
00620                 {
00621                     followers_ = new Container;
00622                     done = true;
00623                 }
00624             }
00625 
00626             static void AddFollower(atexit_pfn_t ae)
00627             {
00628                 Init();
00629                 followers_->push_back(ae);
00630             }
00631 
00632             static void DestroyFollowers()
00633             {
00634                 Init();
00635                 for(iterator it = followers_->begin();it != followers_->end();++it)
00636                     (*it)();    
00637                 delete followers_;
00638             }
00639         };
00640 
00641     public:
00642 
00646         template<template <class> class Lifetime>
00647         struct With
00648         {
00651             template<class Master>
00652             struct AsMasterLifetime
00653             {
00654                 static void ScheduleDestruction(Master* pObj, atexit_pfn_t pFun)
00655                 {
00656                     Followers<Master>::Init();
00657                     Lifetime<Master>::ScheduleDestruction(pObj, pFun);
00658 
00659                     // use same policy for the followers and force a new 
00660                     // template instantiation,  this adds a additional atexit entry
00661                     // does not work with SetLonlevity, but there you can control
00662                     // the lifetime with the GetLongevity function.
00663                     Lifetime<Followers<Master> >::ScheduleDestruction(0,Followers<Master>::DestroyFollowers);
00664                 }
00665 
00666                 static void OnDeadReference()
00667                 { 
00668                     throw std::logic_error("Dead Reference Detected"); 
00669                 }
00670             };
00671         };
00672 
00676         template<class Master>
00677         struct AfterMaster
00678         {
00681             template<class F>
00682             struct IsDestroyed
00683             {
00684                 static void ScheduleDestruction(F*, atexit_pfn_t pFun)
00685                 {
00686                     Followers<Master>::AddFollower(pFun);
00687                 }
00688       
00689                 static void OnDeadReference()
00690                 { 
00691                     throw std::logic_error("Dead Reference Detected"); 
00692                 }
00693             };
00694         };
00695     };
00696 
00697     template<class T>
00698     typename FollowIntoDeath::Followers<T>::Container* 
00699     FollowIntoDeath::Followers<T>::followers_ = 0;
00700     
00701     
00702     
00717     template
00718     <
00719         typename T,
00720         template <class> class CreationPolicy = CreateUsingNew,
00721         template <class> class LifetimePolicy = DefaultLifetime,
00722         template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
00723         class MutexPolicy = LOKI_DEFAULT_MUTEX
00724     >
00725     class SingletonHolder
00726     {
00727     public:
00728 
00730         typedef T ObjectType;
00731 
00733         static T& Instance();
00734         
00735     private:
00736         // Helpers
00737         static void MakeInstance();
00738         static void LOKI_C_CALLING_CONVENTION_QUALIFIER DestroySingleton();
00739         
00740         // Protection
00741         SingletonHolder();
00742         
00743         // Data
00744         typedef typename ThreadingModel<T*,MutexPolicy>::VolatileType PtrInstanceType;
00745         static PtrInstanceType pInstance_;
00746         static bool destroyed_;
00747     };
00748     
00750     // SingletonHolder's data
00752 
00753     template
00754     <
00755         class T,
00756         template <class> class C,
00757         template <class> class L,
00758         template <class, class> class M,
00759         class X
00760     >
00761     typename SingletonHolder<T, C, L, M, X>::PtrInstanceType
00762         SingletonHolder<T, C, L, M, X>::pInstance_;
00763 
00764     template
00765     <
00766         class T,
00767         template <class> class C,
00768         template <class> class L,
00769         template <class, class> class M,
00770         class X
00771     >
00772     bool SingletonHolder<T, C, L, M, X>::destroyed_;
00773 
00775     // SingletonHolder::Instance
00777 
00778     template
00779     <
00780         class T,
00781         template <class> class CreationPolicy,
00782         template <class> class LifetimePolicy,
00783         template <class, class> class ThreadingModel,
00784         class MutexPolicy
00785     >
00786     inline T& SingletonHolder<T, CreationPolicy, 
00787         LifetimePolicy, ThreadingModel, MutexPolicy>::Instance()
00788     {
00789         if (!pInstance_)
00790         {
00791             MakeInstance();
00792         }
00793         return *pInstance_;
00794     }
00795 
00797     // SingletonHolder::MakeInstance (helper for Instance)
00799 
00800     template
00801     <
00802         class T,
00803         template <class> class CreationPolicy,
00804         template <class> class LifetimePolicy,
00805         template <class, class> class ThreadingModel,
00806         class MutexPolicy
00807     >
00808     void SingletonHolder<T, CreationPolicy, 
00809         LifetimePolicy, ThreadingModel, MutexPolicy>::MakeInstance()
00810     {
00811         typename ThreadingModel<SingletonHolder,MutexPolicy>::Lock guard;
00812         (void)guard;
00813         
00814         if (!pInstance_)
00815         {
00816             if (destroyed_)
00817             {
00818                 destroyed_ = false;
00819                 LifetimePolicy<T>::OnDeadReference();
00820             }
00821             pInstance_ = CreationPolicy<T>::Create();
00822             LifetimePolicy<T>::ScheduleDestruction(pInstance_, 
00823                 &DestroySingleton);
00824         }
00825     }
00826 
00827     template
00828     <
00829         class T,
00830         template <class> class CreationPolicy,
00831         template <class> class L,
00832         template <class, class> class M,
00833         class X
00834     >
00835     void LOKI_C_CALLING_CONVENTION_QUALIFIER 
00836     SingletonHolder<T, CreationPolicy, L, M, X>::DestroySingleton()
00837     {
00838         assert(!destroyed_);
00839         CreationPolicy<T>::Destroy(pInstance_);
00840         pInstance_ = 0;
00841         destroyed_ = true;
00842     }
00843 
00844 
00858 
00859 #ifndef LOKI_SINGLETON_EXPORT
00860 #define LOKI_SINGLETON_EXPORT
00861 #endif
00862 
00863     template<class T>
00864     class LOKI_SINGLETON_EXPORT Singleton
00865     {
00866     public:
00867         static T& Instance();
00868     };
00869 
00870 } // namespace Loki
00871 
00872 
00876 
00877 #define LOKI_SINGLETON_INSTANCE_DEFINITION(SHOLDER)                     \
00878 namespace Loki                                                          \
00879 {                                                                        \
00880     template<>                                                          \
00881     SHOLDER::ObjectType&  Singleton<SHOLDER::ObjectType>::Instance()    \
00882     {                                                                   \
00883         return SHOLDER::Instance();                                     \
00884     }                                                                    \
00885 }
00886 
00887 
00888 #endif // end file guardian
00889 

Generated on Sun Feb 25 16:52:27 2007 for Loki by  doxygen 1.5.1-p1