Browse Source

Whoops wrong file...

Sam Jaffe 7 years ago
parent
commit
0e2aaa3fac

+ 0 - 13
include/resource_factory/prototype_compiler.hpp

@@ -1,13 +0,0 @@
-//
-//  prototype_compiler.hpp
-//  resource_factory
-//
-//  Created by Sam Jaffe on 11/11/18.
-//  Copyright © 2018 Sam Jaffe. All rights reserved.
-//
-
-#pragma once
-
-class prototype_factory {
-  
-};

+ 80 - 0
include/resource_factory/prototype_factory.hpp

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