Browse Source

meta: support creating multiple types with different factories

skypjack 1 year ago
parent
commit
8b0ef2b942
1 changed files with 55 additions and 35 deletions
  1. 55 35
      src/entt/meta/factory.hpp

+ 55 - 35
src/entt/meta/factory.hpp

@@ -28,57 +28,62 @@ namespace entt {
 namespace internal {
 
 class basic_meta_factory {
+    using invoke_type = std::remove_pointer_t<decltype(meta_func_node::invoke)>;
+
+    auto *find_overload() {
+        auto *curr = &details->func[bucket];
+
+        while(curr->invoke != invoke) {
+            curr = curr->next.get();
+        }
+
+        return curr;
+    }
+
 protected:
     void type(const id_type id) noexcept {
         auto &&elem = meta_context::from(*ctx).value[parent];
         ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier");
-        bucket = &elem.details->prop;
-        user = &elem.custom;
-        mask = &elem.traits;
+        invoke = nullptr;
+        bucket = parent;
         elem.id = id;
     }
 
     void base(const id_type id, meta_base_node node) {
         details->base.insert_or_assign(id, node);
-        bucket = nullptr;
-        user = nullptr;
-        mask = nullptr;
+        invoke = nullptr;
+        bucket = parent;
     }
 
     void conv(const id_type id, meta_conv_node node) {
         details->conv.insert_or_assign(id, node);
-        bucket = nullptr;
-        user = nullptr;
-        mask = nullptr;
+        invoke = nullptr;
+        bucket = parent;
     }
 
     void ctor(const id_type id, meta_ctor_node node) {
         details->ctor.insert_or_assign(id, node);
-        bucket = nullptr;
-        user = nullptr;
-        mask = nullptr;
+        invoke = nullptr;
+        bucket = parent;
     }
 
     void dtor(meta_dtor_node node) {
         meta_context::from(*ctx).value[parent].dtor = node;
-        bucket = nullptr;
-        user = nullptr;
-        mask = nullptr;
+        invoke = nullptr;
+        bucket = parent;
     }
 
     void data(const id_type id, meta_data_node node) {
-        auto &&it = details->data.insert_or_assign(id, std::move(node)).first;
-        bucket = &it->second.prop;
-        user = &it->second.custom;
-        mask = &it->second.traits;
+        details->data.insert_or_assign(id, std::move(node));
+        invoke = nullptr;
+        bucket = id;
     }
 
     void func(const id_type id, meta_func_node node) {
         if(auto it = details->func.find(id); it == details->func.end()) {
             auto &&elem = details->func.insert_or_assign(id, std::move(node)).first;
-            bucket = &elem->second.prop;
-            user = &elem->second.custom;
-            mask = &elem->second.traits;
+            invoke = elem->second.invoke;
+            bucket = id;
         } else {
             auto *curr = &it->second;
 
@@ -93,28 +98,47 @@ protected:
 
             node.next = std::move(curr->next);
             *curr = std::move(node);
-            bucket = &curr->prop;
-            user = &curr->custom;
-            mask = &curr->traits;
+
+            invoke = curr->invoke;
+            bucket = id;
         }
     }
 
     void prop(const id_type key, meta_prop_node value) {
-        (*bucket)[key] = std::move(value);
+        if(bucket == parent) {
+            details->prop[key] = std::move(value);
+        } else if(invoke == nullptr) {
+            details->data[bucket].prop[key] = std::move(value);
+        } else {
+            find_overload()->prop[key] = std::move(value);
+        }
     }
 
     void traits(const meta_traits value) {
-        *mask |= value;
+        if(bucket == parent) {
+            meta_context::from(*ctx).value[bucket].traits |= value;
+        } else if(invoke == nullptr) {
+            details->data[bucket].traits |= value;
+        } else {
+            find_overload()->traits |= value;
+        }
     }
 
     void custom(meta_custom_node node) {
-        *user = std::move(node);
+        if(bucket == parent) {
+            meta_context::from(*ctx).value[bucket].custom = std::move(node);
+        } else if(invoke == nullptr) {
+            details->data[bucket].custom = std::move(node);
+        } else {
+            find_overload()->custom = std::move(node);
+        }
     }
 
 public:
     basic_meta_factory(const id_type id, meta_ctx &area)
         : ctx{&area},
-          parent{id} {
+          parent{id},
+          bucket{id} {
         auto &&elem = meta_context::from(*ctx).value[parent];
 
         if(!elem.details) {
@@ -122,18 +146,14 @@ public:
         }
 
         details = elem.details.get();
-        bucket = &details->prop;
-        user = &elem.custom;
-        mask = &elem.traits;
     }
 
 private:
     meta_ctx *ctx{};
     id_type parent{};
+    id_type bucket{};
+    invoke_type *invoke{};
     meta_type_descriptor *details{};
-    dense_map<id_type, meta_prop_node, identity> *bucket{};
-    meta_custom_node *user{};
-    meta_traits *mask;
 };
 
 } // namespace internal