MIRA
Singleton.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 by
3  * MetraLabs GmbH (MLAB), GERMANY
4  * and
5  * Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
6  * All rights reserved.
7  *
8  * Contact: info@mira-project.org
9  *
10  * Commercial Usage:
11  * Licensees holding valid commercial licenses may use this file in
12  * accordance with the commercial license agreement provided with the
13  * software or, alternatively, in accordance with the terms contained in
14  * a written agreement between you and MLAB or NICR.
15  *
16  * GNU General Public License Usage:
17  * Alternatively, this file may be used under the terms of the GNU
18  * General Public License version 3.0 as published by the Free Software
19  * Foundation and appearing in the file LICENSE.GPL3 included in the
20  * packaging of this file. Please review the following information to
21  * ensure the GNU General Public License version 3.0 requirements will be
22  * met: http://www.gnu.org/copyleft/gpl.html.
23  * Alternatively you may (at your option) use any later version of the GNU
24  * General Public License if such license has been publicly approved by
25  * MLAB and NICR (or its successors, if any).
26  *
27  * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
28  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
29  * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
30  * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
33  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
34  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
35  * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
36  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
37  */
38 
48 #ifndef _MIRA_SINGLETON_H_
49 #define _MIRA_SINGLETON_H_
50 
51 #ifndef Q_MOC_RUN
52 #include <type_traits>
53 #include <boost/thread/mutex.hpp>
54 #endif
55 
56 #include <error/Exception.h>
57 #include <platform/Platform.h>
58 #include <platform/Typename.h>
59 
60 namespace mira {
61 
63 
65 namespace Private {
66 
68 typedef void (*atexit_lifetime_fn) (void);
69 
76 template <typename T,
77  template <class> class I,
78  template <class> class C,
79  template <class> class L,
80  class M>
81 struct SingletonTrait
82 {
83  // type of singleton class without const and volatile qualifiers
84  typedef typename std::remove_cv<T>::type Type;
85  typedef I<SingletonTrait> InstantiationPolicy;
86  typedef C<Type> CreationPolicy;
87  typedef L<Type> LifetimePolicy;
88  typedef M LockPolicy;
89 };
90 
97 template <typename Trait>
98 class SingletonBase
99 {
100 public:
101  typedef typename Trait::InstantiationPolicy InstantiationPolicy;
102  typedef typename Trait::CreationPolicy CreationPolicy;
103  typedef typename Trait::LifetimePolicy LifetimePolicy;
104  typedef typename Trait::LockPolicy LockPolicy;
105  typedef typename Trait::Type Type;
106  typedef typename LockPolicy::template Volatile<Type>::type* TypePtr;
107 
108  SingletonBase() = default;
109  SingletonBase(const SingletonBase&) = delete;
110  SingletonBase& operator=(const SingletonBase&) = delete;
111 
112 protected:
113 
114  static TypePtr sInstance;
115  static bool sDestroyed;
116 
117 };
118 
119 // the static member sInstance
120 template <typename Trait>
121 typename SingletonBase<Trait>::TypePtr SingletonBase<Trait>::sInstance = NULL;
122 
123 // the static member sDestroyed
124 template <typename Trait>
125 bool SingletonBase<Trait>::sDestroyed = false;
126 
127 } // namespace Private
129 
131 
132 MIRA_DEFINE_EXCEPTION(XSingleton, Exception)
133 
134 namespace singleton {
135 
137 // Creation policies
138 
148 template <typename T>
150  static T* create() { return new T; }
151  static void destroy(T* p) { delete p; }
152 };
153 
164 template <typename T>
165 struct CreateStatic {
166 
167 #ifdef _MSC_VER
168 # define MIRA_CREATESTATIC_ALIGN __declspec(align(16))
169 #else
170 # define MIRA_CREATESTATIC_ALIGN __attribute__((aligned(16)))
171 #endif
172 
173  static T* create() {
174  // create 16 byte aligned static memory block
175  static MIRA_CREATESTATIC_ALIGN char staticMemory[sizeof(T)];
176  return new(&staticMemory) T;
177  }
178  static void destroy(T* p) {
179  p->~T();
180  }
181 #undef MIRA_CREATESTATIC_ALIGN
182 };
183 
195 template <template <class> class Alloc>
196 struct CreateUsing {
197  template <typename T>
198  struct Allocator {
199  static Alloc<T> alloc;
200  static T* create() { return new (alloc.allocate(1)) T; }
201  static void destroy(T* p) {
202  p->~T();
203  alloc.deallocate(p,1);
204  }
205  };
206 };
207 
209 // Lifetime Policies
210 
217 template <typename T>
219 {
220  static void scheduleDestruction(T*, Private::atexit_lifetime_fn fun) {
221  std::atexit(fun);
222  }
223 };
224 
231 template <typename T>
233 {
234  static void scheduleDestruction(T*, Private::atexit_lifetime_fn fun) {}
235 };
236 
238 // Instantiation policies
239 
248 template <typename Trait>
249 class LazyInstantiation : public Private::SingletonBase<Trait>
250 {
251  typedef Private::SingletonBase<Trait> Base;
252 
253 public:
254  typedef typename Base::Type Type;
255 
256  static Type& instance() {
257  if(!Base::sInstance)
258  makeInstance();
259  return *((Type*)Base::sInstance);
260  }
261 
262 protected:
263 
264  static Type* makeInstance()
265  {
266  // according to the standard, the creation of static variables is thread-safe
267  static typename Base::LockPolicy::Mutex sMutex;
268 
269  // protect the instantiation of a new singleton object
270  typename Base::LockPolicy::Lock lock(sMutex);
271 
272  // together with the check in instance() this is the
273  // double-checked locking pattern which is safe, if sInstance is
274  // declared volatile
275  if(!Base::sInstance) {
276  if(Base::sDestroyed)
277  MIRA_THROW(XSingleton, "Singleton of class '"
278  << typeName<Type>() << "' was already destroyed!");
279 
280  Type* p = Base::CreationPolicy::create();
281  Base::LifetimePolicy::scheduleDestruction(p,&destroyInstance);
282  Base::sInstance = p;
283  }
284 
285  assert(Base::sInstance);
286  return (Type*)Base::sInstance;
287  }
288 
289  static void destroyInstance(void){
290  if (!Base::sDestroyed) {
291  Base::CreationPolicy::destroy((Type*)Base::sInstance);
292  Base::sInstance=NULL;
293  Base::sDestroyed=true;
294  }
295  }
296 };
297 
298 
309 template <typename Trait>
311 {
312  typedef LazyInstantiation<Trait> Base;
313 
314 public:
315  typedef typename Base::Type Type;
316 
317  static Type& instance() {
318  if(!sInstantiationHelper)
319  sInstantiationHelper = Base::makeInstance();
320 
321  assert(sInstantiationHelper);
322  return *sInstantiationHelper;
323  }
324 private:
325  // include this to provoke instantiation at pre-execution time
326  static void use(const Type*) {}
327  static Type* forceInstantiation() {
328  Type* inst = Base::makeInstance();
329  // refer to instance, causing it to be instantiated (and
330  // initialized at startup on working compilers)
331  use(sInstantiationHelper);
332  return inst;
333  }
334 
335  static Type* sInstantiationHelper;
336 };
337 template <typename Trait>
338 typename EagerInstantiation<Trait>::Type* EagerInstantiation<Trait>::sInstantiationHelper = EagerInstantiation<Trait>::forceInstantiation();
339 
340 
355 template <typename Trait>
356 class ExplicitInstantiation : public Private::SingletonBase<Trait>
357 {
358  typedef Private::SingletonBase<Trait> Base;
359 
360 public:
361  typedef typename Base::Type Type;
362 
364  if(Base::sInstance!=NULL)
365  MIRA_THROW(XSingleton, "There should be just one object of '"
366  << typeName<Type>() << "', you tried to initialize another one!");
367  Base::sInstance = static_cast<Type*>(this);
368  Base::sDestroyed=false;
369  }
370 
374  {
375  // remove singleton instance
376  Base::sInstance = NULL;
377  Base::sDestroyed=true;
378  }
379 
380  static Type& instance()
381  {
382  if(Base::sInstance==NULL) {
383  MIRA_THROW(XSingleton, "No instance of the explicit singleton '"
384  << typeName<Type>() << "' created, "
385  "or instance was already destroyed. "
386  "You must create one object of this class before "
387  "you can start using it!");
388  }
389  return *((Type*)Base::sInstance);
390  }
391 };
392 
393 
395 // Lock Policies
396 
402 struct NoLock
403 {
404  typedef int Mutex; // use an int as dummy mutex instance
405  struct Lock {
406  Lock(int) {}
407  };
408  template <typename T>
409  struct Volatile {
410  typedef T type;
411  };
412 };
413 
422 struct MutexLock
423 {
424  typedef boost::mutex Mutex;
425  typedef boost::mutex::scoped_lock Lock;
426 
427  // adds volatile to T to make the double-checked locking pattern safe
428  template <typename T>
429  struct Volatile {
430  typedef volatile T type;
431  };
432 };
433 
434 } // namespace singleton
435 
437 
490 template <typename T,
491  template <class> class TInstantiationPolicy = singleton::LazyInstantiation,
492  template <class> class TCreationPolicy = singleton::CreateUsingNew,
493  template <class> class TLifetimePolicy = singleton::NormalLifetime,
494  class TLockPolicy = singleton::MutexLock>
495 class Singleton : public TInstantiationPolicy<Private::SingletonTrait<T,TInstantiationPolicy,TCreationPolicy,TLifetimePolicy,TLockPolicy>>
496 {
497  typedef TInstantiationPolicy<Private::SingletonTrait<T,TInstantiationPolicy,TCreationPolicy,TLifetimePolicy,TLockPolicy>> Base;
498 public:
499 
500  // type of singleton class T without const and volatile qualifiers
501  typedef typename Base::Type Type;
502 
508  static Type& instance() {
509  return Base::instance();
510  }
511 
516  static bool isDestroyed() {
517  return Base::sDestroyed;
518  }
519 
520 };
521 
527 template <typename T>
528 class LazySingleton : public Singleton<T, singleton::LazyInstantiation, singleton::CreateUsingNew> {};
529 
535 template <typename T>
536 class EagerSingleton : public Singleton<T, singleton::EagerInstantiation, singleton::CreateUsingNew> {};
537 
543 template <typename T>
544 class ExplicitSingleton : public Singleton<T, singleton::ExplicitInstantiation> {};
545 
551 template <typename T>
552 class LazySingletonNoLock : public Singleton<T, singleton::LazyInstantiation,
553  singleton::CreateUsingNew, singleton::NormalLifetime,
554  singleton::NoLock> {};
555 
561 template <typename T>
562 class EagerSingletonNoLock : public Singleton<T, singleton::EagerInstantiation,
563  singleton::CreateUsingNew, singleton::NormalLifetime,
564  singleton::NoLock> {};
565 
567 
568 } // namespace
569 
570 #endif
ExplicitInstantiation()
Definition: Singleton.h:363
#define MIRA_DEFINE_EXCEPTION(Ex, Base)
Macro for easily defining a new compatible exception class.
Definition: Exception.h:166
Provided for convenience.
Definition: Singleton.h:562
Definition: Singleton.h:409
Implementation of the CreationPolicy that is used by the Singleton template.
Definition: Singleton.h:149
static void destroy(T *p)
Definition: Singleton.h:178
Implementation of the LockPolicy that is used by the Singleton template.
Definition: Singleton.h:422
static Type & instance()
Returns a reference to the singleton instance.
Definition: Singleton.h:508
Implementation of the LifetimePolicy that is used by the Singleton template.
Definition: Singleton.h:218
specialize cv::DataType for our ImgPixel and inherit from cv::DataType<Vec>
Definition: IOService.h:67
static Type * makeInstance()
Definition: Singleton.h:264
static Type & instance()
Definition: Singleton.h:256
Implementation of the InstantiationPolicy that is used by the Singleton template. ...
Definition: Singleton.h:356
Implementation of the CreationPolicy that is used by the Singleton template.
Definition: Singleton.h:196
Definition: Singleton.h:198
boost::mutex Mutex
Definition: Singleton.h:424
Provided for convenience.
Definition: Singleton.h:536
static void destroy(T *p)
Definition: Singleton.h:151
Provided for convenience.
Definition: Singleton.h:528
Get compiler and platform independent typenames.
static bool isDestroyed()
Returns true, if the singleton was already destroyed.
Definition: Singleton.h:516
#define MIRA_THROW(ex, msg)
Macro for throwing an exception.
Definition: Exception.h:78
static void destroyInstance(void)
Definition: Singleton.h:289
static T * create()
Definition: Singleton.h:200
Base::Type Type
Definition: Singleton.h:361
static T * create()
Definition: Singleton.h:173
static Type & instance()
Definition: Singleton.h:317
Implementation of the InstantiationPolicy that is used by the Singleton template. ...
Definition: Singleton.h:310
Provided for convenience.
Definition: Singleton.h:552
A singleton template class that can be freely configured using policies that control the instantiatio...
Definition: Singleton.h:495
PropertyHint type(const std::string &t)
Sets the attribute "type" to the specified value.
Definition: PropertyHint.h:295
Definition: Singleton.h:405
Provided for convenience.
Definition: Singleton.h:544
Definition: Singleton.h:429
~ExplicitInstantiation()
Destroys and removes the shared singleton instance.
Definition: Singleton.h:373
static void scheduleDestruction(T *, Private::atexit_lifetime_fn fun)
Definition: Singleton.h:220
Implementation of the CreationPolicy that is used by the Singleton template.
Definition: Singleton.h:165
Lock(int)
Definition: Singleton.h:406
static void scheduleDestruction(T *, Private::atexit_lifetime_fn fun)
Definition: Singleton.h:234
volatile T type
Definition: Singleton.h:430
#define MIRA_CREATESTATIC_ALIGN
Definition: Singleton.h:170
static void destroy(T *p)
Definition: Singleton.h:201
Base::Type Type
Definition: Singleton.h:254
boost::mutex::scoped_lock Lock
Definition: Singleton.h:425
Base::Type Type
Definition: Singleton.h:315
Implementation of the InstantiationPolicy that is used by the Singleton template. ...
Definition: Singleton.h:249
static T * create()
Definition: Singleton.h:150
int Mutex
Definition: Singleton.h:404
Base::Type Type
Definition: Singleton.h:501
static Type & instance()
Definition: Singleton.h:380
Implementation of the LockPolicy that is used by the Singleton template.
Definition: Singleton.h:402
Implementation of the LifetimePolicy that is used by the Singleton template.
Definition: Singleton.h:232
Exception base class.
T type
Definition: Singleton.h:410
static Alloc< T > alloc
Definition: Singleton.h:199
Platform dependent defines and macros.