/****************************************************************************** Factory: factory template Copyright (C) 2012-2016 Wang Bin 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 for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ #ifndef FACTORY_H #define FACTORY_H /* * NOTE: this file can not be included in public headers! It must be used * inside the library, i.e., only be included in cpp or internal header. * Using it outside results in initializing static singleton member twice. */ #include //tolower #include #include #include #include #include //std::remove #include "singleton.h" #if 0 #include template Class& Loki::Singleton::Instance() { return Loki::SingletonHolder::Instance(); } #endif #define FACTORY_REGISTER(BASE, _ID, NAME) FACTORY_REGISTER_ID_TYPE(BASE, BASE##Id_##_ID, BASE##_ID, NAME) #define FACTORY_REGISTER_ID_TYPE(BASE, ID, TYPE, NAME) \ FACTORY_REGISTER_ID_TYPE_AUTO(BASE, ID, TYPE, NAME) \ bool Register##TYPE##_Man() { \ return BASE::Register(ID, NAME); \ } #define FACTORY_REGISTER_ID_TYPE_AUTO(BASE, ID, TYPE, NAME) \ namespace { \ static const struct factory_register_##TYPE { \ inline factory_register_##TYPE() { \ BASE::Register(ID, NAME); \ } \ } sInit_##TYPE; \ } #define FACTORY_DEFINE(T) \ class T##Factory : public Factory {}; \ bool T::Register(T##Id id, T##Creator c, const char *name) { \ DBG(#T "::Register(..., %s)\n", name); \ return T##Factory::Instance().registerCreator(id, c) && T##Factory::Instance().registerIdName(id, name); \ } \ T* T::create(T##Id id) {return T##Factory::Instance().create(id);} \ T* T::create(const char* name) { return T::create(T::id(name));} \ T##Id* T::next(T##Id *id) { \ const std::vector& ids = T##Factory::Instance().registeredIds(); \ if (!id) return (T##Id*)&ids[0]; \ T##Id *id0 = (T##Id*)&ids[0], *id1 = (T##Id*)&ids[ids.size() - 1]; \ if (id >= id0 && id < id1) return id + 1; \ if (id == id1) return NULL; \ std::vector::const_iterator it = std::find(ids.begin(), ids.end(), *id); \ if (it == ids.end()) return NULL; \ return (T##Id*)&*(it++); \ } \ T##Id T::id(const char* name) { DBG(#T "::id(\"%s\")\n", name); return T##Factory::Instance().id(name, false);} \ const char* T::name(T##Id id) {return T##Factory::Instance().name(id);} /* * Used in library, can not be used both in library and outside. so we don't need export it */ template class Factory : public Singleton { DISABLE_COPY(Factory) typedef Id ID; typedef T Type; typedef Type* (*Creator)(); public: Type* create(const ID& id); template bool register_(const ID& id) { // register_(id, name) std::pair result = creators.insert(std::make_pair(id, create)); return result.second; } //template bool registerCreator(const ID& id, const Creator& callback); bool registerIdName(const ID& id, const char* name); bool unregisterCreator(const ID& id); //bool unregisterAll(); ID id(const char* name, bool caseSensitive = true) const; const char* name(const ID &id) const; size_t count() const; const std::vector ®isteredIds() const; std::vector registeredNames() const; Type* getRandom(); //remove // Type* at(int index); // ID idAt(int index); protected: Factory() {} virtual ~Factory() {} private: template static Type* create() { return new C(); } typedef std::map CreatorMap; CreatorMap creators; std::vector ids; typedef std::map NameMap; NameMap name_map; //static? }; #if 0 template typename Factory::CreatorMap Factory::creators; template typename Factory::NameMap Factory::name_map; #endif template typename Factory::Type *Factory::create(const ID& id) { typename CreatorMap::const_iterator it = creators.find(id); if (it == creators.end()) { DBG("Unknown id "); return 0; //throw std::runtime_error(err_msg.arg(id).toStdString()); } return (it->second)(); } template bool Factory::registerCreator(const ID& id, const Creator& callback) { //DBG("%p id [%d] registered. size=%d\n", &Factory::Instance(), id, ids.size()); ids.insert(ids.end(), id); return creators.insert(typename CreatorMap::value_type(id, callback)).second; } template bool Factory::registerIdName(const ID& id, const char* name) { return name_map.insert(typename NameMap::value_type(id, name/*.toLower()*/)).second; } template bool Factory::unregisterCreator(const ID& id) { //DBG("Id [%d] unregistered\n", id); ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end()); name_map.erase(id); return creators.erase(id) == 1; } template typename Factory::ID Factory::id(const char* name, bool caseSensitive) const { #ifdef _MSC_VER #define strcasecmp(s1, s2) _strcmpi(s1, s2) #endif //need 'typename' because 'Factory::NameMap' is a dependent scope for (typename NameMap::const_iterator it = name_map.begin(); it!=name_map.end(); ++it) { if (caseSensitive) { if (it->second == name || !strcmp(it->second, name)) return it->first; } else { if (!strcasecmp(it->second, name)) { return it->first; } } } DBG("Not found\n"); return ID(); //can not return ref. TODO: Use a ID wrapper class } template const char* Factory::name(const ID &id) const { typename NameMap::const_iterator it = name_map.find(id); if (it == name_map.end()) return NULL; return it->second; } template const std::vector& Factory::registeredIds() const { return ids; } template std::vector Factory::registeredNames() const { std::vector names; for (typename NameMap::const_iterator it = name_map.begin(); it != name_map.end(); ++it) { names.push_back((*it).second); } return names; } template size_t Factory::count() const { //DBG("%p size = %d", &Factory::Instance(), ids.size()); return ids.size(); } template typename Factory::Type* Factory::getRandom() { srand(time(0)); int index = rand() % ids.size(); //DBG("random %d/%d", index, ids.size()); ID new_eid = ids.at(index); //DBG("id %d", new_eid); return create(new_eid); } #endif // FACTORY_H