1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkSingleton_h
19 #define itkSingleton_h
20 
21 #include "itkMacro.h"
22 #include "itkSingletonMacro.h"
23 #include <map>
24 #include <functional>
25 
26 /** \brief A function which does nothing
27  *
28  * This function is to be used to mark parameters as unused to suppress
29  * compiler warning. It can be used when the parameter needs to be named
30  * (i.e. itkNotUsed cannot be used) but is not always used. It ensures
31  * that the parameter is not optimized out.
32  */
33 template <typename T>
Unused(const T &)34 inline void Unused( const T &) {};
35 
36 namespace itk
37 {
38 /** \class SingletonIndex
39  * \brief Implementation detail.
40  *
41  * \ingroup ITKCommon
42  */
43 
44 class ITKCommon_EXPORT SingletonIndex
45 {
46 public:
47   /** Standard class typedefs. */
48   typedef SingletonIndex Self;
49   typedef std::map<std::string, std::tuple<void*, std::function<void(void*)>, std::function<void(void)> > > SingletonData;
50 
51   // obtain a global registered in the singleton index under the
52   // globalName, if unknown then nullptr will be returned.
53   template<typename T>
GetGlobalInstance(const char * globalName)54   T *GetGlobalInstance( const char *globalName )
55     { return static_cast<T*>(this->GetGlobalInstancePrivate(globalName)); }
56 
57 
58   // returns true if the globalName has not been registered yet.
59   //
60   // It is assumed that the global will remain valid until the start
61   // of globals being destroyed.
62   template<typename T>
SetGlobalInstance(const char * globalName,T * global,std::function<void (void *)> func,std::function<void (void)> deleteFunc)63   bool SetGlobalInstance( const char * globalName, T * global, std::function<void(void*)> func, std::function<void(void)> deleteFunc)
64     { return this->SetGlobalInstancePrivate(globalName, global, func, deleteFunc);}
65 
66   /** Set/Get the pointer to GlobalSingleton.
67    * Note that SetGlobalSingleton is not concurrent thread safe. */
68   static Self* GetInstance();
69   static void SetInstance(Self *SingletonIndex);
70   ~SingletonIndex();
71 
72 private:
73 
74   // may return nullptr if string is not registered already
75   //
76   // access something like a std::map<std::string, void *> or
77   // registered globals, it may be possible to restrict the held
78   // classes to be derived from itk::LightObject, so dynamic cast can
79   // work, and could use some type of Holder<T> class for intrinsic types
80   void * GetGlobalInstancePrivate( const char *globalName );
81   // If globalName is already registered than false is return,
82   // otherwise global is added to the singleton index under globalName
83   bool SetGlobalInstancePrivate( const char * globalName, void * global, std::function<void(void*)> func, std::function<void(void)> deleteFunc);
84 
85   /** The static GlobalSingleton. This is initialized to nullptr as the first
86    * stage of static initialization. It is then populated on the first call to
87    * itk::Singleton::Modified() but it can be overridden with SetGlobalSingleton().
88    * */
89   SingletonData m_GlobalObjects;
90   static Self*  m_Instance;
91 //  static SingletonIndexPrivate * m_GlobalSingleton;
92 };
93 
94 
95 // A wrapper for a global variable registered in the singleton index.
96 template<typename T>
Singleton(const char * globalName,std::function<void (void *)> func,std::function<void (void)> deleteFunc)97 T* Singleton(const char *globalName, std::function<void(void*)> func, std::function<void(void)> deleteFunc)
98 {
99   static SingletonIndex * singletonIndex = SingletonIndex::GetInstance();
100   Unused(singletonIndex);
101   T* instance = SingletonIndex::GetInstance()->GetGlobalInstance<T>(globalName);
102   if( instance == nullptr )
103     {
104     instance = new T;
105     if (!SingletonIndex::GetInstance()->SetGlobalInstance<T>(globalName, instance, func, deleteFunc))
106       {
107       delete instance;
108       instance = nullptr;
109       }
110     }
111   return instance;
112 }
113 } // end namespace itk
114 
115 #endif
116