Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

base/Singleton

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)2001 by Andrei Alexandrescu
00003 
00004   This file is a derivative of a file from the Loki Library written by
00005   Andrei Alexandrescu.  It was distributed by him under the terms
00006   listed below (titled Loki Original Distribution Terms).
00007   In accordance with the terms, this distribution contains the copyright
00008   notice here and the copyright notice and permission notice
00009   in supporting documentation.  The terms do *not* require
00010   redistribution under those same terms.  This code is distributed
00011   to you under the terms of the GNU General Public License (GPL) 
00012   below.  The GPL does not require you to maintain the terms of
00013   the Loki Original Distribution Terms, but you are encouraged to do so.
00014 
00015   This program/file is free software; you can redistribute it and/or modify
00016   it under the terms of the GNU General Public License as published by
00017   the Free Software Foundation; either version 2 of the License, or
00018   (at your option) any later version.
00019   
00020   This program is distributed in the hope that it will be useful,
00021   but WITHOUT ANY WARRANTY; without even the implied warranty of
00022   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023   GNU General Public License for more details. (http://www.gnu.org)
00024   
00025   You should have received a copy of the GNU General Public License
00026   along with this program; if not, write to the Free Software
00027   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028   
00029  ****************************************************************************
00030   Loki Original Distribution Terms:
00031 
00032   The Loki Library
00033   Copyright (c) 2001 by Andrei Alexandrescu
00034   This code accompanies the book:
00035   Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design 
00036       Patterns Applied". Copyright (c) 2001. Addison-Wesley.
00037   Permission to use, copy, modify, distribute and sell this software for any 
00038       purpose is hereby granted without fee, provided that the above copyright 
00039       notice appear in all copies and that both that copyright notice and this 
00040       permission notice appear in supporting documentation.
00041   The author or Addison-Welsey Longman make no representations about the 
00042       suitability of this software for any purpose. It is provided "as is" 
00043       without express or implied warranty.
00044  ****************************************************************************
00045 
00046   $Id: Singleton 1029 2004-02-11 20:45:54Z jungd $
00047   $Revision: 1.1 $
00048   $Date: 2004-02-11 15:45:54 -0500 (Wed, 11 Feb 2004) $
00049   $Author: jungd $
00050  
00051 ****************************************************************************/
00052 
00053 // Last update: June 20, 2001
00054 
00055 #ifndef SINGLETON_INC_
00056 #define SINGLETON_INC_
00057 
00058 #include <base/Threads>
00059 #include <algorithm>
00060 #include <stdexcept>
00061 #include <cassert>
00062 #include <cstdlib>
00063 #include <new>
00064 
00065 namespace base
00066 {
00067     namespace Private
00068     {
00069 ////////////////////////////////////////////////////////////////////////////////
00070 // class LifetimeTracker
00071 // Helper class for SetLongevity
00072 ////////////////////////////////////////////////////////////////////////////////
00073 
00074         class LifetimeTracker
00075         {
00076         public:
00077             LifetimeTracker(unsigned int x) : longevity_(x) 
00078             {}
00079             
00080             virtual ~LifetimeTracker() = 0;
00081             
00082             static bool Compare(const LifetimeTracker* lhs,
00083                 const LifetimeTracker* rhs)
00084             {
00085                 return rhs->longevity_ > lhs->longevity_;
00086             }
00087             
00088         private:
00089             unsigned int longevity_;
00090         };
00091         
00092         // Definition required
00093         inline LifetimeTracker::~LifetimeTracker() {} 
00094         
00095         // Helper data
00096         typedef LifetimeTracker** TrackerArray;
00097         extern TrackerArray pTrackerArray;
00098         extern unsigned int elements;
00099 
00100         // Helper destroyer function
00101         template <typename T>
00102         struct Deleter
00103         {
00104             static void Delete(T* pObj)
00105             { delete pObj; }
00106         };
00107 
00108         // Concrete lifetime tracker for objects of type T
00109         template <typename T, typename Destroyer>
00110         class ConcreteLifetimeTracker : public LifetimeTracker
00111         {
00112         public:
00113             ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d)
00114                 : LifetimeTracker(longevity)
00115                 , pTracked_(p)
00116                 , destroyer_(d)
00117             {}
00118             
00119             ~ConcreteLifetimeTracker()
00120             { destroyer_(pTracked_); }
00121             
00122         private:
00123             T* pTracked_;
00124             Destroyer destroyer_;
00125         };
00126 
00127         void AtExitFn(); // declaration needed below
00128     
00129     } // namespace Private
00130 
00131 ////////////////////////////////////////////////////////////////////////////////
00132 // function template SetLongevity
00133 // Assigns an object a longevity; ensures ordered destructions of objects 
00134 //     registered thusly during the exit sequence of the application
00135 ////////////////////////////////////////////////////////////////////////////////
00136 
00137     template <typename T, typename Destroyer>
00138     void SetLongevity(T* pDynObject, unsigned int longevity,
00139         Destroyer d = Private::Deleter<T>::Delete)
00140     {
00141         using namespace Private;
00142         
00143         TrackerArray pNewArray = static_cast<TrackerArray>(
00144                 std::realloc(pTrackerArray, elements + 1));
00145         if (!pNewArray) throw std::bad_alloc();
00146         
00147         LifetimeTracker* p = new ConcreteLifetimeTracker<T, Destroyer>(
00148             pDynObject, longevity, d);
00149         
00150         // Delayed assignment for exception safety
00151         pTrackerArray = pNewArray;
00152         
00153         // Insert a pointer to the object into the queue
00154         TrackerArray pos = std::upper_bound(
00155             pTrackerArray, 
00156             pTrackerArray + elements, 
00157             p, 
00158             LifetimeTracker::Compare);
00159         std::copy_backward(
00160             pos, 
00161             pTrackerArray + elements,
00162             pTrackerArray + elements + 1);
00163         *pos = p;
00164         ++elements;
00165         
00166         // Register a call to AtExitFn
00167         std::atexit(Private::AtExitFn);
00168     }
00169 
00170 ////////////////////////////////////////////////////////////////////////////////
00171 // class template CreateUsingNew
00172 // Implementation of the CreationPolicy used by SingletonHolder
00173 // Creates objects using a straight call to the new operator 
00174 ////////////////////////////////////////////////////////////////////////////////
00175 
00176     template <class T> struct CreateUsingNew
00177     {
00178         static T* Create()
00179         { return new T; }
00180         
00181         static void Destroy(T* p)
00182         { delete p; }
00183     };
00184     
00185 ////////////////////////////////////////////////////////////////////////////////
00186 // class template CreateUsingNew
00187 // Implementation of the CreationPolicy used by SingletonHolder
00188 // Creates objects using a call to std::malloc, followed by a call to the 
00189 //     placement new operator
00190 ////////////////////////////////////////////////////////////////////////////////
00191 
00192     template <class T> struct CreateUsingMalloc
00193     {
00194         static T* Create()
00195         {
00196             void* p = std::malloc(sizeof(T));
00197             if (!p) return 0;
00198             return new(p) T;
00199         }
00200         
00201         static void Destroy(T* p)
00202         {
00203             p->~T();
00204             std::free(p);
00205         }
00206     };
00207     
00208 ////////////////////////////////////////////////////////////////////////////////
00209 // class template CreateStatic
00210 // Implementation of the CreationPolicy used by SingletonHolder
00211 // Creates an object in static memory
00212 // Implementation is slightly nonportable because it uses the MaxAlign trick 
00213 //     (an union of all types to ensure proper memory alignment). This trick is 
00214 //     nonportable in theory but highly portable in practice.
00215 ////////////////////////////////////////////////////////////////////////////////
00216 
00217     template <class T> struct CreateStatic
00218     {
00219         union MaxAlign
00220         {
00221             char t_[sizeof(T)];
00222             short int shortInt_;
00223             int int_;
00224             long int longInt_;
00225             float float_;
00226             double double_;
00227             long double longDouble_;
00228             struct Test;
00229             int Test::* pMember_;
00230             int (Test::*pMemberFn_)(int);
00231         };
00232         
00233         static T* Create()
00234         {
00235             static MaxAlign staticMemory_;
00236             return new(&staticMemory_) T;
00237         }
00238         
00239         static void Destroy(T* p)
00240         {
00241             p->~T();
00242         }
00243     };
00244     
00245 ////////////////////////////////////////////////////////////////////////////////
00246 // class template DefaultLifetime
00247 // Implementation of the LifetimePolicy used by SingletonHolder
00248 // Schedules an object's destruction as per C++ rules
00249 // Forwards to std::atexit
00250 ////////////////////////////////////////////////////////////////////////////////
00251 
00252     template <class T>
00253     struct DefaultLifetime
00254     {
00255         static void ScheduleDestruction(T*, void (*pFun)())
00256         { std::atexit(pFun); }
00257         
00258         static void OnDeadReference()
00259         { throw std::logic_error("Dead Reference Detected"); }
00260     };
00261 
00262 ////////////////////////////////////////////////////////////////////////////////
00263 // class template PhoenixSingleton
00264 // Implementation of the LifetimePolicy used by SingletonHolder
00265 // Schedules an object's destruction as per C++ rules, and it allows object 
00266 //    recreation by not throwing an exception from OnDeadReference
00267 ////////////////////////////////////////////////////////////////////////////////
00268 
00269     template <class T>
00270     class PhoenixSingleton
00271     {
00272     public:
00273         static void ScheduleDestruction(T*, void (*pFun)())
00274         {
00275 #ifndef ATEXIT_FIXED
00276             if (!destroyedOnce_)
00277 #endif
00278                 std::atexit(pFun);
00279         }
00280         
00281         static void OnDeadReference()
00282         {
00283 #ifndef ATEXIT_FIXED
00284             destroyedOnce_ = true;
00285 #endif
00286         }
00287         
00288     private:
00289 #ifndef ATEXIT_FIXED
00290         static bool destroyedOnce_;
00291 #endif
00292     };
00293     
00294 #ifndef ATEXIT_FIXED
00295     template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false;
00296 #endif
00297         
00298 ////////////////////////////////////////////////////////////////////////////////
00299 // class template Adapter
00300 // Helper for SingletonWithLongevity below
00301 ////////////////////////////////////////////////////////////////////////////////
00302 
00303     namespace Private
00304     {
00305         template <class T>
00306         struct Adapter
00307         {
00308             void operator()(T*) { return pFun_(); }
00309             void (*pFun_)();
00310         };
00311     }
00312 
00313 ////////////////////////////////////////////////////////////////////////////////
00314 // class template SingletonWithLongevity
00315 // Implementation of the LifetimePolicy used by SingletonHolder
00316 // Schedules an object's destruction in order of their longevities
00317 // Assumes a visible function GetLongevity(T*) that returns the longevity of the
00318 //     object
00319 ////////////////////////////////////////////////////////////////////////////////
00320 
00321     template <class T>
00322     class SingletonWithLongevity
00323     {
00324     public:
00325         static void ScheduleDestruction(T* pObj, void (*pFun)())
00326         {
00327             Private::Adapter<T> adapter = { pFun };
00328             SetLongevity(pObj, GetLongevity(pObj), adapter);
00329         }
00330         
00331         static void OnDeadReference()
00332         { throw std::logic_error("Dead Reference Detected"); }
00333     };
00334 
00335 ////////////////////////////////////////////////////////////////////////////////
00336 // class template NoDestroy
00337 // Implementation of the LifetimePolicy used by SingletonHolder
00338 // Never destroys the object
00339 ////////////////////////////////////////////////////////////////////////////////
00340 
00341     template <class T>
00342     struct NoDestroy
00343     {
00344         static void ScheduleDestruction(T*, void (*)())
00345         {}
00346         
00347         static void OnDeadReference()
00348         {}
00349     };
00350 
00351 ////////////////////////////////////////////////////////////////////////////////
00352 // class template SingletonHolder
00353 // Provides Singleton amenities for a type T
00354 // To protect that type from spurious instantiations, you have to protect it
00355 //     yourself.
00356 ////////////////////////////////////////////////////////////////////////////////
00357 
00358     template
00359     <
00360         typename T,
00361         template <class> class CreationPolicy = CreateUsingNew,
00362         template <class> class LifetimePolicy = DefaultLifetime,
00363         template <class> class ThreadingModel = SingleThreaded
00364     >
00365     class SingletonHolder
00366     {
00367     public:
00368         static T& Instance();
00369         
00370     private:
00371         // Helpers
00372         static void MakeInstance();
00373         static void DestroySingleton();
00374         
00375         // Protection
00376         SingletonHolder();
00377         
00378         // Data
00379         typedef typename ThreadingModel<T*>::VolatileType PtrInstanceType;
00380         static PtrInstanceType pInstance_;
00381         static bool destroyed_;
00382     };
00383     
00384 ////////////////////////////////////////////////////////////////////////////////
00385 // SingletonHolder's data
00386 ////////////////////////////////////////////////////////////////////////////////
00387 
00388     template
00389     <
00390         class T,
00391         template <class> class C,
00392         template <class> class L,
00393         template <class> class M
00394     >
00395     typename SingletonHolder<T, C, L, M>::PtrInstanceType
00396         SingletonHolder<T, C, L, M>::pInstance_;
00397 
00398     template
00399     <
00400         class T,
00401         template <class> class C,
00402         template <class> class L,
00403         template <class> class M
00404     >
00405     bool SingletonHolder<T, C, L, M>::destroyed_;
00406 
00407 ////////////////////////////////////////////////////////////////////////////////
00408 // SingletonHolder::Instance
00409 ////////////////////////////////////////////////////////////////////////////////
00410 
00411     template
00412     <
00413         class T,
00414         template <class> class CreationPolicy,
00415         template <class> class LifetimePolicy,
00416         template <class> class ThreadingModel
00417     >
00418     inline T& SingletonHolder<T, CreationPolicy, 
00419         LifetimePolicy, ThreadingModel>::Instance()
00420     {
00421         if (!pInstance_)
00422         {
00423             MakeInstance();
00424         }
00425         return *pInstance_;
00426     }
00427 
00428 ////////////////////////////////////////////////////////////////////////////////
00429 // SingletonHolder::MakeInstance (helper for Instance)
00430 ////////////////////////////////////////////////////////////////////////////////
00431 
00432     template
00433     <
00434         class T,
00435         template <class> class CreationPolicy,
00436         template <class> class LifetimePolicy,
00437         template <class> class ThreadingModel
00438     >
00439     void SingletonHolder<T, CreationPolicy, 
00440         LifetimePolicy, ThreadingModel>::MakeInstance()
00441     {
00442         typename ThreadingModel<T>::Lock guard;
00443         (void)guard;
00444         
00445         if (!pInstance_)
00446         {
00447             if (destroyed_)
00448             {
00449                 LifetimePolicy<T>::OnDeadReference();
00450                 destroyed_ = false;
00451             }
00452             pInstance_ = CreationPolicy<T>::Create();
00453             LifetimePolicy<T>::ScheduleDestruction(pInstance_, 
00454                 &DestroySingleton);
00455         }
00456     }
00457 
00458     template
00459     <
00460         class T,
00461         template <class> class CreationPolicy,
00462         template <class> class L,
00463         template <class> class M
00464     >
00465     void SingletonHolder<T, CreationPolicy, L, M>::DestroySingleton()
00466     {
00467         assert(!destroyed_);
00468         CreationPolicy<T>::Destroy(pInstance_);
00469         pInstance_ = 0;
00470         destroyed_ = true;
00471     }
00472 } // namespace base
00473 
00474 ////////////////////////////////////////////////////////////////////////////////
00475 // Change log:
00476 // May 21, 2001: Correct the volatile qualifier - credit due to Darin Adler
00477 // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
00478 // Feb 25, 2002: David Jung: integrated into larger project - changed to 
00479 //                namespace base and changed header comments to reflect GPL
00480 //                distribution
00481 ////////////////////////////////////////////////////////////////////////////////
00482 
00483 #endif // SINGLETON_INC_

Generated on Thu Jul 29 15:56:14 2004 for OpenSim by doxygen 1.3.6