/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkSingleton_h #define itkSingleton_h #include "itkMacro.h" #include "itkSingletonMacro.h" #include #include #ifndef ITK_FUTURE_LEGACY_REMOVE /** \brief A function which does nothing * \deprecated Preferably use the C++ `[[maybe_unused]]` attribute instead! * * This function is to be used to mark parameters as unused to suppress * compiler warning. It can be used when the parameter needs to be named * (i.e. itkNotUsed cannot be used) but is not always used. */ template [[deprecated("Preferably use the C++ `[[maybe_unused]]` attribute instead!")]] inline void Unused(const T &){}; #endif namespace itk { /** \class SingletonIndex * \brief Implementation detail. * * \ingroup ITKCommon */ class ITKCommon_EXPORT SingletonIndex { public: /** Standard class types. */ using Self = SingletonIndex; #ifndef ITK_LEGACY_REMOVE using SingletonData [[deprecated("The internal representation of the singleton data is private, and may not " "correspond with SingletonData anymore.")]] = std::map, std::function>>; #endif // obtain a global registered in the singleton index under the // globalName, if unknown then nullptr will be returned. template T * GetGlobalInstance(const char * globalName) { return static_cast(this->GetGlobalInstancePrivate(globalName)); } // It is assumed that the global will remain valid until the start // of globals being destroyed. template void SetGlobalInstance(const char * globalName, T * global, std::function deleteFunc) { this->SetGlobalInstancePrivate(globalName, GlobalObject{ global, std::move(deleteFunc) }); } #ifndef ITK_FUTURE_LEGACY_REMOVE template [[deprecated("Prefer calling the SetGlobalInstance(globalName, global, deleteFunc) overload (without the unused func " "parameter)!")]] bool SetGlobalInstance(const char * globalName, T * global, std::function itkNotUsed(func), std::function deleteFunc) { this->SetGlobalInstance(globalName, global, std::move(deleteFunc)); // Just returns true for backward compatibility (legacy only). return true; } #endif /** Set/Get the pointer to GlobalSingleton. * Note that SetGlobalSingleton is not concurrent thread safe. */ static Self * GetInstance(); static void SetInstance(Self * instance); ~SingletonIndex(); private: // Internal struct to store the instance pointer and the delete function object of a global object. struct GlobalObject { void * Instance{}; std::function DeleteFunc{}; }; // may return nullptr if string is not registered already // // access something like a std::map or // registered globals, it may be possible to restrict the held // classes to be derived from itk::LightObject, so dynamic cast can // work, and could use some type of Holder class for intrinsic types void * GetGlobalInstancePrivate(const char * globalName); // global is added or set to the singleton index under globalName void SetGlobalInstancePrivate(const char * globalName, GlobalObject globalObject); /** The static GlobalSingleton. This is initialized to nullptr as the first * stage of static initialization. It is then populated on the first call to * itk::Singleton::Modified() but it can be overridden with SetGlobalSingleton(). * */ std::map m_GlobalObjects; static Self * m_Instance; // static SingletonIndexPrivate * m_GlobalSingleton; }; // A wrapper for a global variable registered in the singleton index. template T * Singleton(const char * globalName, std::function deleteFunc) { [[maybe_unused]] static SingletonIndex * singletonIndex = SingletonIndex::GetInstance(); T * instance = SingletonIndex::GetInstance()->GetGlobalInstance(globalName); if (instance == nullptr) { instance = new T; SingletonIndex::GetInstance()->SetGlobalInstance(globalName, instance, std::move(deleteFunc)); } return instance; } #ifndef ITK_FUTURE_LEGACY_REMOVE template [[deprecated("Prefer calling the Singleton(globalName, deleteFunc) overload (without the unused func parameter)!")]] T * Singleton(const char * globalName, std::function itkNotUsed(func), std::function deleteFunc) { return Singleton(globalName, std::move(deleteFunc)); } #endif } // end namespace itk #endif