[ create a new paste ] login | about

Link: http://codepad.org/kBtU0puv    [ raw code | fork ]

C++, pasted on Feb 9:
#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


Create a new paste based on this one


Comments: