ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/REPOS_ERICCA/util/Loki/Loki/Singleton.h
Revision: 4
Committed: Tue Jun 12 19:51:29 2007 UTC (18 years, 2 months ago)
Content type: text/plain
File size: 15018 byte(s)
Log Message:

File Contents

# User Rev Content
1 4 ////////////////////////////////////////////////////////////////////////////////
2     // The Loki Library
3     // Copyright (c) 2001 by Andrei Alexandrescu
4     // This code accompanies the book:
5     // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
6     // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
7     // Permission to use, copy, modify, distribute and sell this software for any
8     // purpose is hereby granted without fee, provided that the above copyright
9     // notice appear in all copies and that both that copyright notice and this
10     // permission notice appear in supporting documentation.
11     // The author or Addison-Wesley Longman make no representations about the
12     // suitability of this software for any purpose. It is provided "as is"
13     // without express or implied warranty.
14     ////////////////////////////////////////////////////////////////////////////////
15    
16     #ifndef SINGLETON_INC_
17     #define SINGLETON_INC_
18    
19     #include "Threads.h"
20     #include <algorithm>
21     #include <stdexcept>
22     #include <cassert>
23     #include <cstdlib>
24     #include <new>
25    
26     namespace Loki
27     {
28     namespace Private
29     {
30     ////////////////////////////////////////////////////////////////////////////////
31     // class LifetimeTracker
32     // Helper class for SetLongevity
33     ////////////////////////////////////////////////////////////////////////////////
34    
35     class LifetimeTracker
36     {
37     public:
38     LifetimeTracker(unsigned int x) : longevity_(x)
39     {}
40    
41     virtual ~LifetimeTracker() = 0;
42    
43     static bool Compare(const LifetimeTracker* lhs,
44     const LifetimeTracker* rhs)
45     {
46     return lhs->longevity_ > rhs->longevity_;
47     }
48    
49     private:
50     unsigned int longevity_;
51     };
52    
53     // Definition required
54     inline LifetimeTracker::~LifetimeTracker() {}
55    
56     // Helper data
57     typedef LifetimeTracker** TrackerArray;
58     extern TrackerArray pTrackerArray;
59     extern unsigned int elements;
60    
61     // Helper destroyer function
62     template <typename T>
63     struct Deleter
64     {
65     static void Delete(T* pObj)
66     { delete pObj; }
67     };
68    
69     // Concrete lifetime tracker for objects of type T
70     template <typename T, typename Destroyer>
71     class ConcreteLifetimeTracker : public LifetimeTracker
72     {
73     public:
74     ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d)
75     : LifetimeTracker(longevity)
76     , pTracked_(p)
77     , destroyer_(d)
78     {}
79    
80     ~ConcreteLifetimeTracker()
81     { destroyer_(pTracked_); }
82    
83     private:
84     T* pTracked_;
85     Destroyer destroyer_;
86     };
87    
88     void AtExitFn(); // declaration needed below
89    
90     } // namespace Private
91    
92     ////////////////////////////////////////////////////////////////////////////////
93     // function template SetLongevity
94     // Assigns an object a longevity; ensures ordered destructions of objects
95     // registered thusly during the exit sequence of the application
96     ////////////////////////////////////////////////////////////////////////////////
97    
98     template <typename T, typename Destroyer>
99     void SetLongevity(T* pDynObject, unsigned int longevity,
100     Destroyer d = Private::Deleter<T>::Delete)
101     {
102     using namespace Private;
103    
104     TrackerArray pNewArray = static_cast<TrackerArray>(
105     std::realloc(pTrackerArray,
106     sizeof(*pTrackerArray) * (elements + 1)));
107     if (!pNewArray) throw std::bad_alloc();
108    
109     // Delayed assignment for exception safety
110     pTrackerArray = pNewArray;
111    
112     LifetimeTracker* p = new ConcreteLifetimeTracker<T, Destroyer>(
113     pDynObject, longevity, d);
114    
115     // Insert a pointer to the object into the queue
116     TrackerArray pos = std::upper_bound(
117     pTrackerArray,
118     pTrackerArray + elements,
119     p,
120     LifetimeTracker::Compare);
121     std::copy_backward(
122     pos,
123     pTrackerArray + elements,
124     pTrackerArray + elements + 1);
125     *pos = p;
126     ++elements;
127    
128     // Register a call to AtExitFn
129     std::atexit(Private::AtExitFn);
130     }
131    
132     ////////////////////////////////////////////////////////////////////////////////
133     // class template CreateUsingNew
134     // Implementation of the CreationPolicy used by SingletonHolder
135     // Creates objects using a straight call to the new operator
136     ////////////////////////////////////////////////////////////////////////////////
137    
138     template <class T> struct CreateUsingNew
139     {
140     static T* Create()
141     { return new T; }
142    
143     static void Destroy(T* p)
144     { delete p; }
145     };
146    
147     ////////////////////////////////////////////////////////////////////////////////
148     // class template CreateUsingNew
149     // Implementation of the CreationPolicy used by SingletonHolder
150     // Creates objects using a call to std::malloc, followed by a call to the
151     // placement new operator
152     ////////////////////////////////////////////////////////////////////////////////
153    
154     template <class T> struct CreateUsingMalloc
155     {
156     static T* Create()
157     {
158     void* p = std::malloc(sizeof(T));
159     if (!p) return 0;
160     return new(p) T;
161     }
162    
163     static void Destroy(T* p)
164     {
165     p->~T();
166     std::free(p);
167     }
168     };
169    
170     ////////////////////////////////////////////////////////////////////////////////
171     // class template CreateStatic
172     // Implementation of the CreationPolicy used by SingletonHolder
173     // Creates an object in static memory
174     // Implementation is slightly nonportable because it uses the MaxAlign trick
175     // (an union of all types to ensure proper memory alignment). This trick is
176     // nonportable in theory but highly portable in practice.
177     ////////////////////////////////////////////////////////////////////////////////
178    
179     template <class T> struct CreateStatic
180     {
181     #if defined(_MSC_VER) && _MSC_VER >= 1300
182     #pragma warning( push )
183     // alignment of a member was sensitive to packing
184     #pragma warning( disable : 4121 )
185     #endif // _MSC_VER
186     union MaxAlign
187     {
188     char t_[sizeof(T)];
189     short int shortInt_;
190     int int_;
191     long int longInt_;
192     float float_;
193     double double_;
194     long double longDouble_;
195     struct Test;
196     int Test::* pMember_;
197     int (Test::*pMemberFn_)(int);
198     };
199     #if defined(_MSC_VER) && _MSC_VER >= 1300
200     #pragma warning( pop )
201     #endif // _MSC_VER
202    
203     static T* Create()
204     {
205     static MaxAlign staticMemory_;
206     return new(&staticMemory_) T;
207     }
208    
209     static void Destroy(T* p)
210     {
211     p->~T();
212     }
213     };
214    
215     ////////////////////////////////////////////////////////////////////////////////
216     // class template DefaultLifetime
217     // Implementation of the LifetimePolicy used by SingletonHolder
218     // Schedules an object's destruction as per C++ rules
219     // Forwards to std::atexit
220     ////////////////////////////////////////////////////////////////////////////////
221    
222     template <class T>
223     struct DefaultLifetime
224     {
225     static void ScheduleDestruction(T*, void (*pFun)())
226     { std::atexit(pFun); }
227    
228     static void OnDeadReference()
229     { throw std::logic_error("Dead Reference Detected"); }
230     };
231    
232     ////////////////////////////////////////////////////////////////////////////////
233     // class template PhoenixSingleton
234     // Implementation of the LifetimePolicy used by SingletonHolder
235     // Schedules an object's destruction as per C++ rules, and it allows object
236     // recreation by not throwing an exception from OnDeadReference
237     ////////////////////////////////////////////////////////////////////////////////
238    
239     template <class T>
240     class PhoenixSingleton
241     {
242     public:
243     static void ScheduleDestruction(T*, void (*pFun)())
244     {
245     #ifndef ATEXIT_FIXED
246     if (!destroyedOnce_)
247     #endif
248     std::atexit(pFun);
249     }
250    
251     static void OnDeadReference()
252     {
253     #ifndef ATEXIT_FIXED
254     destroyedOnce_ = true;
255     #endif
256     }
257    
258     private:
259     #ifndef ATEXIT_FIXED
260     static bool destroyedOnce_;
261     #endif
262     };
263    
264     #ifndef ATEXIT_FIXED
265     template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false;
266     #endif
267    
268     ////////////////////////////////////////////////////////////////////////////////
269     // class template Adapter
270     // Helper for SingletonWithLongevity below
271     ////////////////////////////////////////////////////////////////////////////////
272    
273     namespace Private
274     {
275     template <class T>
276     struct Adapter
277     {
278     void operator()(T*) { return pFun_(); }
279     void (*pFun_)();
280     };
281     }
282    
283     ////////////////////////////////////////////////////////////////////////////////
284     // class template SingletonWithLongevity
285     // Implementation of the LifetimePolicy used by SingletonHolder
286     // Schedules an object's destruction in order of their longevities
287     // Assumes a visible function GetLongevity(T*) that returns the longevity of the
288     // object
289     ////////////////////////////////////////////////////////////////////////////////
290    
291     template <class T>
292     class SingletonWithLongevity
293     {
294     public:
295     static void ScheduleDestruction(T* pObj, void (*pFun)())
296     {
297     Private::Adapter<T> adapter = { pFun };
298     SetLongevity(pObj, GetLongevity(pObj), adapter);
299     }
300    
301     static void OnDeadReference()
302     { throw std::logic_error("Dead Reference Detected"); }
303     };
304    
305     ////////////////////////////////////////////////////////////////////////////////
306     // class template NoDestroy
307     // Implementation of the LifetimePolicy used by SingletonHolder
308     // Never destroys the object
309     ////////////////////////////////////////////////////////////////////////////////
310    
311     template <class T>
312     struct NoDestroy
313     {
314     static void ScheduleDestruction(T*, void (*)())
315     {}
316    
317     static void OnDeadReference()
318     {}
319     };
320    
321     ////////////////////////////////////////////////////////////////////////////////
322     // class template SingletonHolder
323     // Provides Singleton amenities for a type T
324     // To protect that type from spurious instantiations, you have to protect it
325     // yourself.
326     ////////////////////////////////////////////////////////////////////////////////
327    
328     template
329     <
330     typename T,
331     template <class> class CreationPolicy = CreateUsingNew,
332     template <class> class LifetimePolicy = DefaultLifetime,
333     template <class> class ThreadingModel = SingleThreaded
334     >
335     class SingletonHolder
336     {
337     public:
338     static T& Instance();
339    
340     private:
341     // Helpers
342     static void MakeInstance();
343     static void DestroySingleton();
344    
345     // Protection
346     SingletonHolder();
347    
348     // Data
349     typedef typename ThreadingModel<T*>::VolatileType PtrInstanceType;
350     static PtrInstanceType pInstance_;
351     static bool destroyed_;
352     };
353    
354     ////////////////////////////////////////////////////////////////////////////////
355     // SingletonHolder's data
356     ////////////////////////////////////////////////////////////////////////////////
357    
358     template
359     <
360     class T,
361     template <class> class C,
362     template <class> class L,
363     template <class> class M
364     >
365     typename SingletonHolder<T, C, L, M>::PtrInstanceType
366     SingletonHolder<T, C, L, M>::pInstance_;
367    
368     template
369     <
370     class T,
371     template <class> class C,
372     template <class> class L,
373     template <class> class M
374     >
375     bool SingletonHolder<T, C, L, M>::destroyed_;
376    
377     ////////////////////////////////////////////////////////////////////////////////
378     // SingletonHolder::Instance
379     ////////////////////////////////////////////////////////////////////////////////
380    
381     template
382     <
383     class T,
384     template <class> class CreationPolicy,
385     template <class> class LifetimePolicy,
386     template <class> class ThreadingModel
387     >
388     inline T& SingletonHolder<T, CreationPolicy,
389     LifetimePolicy, ThreadingModel>::Instance()
390     {
391     if (!pInstance_)
392     {
393     MakeInstance();
394     }
395     return *pInstance_;
396     }
397    
398     ////////////////////////////////////////////////////////////////////////////////
399     // SingletonHolder::MakeInstance (helper for Instance)
400     ////////////////////////////////////////////////////////////////////////////////
401    
402     template
403     <
404     class T,
405     template <class> class CreationPolicy,
406     template <class> class LifetimePolicy,
407     template <class> class ThreadingModel
408     >
409     void SingletonHolder<T, CreationPolicy,
410     LifetimePolicy, ThreadingModel>::MakeInstance()
411     {
412     typename ThreadingModel<T>::Lock guard;
413     (void)guard;
414    
415     if (!pInstance_)
416     {
417     if (destroyed_)
418     {
419     LifetimePolicy<T>::OnDeadReference();
420     destroyed_ = false;
421     }
422     pInstance_ = CreationPolicy<T>::Create();
423     LifetimePolicy<T>::ScheduleDestruction(pInstance_,
424     &DestroySingleton);
425     }
426     }
427    
428     template
429     <
430     class T,
431     template <class> class CreationPolicy,
432     template <class> class L,
433     template <class> class M
434     >
435     void SingletonHolder<T, CreationPolicy, L, M>::DestroySingleton()
436     {
437     assert(!destroyed_);
438     CreationPolicy<T>::Destroy(pInstance_);
439     pInstance_ = 0;
440     destroyed_ = true;
441     }
442     } // namespace Loki
443    
444     ////////////////////////////////////////////////////////////////////////////////
445     // Change log:
446     // May 21, 2001: Correct the volatile qualifier - credit due to Darin Adler
447     // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
448     // January 08, 2002: Fixed bug in call to realloc - credit due to Nigel Gent and
449     // Eike Petersen
450     // March 08, 2002: moved the assignment to pTrackerArray in SetLongevity to fix
451     // exception safety issue. Credit due to Kari Hoijarvi
452     // May 09, 2002: Fixed bug in Compare that caused longevities to act backwards.
453     // Credit due to Scott McDonald.
454     ////////////////////////////////////////////////////////////////////////////////
455    
456     #endif // SINGLETON_INC_