| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- //
- // polymorphic_factory.hpp
- // resource_factory
- //
- // Created by Sam Jaffe on 8/14/16.
- //
- #pragma once
- #include <functional>
- #include <string>
- #include <unordered_map>
- /*
- * An instance prototype factory factory.
- * The purpose of this object is a prefab for situations where you do not
- * know, necessarily, at compile time all posible types inheriting from the
- * base class. An example of this is in a game, you may have a Mob class.
- * Mob may be instantiated as an Orc, Goblin, Slime, or Knight, but you don't
- * know the exhaustive list, and the overhead for implementing an override
- * for every single type is wasteful. With this object, you can initialize
- * implementations from a string ID, and some parameters required.
- * For example:
- *
- * class Monster { ... };
- * class MonsterPrototype : public Monster {
- * public: Monster operator()(...) const { ... }
- * };
- * using MonsterGenerator = prototype_factory<Monster, ...>;
- * MonsterGenerator::bind("Orc", MonsterPrototype("resources/orc.proto"));
- *
- * -----
- *
- * This can also be used as a generator for polymorphic types, optionally
- * through a plugin system. This would allow a library consumer to define
- * extensions to some polymorphic class, such as a Widget, and use built in
- * features of the library to instantiate it. For example:
- *
- * class Widget { ... };
- * class Button : public Widget { ... };
- * using WidgetGenerator = objects::prototype::factory<std::unique_ptr<Widget>, ...>;
- * WidgetGenerator::bind("Button",
- * [](...) { return std::make_unique<Button>(...); });
- */
- namespace objects { namespace prototype {
- template <typename Base, typename... Args>
- class factory {
- public:
- using rval_t = Base;
- using producer = std::function<rval_t(Args &&...)>;
-
- static factory & instance();
-
- rval_t get(std::string const & type_id, Args &&... args) {
- auto it = _factories.find(type_id);
- if (it == _factories.end()) { return rval_t(); }
- else { return (it->second)(std::forward<Args>(args)...); }
- }
-
- bool bind(std::string const & type_id, producer p) {
- return _factories.insert(std::make_pair(type_id, p)).second;
- }
- private:
- factory() = default;
- std::unordered_map<std::string, producer> _factories;
- };
- } }
- #define INSTANTIATE_PROTOTYPE_FACTORY(...) \
- template <> ::objects::prototype::factory<__VA_ARGS__> & \
- ::objects::prototype::factory<__VA_ARGS__>::instance() { \
- static ::objects::prototype::factory<__VA_ARGS__> _instance; \
- return _instance; \
- }
- #define INSTANTIATE_PROTOTYPE_FACTORY_2(Typedef) \
- template <> Typedef & Typedef::instance() { \
- static Typedef _instance; \
- return _instance; \
- }
|