/*========================================================================= * * 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. * *=========================================================================*/ /*========================================================================= * * Portions of this file are subject to the VTK Toolkit Version 3 copyright. * * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen * * For complete copyright, license and disclaimer of warranty information * please refer to the NOTICE file at the top of the ITK source tree. * *=========================================================================*/ #ifndef itkObjectFactoryBase_h #define itkObjectFactoryBase_h #include "itkCreateObjectFunction.h" #include "itkSingletonMacro.h" #include "itkCommonEnums.h" #include #include // For unique_ptr. #include namespace itk { /** \class ObjectFactoryBase * \brief Create instances of classes using an object factory. * * ObjectFactoryBase is used to create itk objects. The base class * ObjectFactoryBase contains a static method CreateInstance() that is * used to create itk objects from the list of registered ObjectFactoryBase * sub-classes. The first time CreateInstance() is called, all dll's or * shared libraries in the environment variable ITK_AUTOLOAD_PATH are loaded * into the current process. The C function itkLoad is called on each dll. * itkLoad should return an instance of the factory sub-class implemented in * the shared library. ITK_AUTOLOAD_PATH is an environment variable * containing a colon separated (semi-colon on win32) list of paths. * * This can be use to override the creation of any object in ITK. * * \ingroup ITKSystemObjects * \ingroup ITKCommon */ class ITKCommon_EXPORT ObjectFactoryBase : public Object { public: ITK_DISALLOW_COPY_AND_MOVE(ObjectFactoryBase); /** Standard class type aliases. */ using Self = ObjectFactoryBase; using Superclass = Object; using Pointer = SmartPointer; using ConstPointer = SmartPointer; /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(ObjectFactoryBase); /** Create and return an instance of the named itk object. * Each loaded ObjectFactoryBase will be asked in the order * the factory was in the ITK_AUTOLOAD_PATH. After the * first factory returns the object no other factories are asked. * * \note The object returned by `CreateInstance` will have a reference count of 2, instead of 1. So in order to avoid * memory leaks, one may need to call `object->UnRegister()`. */ static LightObject::Pointer CreateInstance(const char * itkclassname); /** Create and return all possible instances of the named itk object. * Each loaded ObjectFactoryBase will be asked in the order * the factory was in the ITK_AUTOLOAD_PATH. All created objects * will be returned in the list. */ static std::list CreateAllInstance(const char * itkclassname); /** Re-check the ITK_AUTOLOAD_PATH for new factory libraries. * This calls UnRegisterAll before re-loading. */ static void ReHash(); /** Register a factory so it can be used to create itk objects. * This method is intended to be called only for built-in default * factories, not for loadable factories. * * Factories that are registered with this method will be * registered after ReHash. */ static void RegisterFactoryInternal(ObjectFactoryBase *); using InsertionPositionEnum = ObjectFactoryEnums::InsertionPosition; #if !defined(ITK_LEGACY_REMOVE) // We need to expose the enum values at the class level // for backwards compatibility static constexpr InsertionPositionEnum INSERT_AT_FRONT = InsertionPositionEnum::INSERT_AT_FRONT; static constexpr InsertionPositionEnum INSERT_AT_BACK = InsertionPositionEnum::INSERT_AT_BACK; static constexpr InsertionPositionEnum INSERT_AT_POSITION = InsertionPositionEnum::INSERT_AT_POSITION; #endif /** Register a factory so it can be used to create itk objects. * * When InsertionPositionEnum::INSERT_AT_POSITION is selected, a third argument must be provided * with the actual integer number of the intended position. The position * number must be in the range [0, numberOfRegisteredFactories-1]. * * Usage should be any of the following: * * itk::ObjectFactoryBase::RegisterFactory( newFactory1 ); // at back * itk::ObjectFactoryBase::RegisterFactory( newFactory2, InsertionPositionEnum::INSERT_AT_FRONT ); * itk::ObjectFactoryBase::RegisterFactory( newFactory3, InsertionPositionEnum::INSERT_AT_BACK ); * itk::ObjectFactoryBase::RegisterFactory( newFactory4, InsertionPositionEnum::INSERT_AT_POSITION, 5 ); * * If the position value is out of range, an exception will be * thrown. * Returns true if the factory was successfully registered. * Returns false if factory is already loaded. */ static bool RegisterFactory(ObjectFactoryBase *, InsertionPositionEnum where = InsertionPositionEnum::INSERT_AT_BACK, size_t position = 0); /** Remove a factory from the list of registered factories. */ static void UnRegisterFactory(ObjectFactoryBase *); /** Unregister all factories. */ static void UnRegisterAllFactories(); /** Return the list of all registered factories. This is NOT a copy, * do not remove items from this list! */ static std::list GetRegisteredFactories(); /** All sub-classes of ObjectFactoryBase should must return the version of * ITK they were built with. This should be implemented with the macro * ITK_SOURCE_VERSION and NOT a call to Version::GetITKSourceVersion. * As the version needs to be compiled into the file as a string constant. * This is critical to determine possible incompatible dynamic factory loads. */ virtual const char * GetITKSourceVersion() const = 0; /** Require the ITK version of this application to exactly match the ITK * version used to compile a dynamic library. When this is set to true, if the * versions do not match, an exception will be thrown. When this is false, and * the versions do not match, only a warning message is printed out in the * console, and the factory is still registered. */ static void SetStrictVersionChecking(bool); static void StrictVersionCheckingOn(); static void StrictVersionCheckingOff(); static bool GetStrictVersionChecking(); /** Return a descriptive string describing the factory. */ virtual const char * GetDescription() const = 0; /** Return a list of classes that this factory overrides. */ virtual std::list GetClassOverrideNames(); /** Return a list of the names of classes that override classes. */ virtual std::list GetClassOverrideWithNames(); /** Return a list of descriptions for class overrides. */ virtual std::list GetClassOverrideDescriptions(); /** Return a list of enable flags. */ virtual std::list GetEnableFlags(); /** Set the Enable flag for the specific override of className. */ virtual void SetEnableFlag(bool flag, const char * className, const char * subclassName); /** Get the Enable flag for the specific override of className. */ virtual bool GetEnableFlag(const char * className, const char * subclassName); /** Set all enable flags for the given class to 0. This will * mean that the factory will stop producing class with the given * name. */ virtual void Disable(const char * className); /** This returns the path to a dynamically loaded factory. */ const char * GetLibraryPath(); /** Registers the specified internal factory only once, even when `RegisterInternalFactoryOnce()` is called * multiple times (possibly even by multiple threads) for the very same factory. */ template static void RegisterInternalFactoryOnce() { struct FactoryRegistration {}; // Factory registration, made thread-safe by "magic statics" (as introduced with C++11). static const FactoryRegistration staticFactoryRegistration = [] { RegisterFactoryInternal(TFactory::New()); return FactoryRegistration{}; }(); (void)staticFactoryRegistration; } /** Initialize the static members of ObjectFactoryBase. */ static void Initialize(); protected: void PrintSelf(std::ostream & os, Indent indent) const override; /** Register object creation information with the factory. */ void RegisterOverride(const char * classOverride, const char * subclass, const char * description, bool enableFlag, CreateObjectFunctionBase * createFunction); /** This method is provided by sub-classes of ObjectFactoryBase. * It should create the named itk object or return 0 if that object * is not supported by the factory implementation. */ virtual LightObject::Pointer CreateObject(const char * itkclassname); /** This method creates all the objects with the class override of * itkclass name, which are provide by this object */ virtual std::list CreateAllObject(const char * itkclassname); ObjectFactoryBase(); ~ObjectFactoryBase() override; private: // Forward reference because of private implementation class OverrideMap; class ObjectFactoryBasePrivate; /** Set/Get the pointer to ObjectFactoryBasePrivate. * No concurrent thread safe. */ static void SynchronizeObjectFactoryBase(void * objectFactoryBasePrivate); itkGetGlobalDeclarationMacro(ObjectFactoryBasePrivate, PimplGlobals); const std::unique_ptr m_OverrideMap; /** Load dynamic factories from the ITK_AUTOLOAD_PATH */ static void LoadDynamicFactories(); /** Load all dynamic libraries in the given path */ static void LoadLibrariesInPath(const char *); static void DeleteNonInternalFactory(ObjectFactoryBase *); /** Member variables for a factory set by the base class * at load or register time */ void * m_LibraryHandle{}; unsigned long m_LibraryDate{}; std::string m_LibraryPath{}; static ObjectFactoryBasePrivate * m_PimplGlobals; }; } // end namespace itk #endif