codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
#include <type_traits> #include <functional> #include <stdexcept> #include <sstream> #include <string> #include <vector> #include <unordered_map> #include <set> #include <featherkit/entity/entitymanager.h> #include <featherkit/entity/entity.h> namespace fea { using Params = std::vector<std::string>; using Template = std::unordered_map<std::string, std::string>; namespace detail { Params split(const std::string& in, char delim) { Params params; std::string param; std::stringstream splitter(in); while (std::getline(splitter, param, delim)) { params.push_back(param); } return params; } } // namespace detail class EntityFactory { public: EntityFactory(EntityManager& manager) : m_manager{ &manager } {} template<typename Fn> void addPrimitive(const std::string& primitive, Fn parser) { if (m_mapper.find(primitive) != m_mapper.end()) { throw std::logic_error{ "duplicate primitive [" + primitive + "]" }; } using Type = typename std::result_of<Fn(const Params&)>::type; // make parser/registration generator. m_mapper[primitive] = [this, parser](const std::string& name)->Parser { m_manager->registerAttribute<Type>(name); // make paser. return [parser, name](const std::string& params)->Setter { auto value = parser(detail::split(params, ',')); // make setter. return [name, value](EntityPtr& entity) { entity->setAttribute<Type>(name, value); }; }; }; } void map(const std::string& attribute, const std::string& primitive) { if (m_parser.find(attribute) != m_parser.end()) { throw std::logic_error{ "duplicate attribute [" + attribute + "]" }; } auto it = m_mapper.find(primitive); if (it == m_mapper.end()) { throw std::invalid_argument{ "no primitive [" + primitive + "]" }; } m_parser.emplace(attribute, it->second(attribute)); } void addTemplate(const std::string& name, const Template& data) { if (m_proto.find(name) != m_proto.end()) { throw std::logic_error{ "duplicate template [" + name + "]" }; } Proto proto; for (const auto& elememt : data) { const auto& attribute = elememt.first; const auto& arguments = elememt.second; proto.attributes.insert(attribute); if (arguments.size()) { auto it = m_parser.find(attribute); if (it == m_parser.end()) { throw std::invalid_argument{ "attribute [" + attribute + "] not mapped to primitive" }; } const auto& parser = it->second; proto.values.insert({ attribute, parser(arguments) }); } } m_proto.emplace(name, std::move(proto)); } WeakEntityPtr instantiate(const std::string& name) { const auto it = m_proto.find(name); if (it == m_proto.end()) { throw std::invalid_argument{ "no template [" + name + "]" }; } const auto& attributes = it->second.attributes; const auto& values = it->second.values; auto entity = m_manager->createEntity(attributes).lock(); for (const auto& value : values) { value.setter(entity); } return entity; } private: using Setter = std::function<void(EntityPtr&)>; using Parser = std::function<Setter(const std::string&)>; using Mapper = std::function<Parser(const std::string&)>; private: struct Proto { struct Value { bool operator<(const Value& other) const { return key < other.key; } std::string key; Setter setter; }; std::set<std::string> attributes; std::set<Value> values; }; private: std::unordered_map<std::string, Proto> m_proto; std::unordered_map<std::string, Parser> m_parser; std::unordered_map<std::string, Mapper> m_mapper; EntityManager* m_manager; }; } // namespace fea
Private
[
?
]
Run code
Submit