Browse Source

meta: guaranteed order on overloaded meta functions

Michele Caini 1 year ago
parent
commit
689005d452
2 changed files with 64 additions and 33 deletions
  1. 20 17
      src/entt/meta/factory.hpp
  2. 44 16
      test/entt/meta/meta_type.cpp

+ 20 - 17
src/entt/meta/factory.hpp

@@ -74,26 +74,29 @@ protected:
     }
     }
 
 
     void func(const id_type id, meta_func_node node) {
     void func(const id_type id, meta_func_node node) {
-        if(auto it = details->func.find(id); it != details->func.end()) {
-            for(auto *curr = &it->second; curr; curr = curr->next.get()) {
-                if(curr->invoke == node.invoke) {
-                    node.next = std::move(curr->next);
-                    *curr = std::move(node);
-                    bucket = &curr->prop;
-                    user = &curr->custom;
-                    mask = &curr->traits;
-                    return;
-                }
+        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;
+        } else {
+            auto *curr = &it->second;
+
+            while(curr->invoke != node.invoke && curr->next) {
+                curr = curr->next.get();
             }
             }
 
 
-            // locally overloaded function
-            node.next = std::make_shared<meta_func_node>(std::move(details->func[id]));
-        }
+            if(curr->invoke != node.invoke) {
+                curr->next = std::make_shared<meta_func_node>();
+                curr = curr->next.get();
+            }
 
 
-        auto &&it = details->func.insert_or_assign(id, std::move(node)).first;
-        bucket = &it->second.prop;
-        user = &it->second.custom;
-        mask = &it->second.traits;
+            node.next = std::move(curr->next);
+            *curr = std::move(node);
+            bucket = &curr->prop;
+            user = &curr->custom;
+            mask = &curr->traits;
+        }
     }
     }
 
 
     void prop(const id_type key, meta_prop_node value) {
     void prop(const id_type key, meta_prop_node value) {

+ 44 - 16
test/entt/meta/meta_type.cpp

@@ -71,17 +71,13 @@ struct clazz {
 };
 };
 
 
 struct overloaded_func {
 struct overloaded_func {
-    [[nodiscard]] int e(int v) const {
-        return v + v;
-    }
-
     [[nodiscard]] int f(const base &, int a, int b) {
     [[nodiscard]] int f(const base &, int a, int b) {
         return f(a, b);
         return f(a, b);
     }
     }
 
 
     [[nodiscard]] int f(int a, const int b) {
     [[nodiscard]] int f(int a, const int b) {
         value = a;
         value = a;
-        return g(b);
+        return b * b;
     }
     }
 
 
     [[nodiscard]] int f(int v) {
     [[nodiscard]] int f(int v) {
@@ -89,16 +85,12 @@ struct overloaded_func {
     }
     }
 
 
     [[nodiscard]] int f(int v) const {
     [[nodiscard]] int f(int v) const {
-        return g(v);
+        return v * v;
     }
     }
 
 
     [[nodiscard]] float f(int a, const float b) {
     [[nodiscard]] float f(int a, const float b) {
         value = a;
         value = a;
-        return static_cast<float>(e(static_cast<int>(b)));
-    }
-
-    [[nodiscard]] int g(int v) const {
-        return v * v;
+        return b + b;
     }
     }
 
 
     int value{};
     int value{};
@@ -147,13 +139,11 @@ struct MetaType: ::testing::Test {
 
 
         entt::meta<overloaded_func>()
         entt::meta<overloaded_func>()
             .type("overloaded_func"_hs)
             .type("overloaded_func"_hs)
-            .func<&overloaded_func::e>("e"_hs)
             .func<entt::overload<int(const base &, int, int)>(&overloaded_func::f)>("f"_hs)
             .func<entt::overload<int(const base &, int, int)>(&overloaded_func::f)>("f"_hs)
             .func<entt::overload<int(int, int)>(&overloaded_func::f)>("f"_hs)
             .func<entt::overload<int(int, int)>(&overloaded_func::f)>("f"_hs)
             .func<entt::overload<int(int)>(&overloaded_func::f)>("f"_hs)
             .func<entt::overload<int(int)>(&overloaded_func::f)>("f"_hs)
             .func<entt::overload<int(int) const>(&overloaded_func::f)>("f"_hs)
             .func<entt::overload<int(int) const>(&overloaded_func::f)>("f"_hs)
-            .func<entt::overload<float(int, float)>(&overloaded_func::f)>("f"_hs)
-            .func<&overloaded_func::g>("g"_hs);
+            .func<entt::overload<float(int, float)>(&overloaded_func::f)>("f"_hs);
 
 
         entt::meta<property_type>()
         entt::meta<property_type>()
             .type("property"_hs)
             .type("property"_hs)
@@ -457,8 +447,6 @@ TEST_F(MetaType, OverloadedFunc) {
     entt::meta_any res{};
     entt::meta_any res{};
 
 
     ASSERT_TRUE(type.func("f"_hs));
     ASSERT_TRUE(type.func("f"_hs));
-    ASSERT_TRUE(type.func("e"_hs));
-    ASSERT_TRUE(type.func("g"_hs));
 
 
     res = type.invoke("f"_hs, instance, base{}, 1, 2);
     res = type.invoke("f"_hs, instance, base{}, 1, 2);
 
 
@@ -506,6 +494,46 @@ TEST_F(MetaType, OverloadedFunc) {
     ASSERT_FALSE(type.invoke("f"_hs, instance, 4, 8.));
     ASSERT_FALSE(type.invoke("f"_hs, instance, 4, 8.));
 }
 }
 
 
+TEST_F(MetaType, OverloadedFuncOrder) {
+    using namespace entt::literals;
+
+    const auto type = entt::resolve<overloaded_func>();
+    auto func = type.func("f"_hs);
+
+    ASSERT_TRUE(func);
+    ASSERT_EQ(func.arity(), 3u);
+    ASSERT_FALSE(func.is_const());
+    ASSERT_EQ(func.ret(), entt::resolve<int>());
+
+    func = func.next();
+
+    ASSERT_TRUE(func);
+    ASSERT_EQ(func.arity(), 2u);
+    ASSERT_FALSE(func.is_const());
+    ASSERT_EQ(func.ret(), entt::resolve<int>());
+
+    func = func.next();
+
+    ASSERT_TRUE(func);
+    ASSERT_EQ(func.arity(), 1u);
+    ASSERT_FALSE(func.is_const());
+    ASSERT_EQ(func.ret(), entt::resolve<int>());
+
+    func = func.next();
+
+    ASSERT_TRUE(func);
+    ASSERT_EQ(func.arity(), 1u);
+    ASSERT_TRUE(func.is_const());
+    ASSERT_EQ(func.ret(), entt::resolve<int>());
+
+    func = func.next();
+
+    ASSERT_TRUE(func);
+    ASSERT_EQ(func.arity(), 2u);
+    ASSERT_FALSE(func.is_const());
+    ASSERT_EQ(func.ret(), entt::resolve<float>());
+}
+
 TEST_F(MetaType, Construct) {
 TEST_F(MetaType, Construct) {
     auto any = entt::resolve<clazz>().construct(base{}, 2);
     auto any = entt::resolve<clazz>().construct(base{}, 2);