|
@@ -1,80 +0,0 @@
|
|
|
-//
|
|
|
|
|
-// 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; \
|
|
|
|
|
- }
|
|
|