prototype_factory.hpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. //
  2. // polymorphic_factory.hpp
  3. // resource_factory
  4. //
  5. // Created by Sam Jaffe on 8/14/16.
  6. //
  7. #pragma once
  8. #include <functional>
  9. #include <string>
  10. #include <unordered_map>
  11. /*
  12. * An instance prototype factory factory.
  13. * The purpose of this object is a prefab for situations where you do not
  14. * know, necessarily, at compile time all posible types inheriting from the
  15. * base class. An example of this is in a game, you may have a Mob class.
  16. * Mob may be instantiated as an Orc, Goblin, Slime, or Knight, but you don't
  17. * know the exhaustive list, and the overhead for implementing an override
  18. * for every single type is wasteful. With this object, you can initialize
  19. * implementations from a string ID, and some parameters required.
  20. * For example:
  21. *
  22. * class Monster { ... };
  23. * class MonsterPrototype : public Monster {
  24. * public: Monster operator()(...) const { ... }
  25. * };
  26. * using MonsterGenerator = prototype_factory<Monster, ...>;
  27. * MonsterGenerator::bind("Orc", MonsterPrototype("resources/orc.proto"));
  28. *
  29. * -----
  30. *
  31. * This can also be used as a generator for polymorphic types, optionally
  32. * through a plugin system. This would allow a library consumer to define
  33. * extensions to some polymorphic class, such as a Widget, and use built in
  34. * features of the library to instantiate it. For example:
  35. *
  36. * class Widget { ... };
  37. * class Button : public Widget { ... };
  38. * using WidgetGenerator = objects::prototype::factory<std::unique_ptr<Widget>, ...>;
  39. * WidgetGenerator::bind("Button",
  40. * [](...) { return std::make_unique<Button>(...); });
  41. */
  42. namespace objects { namespace prototype {
  43. template <typename Base, typename... Args>
  44. class factory {
  45. public:
  46. using rval_t = Base;
  47. using producer = std::function<rval_t(Args &&...)>;
  48. static factory & instance();
  49. rval_t get(std::string const & type_id, Args &&... args) {
  50. auto it = _factories.find(type_id);
  51. if (it == _factories.end()) { return rval_t(); }
  52. else { return (it->second)(std::forward<Args>(args)...); }
  53. }
  54. bool bind(std::string const & type_id, producer p) {
  55. return _factories.insert(std::make_pair(type_id, p)).second;
  56. }
  57. private:
  58. factory() = default;
  59. std::unordered_map<std::string, producer> _factories;
  60. };
  61. } }
  62. #define INSTANTIATE_PROTOTYPE_FACTORY(...) \
  63. template <> ::objects::prototype::factory<__VA_ARGS__> & \
  64. ::objects::prototype::factory<__VA_ARGS__>::instance() { \
  65. static ::objects::prototype::factory<__VA_ARGS__> _instance; \
  66. return _instance; \
  67. }
  68. #define INSTANTIATE_PROTOTYPE_FACTORY_2(Typedef) \
  69. template <> Typedef & Typedef::instance() { \
  70. static Typedef _instance; \
  71. return _instance; \
  72. }