prototype_factory.hpp 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  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 <unordered_map>
  10. /*
  11. * An instance prototype factory factory.
  12. * The purpose of this object is a prefab for situations where you do not
  13. * know, necessarily, at compile time all posible types inheriting from the
  14. * base class. An example of this is in a game, you may have a Mob class.
  15. * Mob may be instantiated as an Orc, Goblin, Slime, or Knight, but you don't
  16. * know the exhaustive list, and the overhead for implementing an override
  17. * for every single type is wasteful. With this object, you can initialize
  18. * implementations from a string ID, and some parameters required.
  19. * For example:
  20. *
  21. * class Monster { ... };
  22. * class MonsterPrototype : public Monster {
  23. * public: Monster operator()(...) const { ... }
  24. * };
  25. * using MonsterGenerator = prototype_factory<Monster, ...>;
  26. * MonsterGenerator::bind("Orc", MonsterPrototype("resources/orc.proto"));
  27. *
  28. * -----
  29. *
  30. * This can also be used as a generator for polymorphic types, optionally
  31. * through a plugin system. This would allow a library consumer to define
  32. * extensions to some polymorphic class, such as a Widget, and use built in
  33. * features of the library to instantiate it. For example:
  34. *
  35. * class Widget { ... };
  36. * class Button : public Widget { ... };
  37. * using WidgetGenerator = prototype_factory<std::unique_ptr<Widget>, ...>;
  38. * WidgetGenerator::bind("Button",
  39. * [](...) { return std::make_unique<Button>(...); });
  40. */
  41. template <typename Base, typename... Args>
  42. class prototype_factory {
  43. public:
  44. using rval_t = Base;
  45. using producer = std::function<rval_t(Args &&...)>;
  46. static rval_t get(std::string const & type_id, Args &&... args) {
  47. auto it = _factories.find(type_id);
  48. if (it == _factories.end()) { return rval_t(); }
  49. else { return (it->second)(std::forward<Args>(args)...); }
  50. }
  51. static bool bind(std::string const & type_id, producer p) {
  52. return _factories.insert(std::make_pair(type_id, p)).second;
  53. }
  54. private:
  55. static std::unordered_map<std::string, producer> _factories;
  56. };