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