Files
2026-02-21 17:11:31 +09:00

233 lines
8.0 KiB
C++

/******************************************************************************
Factory: factory template
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
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 <ctype.h> //tolower
#include <cstring>
#include <time.h>
#include <map>
#include <vector>
#include <algorithm> //std::remove
#include "singleton.h"
#if 0
#include <loki/Singleton.h>
template<class Class>
Class& Loki::Singleton<Class>::Instance()
{
return Loki::SingletonHolder<Class>::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<TYPE>(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<TYPE>(ID, NAME); \
} \
} sInit_##TYPE; \
}
#define FACTORY_DEFINE(T) \
class T##Factory : public Factory<T##Id, T, T##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<T##Id>& 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<T##Id>::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 <typename Id, typename T, class Class>
class Factory : public Singleton<Class>
{
DISABLE_COPY(Factory)
typedef Id ID;
typedef T Type;
typedef Type* (*Creator)();
public:
Type* create(const ID& id);
template<class C>
bool register_(const ID& id) { // register_<C>(id, name)
std::pair<typename CreatorMap::iterator, bool> result = creators.insert(std::make_pair(id, create<C>));
return result.second;
}
//template <typename Func>
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<ID> &registeredIds() const;
std::vector<const char*> registeredNames() const;
Type* getRandom(); //remove
// Type* at(int index);
// ID idAt(int index);
protected:
Factory() {}
virtual ~Factory() {}
private:
template<class C>
static Type* create() {
return new C();
}
typedef std::map<ID, Creator> CreatorMap;
CreatorMap creators;
std::vector<ID> ids;
typedef std::map<ID, const char*> NameMap;
NameMap name_map; //static?
};
#if 0
template<typename Id, typename T, class Class>
typename Factory<Id, T, Class>::CreatorMap Factory<Id, T, Class>::creators;
template<typename Id, typename T, class Class>
typename Factory<Id, T, Class>::NameMap Factory<Id, T, Class>::name_map;
#endif
template<typename Id, typename T, class Class>
typename Factory<Id, T, Class>::Type *Factory<Id, T, Class>::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<typename Id, typename T, class Class>
bool Factory<Id, T, Class>::registerCreator(const ID& id, const Creator& callback)
{
//DBG("%p id [%d] registered. size=%d\n", &Factory<Id, T, Class>::Instance(), id, ids.size());
ids.insert(ids.end(), id);
return creators.insert(typename CreatorMap::value_type(id, callback)).second;
}
template<typename Id, typename T, class Class>
bool Factory<Id, T, Class>::registerIdName(const ID& id, const char* name)
{
return name_map.insert(typename NameMap::value_type(id, name/*.toLower()*/)).second;
}
template<typename Id, typename T, class Class>
bool Factory<Id, T, Class>::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 Id, typename T, class Class>
typename Factory<Id, T, Class>::ID Factory<Id, T, Class>::id(const char* name, bool caseSensitive) const
{
#ifdef _MSC_VER
#define strcasecmp(s1, s2) _strcmpi(s1, s2)
#endif
//need 'typename' because 'Factory<Id, T, Class>::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<typename Id, typename T, class Class>
const char* Factory<Id, T, Class>::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<typename Id, typename T, class Class>
const std::vector<Id>& Factory<Id, T, Class>::registeredIds() const
{
return ids;
}
template<typename Id, typename T, class Class>
std::vector<const char*> Factory<Id, T, Class>::registeredNames() const
{
std::vector<const char*> names;
for (typename NameMap::const_iterator it = name_map.begin(); it != name_map.end(); ++it) {
names.push_back((*it).second);
}
return names;
}
template<typename Id, typename T, class Class>
size_t Factory<Id, T, Class>::count() const
{
//DBG("%p size = %d", &Factory<Id, T, Class>::Instance(), ids.size());
return ids.size();
}
template<typename Id, typename T, class Class>
typename Factory<Id, T, Class>::Type* Factory<Id, T, Class>::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