//################################################################################################## // // Custom Visualization Core library // Copyright (C) 2011-2013 Ceetron AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: // // GNU General Public License Usage // This library is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // // See the GNU General Public License at <> // for more details. // // GNU Lesser General Public License Usage // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // // See the GNU Lesser General Public License at <> // for more details. // //################################################################################################## #pragma once #include "cafAssert.h" #include #include #include // Taken from gtest.h // // Due to C++ preprocessor weirdness, we need double indirection to // concatenate two tokens when one of them is __LINE__. Writing // // foo ## __LINE__ // // will result in the token foo__LINE__, instead of foo followed by // the current line number. For more details, see // http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 #define CAF_FACTORY_CONCATENATE_STRINGS( foo, bar ) CAF_FACTORY_CONCATENATE_STRINGS_IMPL_( foo, bar ) #define CAF_FACTORY_CONCATENATE_STRINGS_IMPL_( foo, bar ) foo##bar #define CAF_UNIQUE_COMPILE_UNIT_VAR_NAME( foo ) CAF_FACTORY_CONCATENATE_STRINGS( foo, __LINE__ ) /// Macros to simplify registering entries in a factory /// There are two, to make it possible to use two registrations in one macro #define CAF_FACTORY_REGISTER( BaseType, TypeToCreate, KeyType, key ) \ static bool CAF_UNIQUE_COMPILE_UNIT_VAR_NAME( my##TypeToCreate ) = \ caf::Factory::instance()->registerCreator( key ) #define CAF_FACTORY_REGISTER2( BaseType, TypeToCreate, KeyType, key ) \ static bool CAF_UNIQUE_COMPILE_UNIT_VAR_NAME( my2##TypeToCreate ) = \ caf::Factory::instance()->registerCreator( key ) namespace caf { //================================================================================================== /// A generic Factory class template /// Usage: /// Simply add the classes that is supposed to be created by the factory by doing the folowing: /// /// caf::Factory::instance()->registerCreator(key); /// /// This must only be done once for each TypeToCreate. It will assert if you try to do it several times. /// This method returns a bool to make it possible to make this initialization as a static variable initialization. /// That is useful if you do not want a centralized registering (but rather making each class register itself): /// /// static bool uniqueVarname = caf::Factory::instance()->registerCreator(key); /// /// You can also use the macro CAF_FACTORY_REGISTER(BaseType, TypeToCreate, KeyType, key) /// /// See also cafPdmUiFieldEditorHandle.h for an advanced example. /// /// When you need an object: /// /// BaseType* newObject = caf::Factory::instance()->create(key); //================================================================================================== template class Factory { class ObjectCreatorBase; public: typedef typename std::map::iterator iterator_type; static Factory* instance() { static Factory* fact = new Factory; return fact; } template bool registerCreator( const KeyType& key ) { iterator_type entryIt; entryIt = m_factoryMap.find( key ); if ( entryIt == m_factoryMap.end() ) { m_factoryMap[key] = new ObjectCreator(); return true; } else { CAF_ASSERT( key != entryIt->first ); // classNameKeyword has already been used CAF_ASSERT( false ); // To be sure .. return false; } } BaseType* create( const KeyType& key ) { iterator_type entryIt; entryIt = m_factoryMap.find( key ); if ( entryIt != m_factoryMap.end() ) { return entryIt->second->create(); } else { return NULL; } } std::vector allKeys() { std::vector keys; iterator_type entryIt; for ( entryIt = m_factoryMap.begin(); entryIt != m_factoryMap.end(); ++entryIt ) { keys.push_back( entryIt->first ); } return keys; } void deleteCreatorObjects() { for ( auto f : m_factoryMap ) { if ( f.second ) delete f.second; } m_factoryMap.clear(); } private: Factory() {} ~Factory() { iterator_type entryIt; for ( entryIt = m_factoryMap.begin(); entryIt != m_factoryMap.end(); ++entryIt ) { delete ( entryIt->second ); } } // Internal helper classes class ObjectCreatorBase { public: ObjectCreatorBase() {} virtual ~ObjectCreatorBase() {} virtual BaseType* create() = 0; }; template class ObjectCreator : public ObjectCreatorBase { public: BaseType* create() override { return new TypeToCreate(); } }; // Map to store factory std::map m_factoryMap; }; } // End of namespace caf