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

# Content
1 ////////////////////////////////////////////////////////////////////////////////
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_