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 <boost/noncopyable.hpp>
53 #include <boost/type_traits/remove_cv.hpp>
54 #include <boost/thread/mutex.hpp>
55 #endif
56 
57 #include <error/Exception.h>
58 #include <platform/Platform.h>
59 #include <platform/Typename.h>
60 
61 namespace mira {
62 
64 
66 namespace Private {
67 
77 class MIRA_BASE_EXPORT SingletonSharedLibraryHelper
78 {
79 public:
80 
81 #ifdef MIRA_WINDOWS
82  static void* getSharedLibrarySingleton(const std::type_info& type);
83  static void setSharedLibrarySingleton(const std::type_info& type,
84  void* singleton);
85 #else
86  static void* getSharedLibrarySingleton(const std::type_info& type)
87  {
88  return NULL;
89  }
90  static void setSharedLibrarySingleton(const std::type_info& type,
91  void* singleton)
92  {}
93 #endif
94 };
95 
97 typedef void (*atexit_lifetime_fn) (void);
98 
105 template <typename T,
106  template <class> class I,
107  template <class> class C,
108  template <class> class L,
109  class M>
110 struct SingletonTrait
111 {
112  // type of singleton class without const and volatile qualifiers
113  typedef typename boost::remove_cv<T>::type Type;
114  typedef I<SingletonTrait> InstantiationPolicy;
115  typedef C<Type> CreationPolicy;
116  typedef L<Type> LifetimePolicy;
117  typedef M LockPolicy;
118 };
119 
126 template <typename Trait>
127 class SingletonBase : public SingletonSharedLibraryHelper, boost::noncopyable
128 {
129 public:
130  typedef typename Trait::InstantiationPolicy InstantiationPolicy;
131  typedef typename Trait::CreationPolicy CreationPolicy;
132  typedef typename Trait::LifetimePolicy LifetimePolicy;
133  typedef typename Trait::LockPolicy LockPolicy;
134  typedef typename Trait::Type Type;
135  typedef typename LockPolicy::template Volatile<Type>::type* TypePtr;
136 
137 protected:
138 
139  static TypePtr sInstance;
140  static bool sDestroyed;
141 
142 };
143 
144 // the static member sInstance
145 template <typename Trait>
146 typename SingletonBase<Trait>::TypePtr SingletonBase<Trait>::sInstance = NULL;
147 
148 // the static member sDestroyed
149 template <typename Trait>
150 bool SingletonBase<Trait>::sDestroyed = false;
151 
152 } // namespace Private
154 
156 
157 MIRA_DEFINE_EXCEPTION(XSingleton, Exception)
158 
159 namespace singleton {
160 
162 // Creation policies
163 
173 template <typename T>
175  static T* create() { return new T; }
176  static void destroy(T* p) { delete p; }
177 };
178 
189 template <typename T>
190 struct CreateStatic {
191 
192 #ifdef _MSC_VER
193 # define MIRA_CREATESTATIC_ALIGN __declspec(align(16))
194 #else
195 # define MIRA_CREATESTATIC_ALIGN __attribute__((aligned(16)))
196 #endif
197 
198  static T* create() {
199  // create 16 byte aligned static memory block
200  static MIRA_CREATESTATIC_ALIGN char staticMemory[sizeof(T)];
201  return new(&staticMemory) T;
202  }
203  static void destroy(T* p) {
204  p->~T();
205  }
206 #undef MIRA_CREATESTATIC_ALIGN
207 };
208 
220 template <template <class> class Alloc>
221 struct CreateUsing {
222  template <typename T>
223  struct Allocator {
224  static Alloc<T> alloc;
225  static T* create() { return new (alloc.allocate(1)) T; }
226  static void destroy(T* p) {
227  p->~T();
228  alloc.deallocate(p,1);
229  }
230  };
231 };
232 
234 // Lifetime Policies
235 
242 template <typename T>
244 {
245  static void scheduleDestruction(T*, Private::atexit_lifetime_fn fun) {
246  std::atexit(fun);
247  }
248 };
249 
256 template <typename T>
258 {
259  static void scheduleDestruction(T*, Private::atexit_lifetime_fn fun) {}
260 };
261 
263 // Instantiation policies
264 
273 template <typename Trait>
274 class LazyInstantiation : public Private::SingletonBase<Trait>
275 {
276  typedef Private::SingletonBase<Trait> Base;
277 
278 public:
279  typedef typename Base::Type Type;
280 
281  static Type& instance() {
282  if(!Base::sInstance)
283  makeInstance();
284  return *((Type*)Base::sInstance);
285  }
286 
287 protected:
288 
289  static Type* makeInstance()
290  {
291  // according to the standard, the creation of static variables is thread-safe
292  static typename Base::LockPolicy::Mutex sMutex;
293 
294  // protect the instantiation of a new singleton object
295  typename Base::LockPolicy::Lock lock(sMutex);
296 
297  // together with the check in instance() this is the
298  // double-checked locking pattern which is safe, if sInstance is
299  // declared volatile
300  if(!Base::sInstance) {
301  if(Base::sDestroyed)
302  MIRA_THROW(XSingleton, "Singleton of class '"
303  << typeName<Type>() << "' was already destroyed!");
304 
305  Type* p = static_cast<Type*>(Base::getSharedLibrarySingleton(typeid(Type)));
306  if(!p) {
307  p = Base::CreationPolicy::create();
308  Base::LifetimePolicy::scheduleDestruction(p,&destroyInstance);
309  Base::setSharedLibrarySingleton(typeid(Type),p);
310  }
311  Base::sInstance = p;
312  }
313 
314  assert(Base::sInstance);
315  return (Type*)Base::sInstance;
316  }
317 
318  static void destroyInstance(void){
319  if (!Base::sDestroyed) {
320  Base::CreationPolicy::destroy((Type*)Base::sInstance);
321  Base::sInstance=NULL;
322  Base::sDestroyed=true;
323  }
324  }
325 };
326 
327 
338 template <typename Trait>
340 {
341  typedef LazyInstantiation<Trait> Base;
342 
343 public:
344  typedef typename Base::Type Type;
345 
346  static Type& instance() {
347  if(!sInstantiationHelper)
348  sInstantiationHelper = Base::makeInstance();
349 
350  assert(sInstantiationHelper);
351  return *sInstantiationHelper;
352  }
353 private:
354  // include this to provoke instantiation at pre-execution time
355  static void use(const Type*) {}
356  static Type* forceInstantiation() {
357  Type* inst = Base::makeInstance();
358  // refer to instance, causing it to be instantiated (and
359  // initialized at startup on working compilers)
360  use(sInstantiationHelper);
361  return inst;
362  }
363 
364  static Type* sInstantiationHelper;
365 };
366 template <typename Trait>
367 typename EagerInstantiation<Trait>::Type* EagerInstantiation<Trait>::sInstantiationHelper = EagerInstantiation<Trait>::forceInstantiation();
368 
369 
384 template <typename Trait>
385 class ExplicitInstantiation : public Private::SingletonBase<Trait>
386 {
387  typedef Private::SingletonBase<Trait> Base;
388 
389 public:
390  typedef typename Base::Type Type;
391 
393  if(Base::sInstance!=NULL || Base::getSharedLibrarySingleton(typeid(Type))!=NULL)
394  MIRA_THROW(XSingleton, "There should be just one object of '"
395  << typeName<Type>() << "', you tried to initialize another one!");
396  Base::sInstance = static_cast<Type*>(this);
397  Base::setSharedLibrarySingleton(typeid(Type), this);
398  Base::sDestroyed=false;
399  }
400 
404  {
405  // remove singleton instance
406  Base::sInstance = NULL;
407  Base::setSharedLibrarySingleton(typeid(Type), NULL);
408  Base::sDestroyed=true;
409  }
410 
411  static Type& instance()
412  {
413  if(Base::sInstance==NULL) {
414  Type* p = static_cast<Type*>(Base::getSharedLibrarySingleton(typeid(Type)));
415 
416  if(p==NULL)
417  MIRA_THROW(XSingleton, "No instance of the explicit singleton '"
418  << typeName<Type>() << "' created, "
419  "or instance was already destroyed. "
420  "You must create one object of this class before "
421  "you can start using it!");
422 
423  Base::sInstance = p;
424  }
425  return *((Type*)Base::sInstance);
426  }
427 };
428 
429 
431 // Lock Policies
432 
438 struct NoLock
439 {
440  typedef int Mutex; // use an int as dummy mutex instance
441  struct Lock {
442  Lock(int) {}
443  };
444  template <typename T>
445  struct Volatile {
446  typedef T type;
447  };
448 };
449 
458 struct MutexLock
459 {
460  typedef boost::mutex Mutex;
461  typedef boost::mutex::scoped_lock Lock;
462 
463  // adds volatile to T to make the double-checked locking pattern safe
464  template <typename T>
465  struct Volatile {
466  typedef volatile T type;
467  };
468 };
469 
470 } // namespace singleton
471 
473 
526 template <typename T,
527  template <class> class TInstantiationPolicy = singleton::LazyInstantiation,
528  template <class> class TCreationPolicy = singleton::CreateUsingNew,
529  template <class> class TLifetimePolicy = singleton::NormalLifetime,
530  class TLockPolicy = singleton::MutexLock>
531 class Singleton : public TInstantiationPolicy<Private::SingletonTrait<T,TInstantiationPolicy,TCreationPolicy,TLifetimePolicy,TLockPolicy>>
532 {
533  typedef TInstantiationPolicy<Private::SingletonTrait<T,TInstantiationPolicy,TCreationPolicy,TLifetimePolicy,TLockPolicy>> Base;
534 public:
535 
536  // type of singleton class T without const and volatile qualifiers
537  typedef typename Base::Type Type;
538 
544  static Type& instance() {
545  return Base::instance();
546  }
547 
552  static bool isDestroyed() {
553  return Base::sDestroyed;
554  }
555 
556 };
557 
563 template <typename T>
564 class LazySingleton : public Singleton<T, singleton::LazyInstantiation, singleton::CreateUsingNew> {};
565 
571 template <typename T>
572 class EagerSingleton : public Singleton<T, singleton::EagerInstantiation, singleton::CreateUsingNew> {};
573 
579 template <typename T>
580 class ExplicitSingleton : public Singleton<T, singleton::ExplicitInstantiation> {};
581 
587 template <typename T>
588 class LazySingletonNoLock : public Singleton<T, singleton::LazyInstantiation,
589  singleton::CreateUsingNew, singleton::NormalLifetime,
590  singleton::NoLock> {};
591 
597 template <typename T>
598 class EagerSingletonNoLock : public Singleton<T, singleton::EagerInstantiation,
599  singleton::CreateUsingNew, singleton::NormalLifetime,
600  singleton::NoLock> {};
601 
603 
604 } // namespace
605 
606 #endif
ExplicitInstantiation()
Definition: Singleton.h:392
#define MIRA_DEFINE_EXCEPTION(Ex, Base)
Macro for easily defining a new compatible exception class.
Definition: Exception.h:170
Provided for convenience.
Definition: Singleton.h:598
Definition: Singleton.h:445
Implementation of the CreationPolicy that is used by the Singleton template.
Definition: Singleton.h:174
static void destroy(T *p)
Definition: Singleton.h:203
Implementation of the LockPolicy that is used by the Singleton template.
Definition: Singleton.h:458
static Type & instance()
Returns a reference to the singleton instance.
Definition: Singleton.h:544
Implementation of the LifetimePolicy that is used by the Singleton template.
Definition: Singleton.h:243
specialize cv::DataType for our ImgPixel and inherit from cv::DataType<Vec>
Definition: IOService.h:67
static Type * makeInstance()
Definition: Singleton.h:289
static Type & instance()
Definition: Singleton.h:281
Implementation of the InstantiationPolicy that is used by the Singleton template. ...
Definition: Singleton.h:385
Implementation of the CreationPolicy that is used by the Singleton template.
Definition: Singleton.h:221
Definition: Singleton.h:223
boost::mutex Mutex
Definition: Singleton.h:460
Provided for convenience.
Definition: Singleton.h:572
static void destroy(T *p)
Definition: Singleton.h:176
Provided for convenience.
Definition: Singleton.h:564
Get compiler and platform independent typenames.
static bool isDestroyed()
Returns true, if the singleton was already destroyed.
Definition: Singleton.h:552
#define MIRA_THROW(ex, msg)
Macro for throwing an exception.
Definition: Exception.h:82
static void destroyInstance(void)
Definition: Singleton.h:318
static T * create()
Definition: Singleton.h:225
Base::Type Type
Definition: Singleton.h:390
static T * create()
Definition: Singleton.h:198
static Type & instance()
Definition: Singleton.h:346
Implementation of the InstantiationPolicy that is used by the Singleton template. ...
Definition: Singleton.h:339
Provided for convenience.
Definition: Singleton.h:588
A singleton template class that can be freely configured using policies that control the instantiatio...
Definition: Singleton.h:531
PropertyHint type(const std::string &t)
Sets the attribute "type" to the specified value.
Definition: PropertyHint.h:295
Definition: Singleton.h:441
Provided for convenience.
Definition: Singleton.h:580
Definition: Singleton.h:465
~ExplicitInstantiation()
Destroys and removes the shared singleton instance.
Definition: Singleton.h:403
static void scheduleDestruction(T *, Private::atexit_lifetime_fn fun)
Definition: Singleton.h:245
Implementation of the CreationPolicy that is used by the Singleton template.
Definition: Singleton.h:190
Lock(int)
Definition: Singleton.h:442
static void scheduleDestruction(T *, Private::atexit_lifetime_fn fun)
Definition: Singleton.h:259
volatile T type
Definition: Singleton.h:466
#define MIRA_CREATESTATIC_ALIGN
Definition: Singleton.h:195
static void destroy(T *p)
Definition: Singleton.h:226
Base::Type Type
Definition: Singleton.h:279
boost::mutex::scoped_lock Lock
Definition: Singleton.h:461
Base::Type Type
Definition: Singleton.h:344
Implementation of the InstantiationPolicy that is used by the Singleton template. ...
Definition: Singleton.h:274
static T * create()
Definition: Singleton.h:175
int Mutex
Definition: Singleton.h:440
Base::Type Type
Definition: Singleton.h:537
#define MIRA_BASE_EXPORT
This is required because on windows there is a macro defined called ERROR.
Definition: Platform.h:153
static Type & instance()
Definition: Singleton.h:411
Implementation of the LockPolicy that is used by the Singleton template.
Definition: Singleton.h:438
Implementation of the LifetimePolicy that is used by the Singleton template.
Definition: Singleton.h:257
Exception base class.
T type
Definition: Singleton.h:446
static Alloc< T > alloc
Definition: Singleton.h:224
Platform dependent defines and macros.