Browse Source

meta: meta_func_node is no longer static

Michele Caini 3 years ago
parent
commit
53f2bb7701
4 changed files with 78 additions and 127 deletions
  1. 20 25
      src/entt/meta/factory.hpp
  2. 42 55
      src/entt/meta/meta.hpp
  3. 8 35
      src/entt/meta/node.hpp
  4. 8 12
      test/entt/meta/meta_func.cpp

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

@@ -36,19 +36,6 @@ inline void link_type_if_required(meta_type_node *owner, const id_type id) noexc
     }
 }
 
-inline void link_func_if_required(meta_type_node *owner, const id_type id, meta_func_node &node) noexcept {
-    node.id = id;
-
-    for(auto it = owner->func; it; it = it->next) {
-        if(it == &node) {
-            return;
-        }
-    }
-
-    node.next = owner->func;
-    owner->func = &node;
-}
-
 } // namespace internal
 
 /**
@@ -423,19 +410,30 @@ public:
         using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
         static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
 
-        static internal::meta_func_node node{
-            {},
+        internal::meta_func_node node{
+            type_id<type_list_cat_t<type_list<descriptor::return_type>, descriptor::args_type>>().hash(),
             (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
-            nullptr,
             descriptor::args_type::size,
             internal::meta_node<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>::resolve(),
             &meta_arg<typename descriptor::args_type>,
-            &meta_invoke<Type, Candidate, Policy>
-            // tricks clang-format
-        };
+            &meta_invoke<Type, Candidate, Policy>};
+
+        if(owner->func.contains(id)) {
+            for(auto *curr = &owner->func[id]; curr; curr = curr->next.get()) {
+                if(curr->watermark == node.watermark && curr->traits == node.traits) {
+                    node.next = std::move(curr->next);
+                    *curr = std::move(node);
 
-        internal::link_func_if_required(owner, id, node);
-        return meta_factory<Type, decltype(internal::meta_func_node::prop)>{node.prop};
+                    return meta_factory<Type, decltype(internal::meta_func_node::prop)>{curr->prop};
+                }
+            }
+
+            // locally overloaded function
+            node.next = std::make_unique<internal::meta_func_node>(std::move(owner->func[id]));
+        }
+
+        owner->func[id] = std::move(node);
+        return meta_factory<Type, decltype(internal::meta_func_node::prop)>{owner->func[id].prop};
     }
 
 private:
@@ -474,16 +472,13 @@ template<typename Type>
 inline void meta_reset(const id_type id) noexcept {
     for(auto **it = internal::meta_context::global(); *it; it = &(*it)->next) {
         if(auto *node = *it; node->id == id) {
-            for(auto **curr = &node->func; *curr; *curr = std::exchange((*curr)->next, nullptr)) {
-                (*curr)->prop.clear();
-            }
-
             node->id = {};
             node->prop.clear();
             node->ctor.clear();
             node->base.clear();
             node->conv.clear();
             node->data.clear();
+            node->func.clear();
             node->dtor.dtor = nullptr;
 
             *it = std::exchange(node->next, nullptr);

+ 42 - 55
src/entt/meta/meta.hpp

@@ -804,11 +804,6 @@ struct meta_func {
     meta_func(const node_type *curr = nullptr) noexcept
         : node{curr} {}
 
-    /*! @copydoc meta_type::id */
-    [[nodiscard]] id_type id() const noexcept {
-        return node->id;
-    }
-
     /**
      * @brief Returns the number of arguments accepted by a member function.
      * @return The number of arguments accepted by the member function.
@@ -898,6 +893,14 @@ struct meta_func {
         return nullptr;
     }
 
+    /**
+     * @brief Returns the next overload of a given function, if any.
+     * @return The next overload of the given function, if any.
+     */
+    [[nodiscard]] meta_func next() const {
+        return node->next ? meta_func{node->next.get()} : meta_func{};
+    }
+
     /**
      * @brief Returns true if an object is valid, false otherwise.
      * @return True if the object is valid, false otherwise.
@@ -912,52 +915,16 @@ private:
 
 /*! @brief Opaque wrapper for types. */
 class meta_type {
-    template<typename It>
-    [[nodiscard]] auto lookup(It begin, It end, meta_any *const args, const typename internal::meta_type_node::size_type sz) const {
-        size_type extent{sz + 1u};
-        bool ambiguous{};
-        auto candidate = end;
-
-        for(; begin != end; ++begin) {
-            if(begin->second.arity == sz) {
-                size_type direct{};
-                size_type ext{};
-
-                for(size_type next{}; next < sz && next == (direct + ext) && args[next]; ++next) {
-                    const auto type = args[next].type();
-                    const auto other = begin->second.arg(next);
-
-                    if(const auto &info = other.info(); info == type.info()) {
-                        ++direct;
-                    } else {
-                        ext += type.node->base.contains(info.hash()) || type.node->conv.contains(info.hash())
-                               || (type.node->conversion_helper && other.node->conversion_helper);
-                    }
-                }
+    template<typename Func>
+    [[nodiscard]] auto lookup(meta_any *const args, const typename internal::meta_type_node::size_type sz, Func next) const {
+        using element_type = decltype(next());
 
-                if((direct + ext) == sz) {
-                    if(ext < extent) {
-                        candidate = begin;
-                        extent = ext;
-                        ambiguous = false;
-                    } else if(ext == extent) {
-                        ambiguous = true;
-                    }
-                }
-            }
-        }
-
-        return ambiguous ? end : candidate;
-    }
-
-    template<auto Member, typename... Check>
-    [[nodiscard]] std::decay_t<decltype(std::declval<internal::meta_type_node>().*Member)> old_lookup(meta_any *const args, const typename internal::meta_type_node::size_type sz, Check... check) const {
-        std::decay_t<decltype(node->*Member)> candidate{};
+        element_type candidate = nullptr;
         size_type extent{sz + 1u};
         bool ambiguous{};
 
-        for(auto *curr = (node->*Member); curr; curr = curr->next) {
-            if(((curr->id == check) && ... && (curr->arity == sz))) {
+        for(element_type curr = next(); curr; curr = next()) {
+            if(curr->arity == sz) {
                 size_type direct{};
                 size_type ext{};
 
@@ -985,7 +952,7 @@ class meta_type {
             }
         }
 
-        return (candidate && !ambiguous) ? candidate : decltype(candidate){};
+        return ambiguous ? nullptr : candidate;
     }
 
 public:
@@ -1202,8 +1169,8 @@ public:
      * @brief Returns a range to visit registered top-level functions.
      * @return An iterable range to visit registered top-level functions.
      */
-    [[nodiscard]] old_meta_range<meta_func> func() const noexcept {
-        return {node->func, nullptr};
+    [[nodiscard]] meta_range<meta_func, typename decltype(internal::meta_type_node::func)::const_iterator> func() const noexcept {
+        return {node->func.cbegin(), node->func.cend()};
     }
 
     /**
@@ -1217,7 +1184,17 @@ public:
      * @return The registered meta function for the given identifier, if any.
      */
     [[nodiscard]] meta_func func(const id_type id) const {
-        return internal::find_by<&node_type::func>(id, node);
+        if(auto it = node->func.find(id); it != node->func.cend()) {
+            return &it->second;
+        }
+
+        for(auto &&curr: base()) {
+            if(auto &&elem = curr.second.func(id); elem) {
+                return elem;
+            }
+        }
+
+        return meta_func{};
     }
 
     /**
@@ -1232,8 +1209,12 @@ public:
      * @return A wrapper containing the new instance, if any.
      */
     [[nodiscard]] meta_any construct(meta_any *const args, const size_type sz) const {
-        if(auto it = lookup(node->ctor.cbegin(), node->ctor.cend(), args, sz); it != node->ctor.cend()) {
-            return it->second.invoke(args);
+        const auto *candidate = lookup(args, sz, [first = node->ctor.cbegin(), last = node->ctor.cend()]() mutable {
+            return first == last ? nullptr : &(first++)->second;
+        });
+
+        if(candidate) {
+            return candidate->invoke(args);
         }
 
         return (sz == 0u && node->default_constructor) ? node->default_constructor() : meta_any{};
@@ -1283,8 +1264,14 @@ public:
      * @return A wrapper containing the returned value, if any.
      */
     meta_any invoke(const id_type id, meta_handle instance, meta_any *const args, const size_type sz) const {
-        if(const auto *candidate = old_lookup<&node_type::func>(args, sz, id); candidate) {
-            return candidate->invoke(std::move(instance), args);
+        if(auto it = node->func.find(id); it != node->func.cend()) {
+            const auto *candidate = lookup(args, sz, [curr = &it->second]() mutable {
+                return curr ? std::exchange(curr, curr->next.get()) : nullptr;
+            });
+
+            if(candidate) {
+                return candidate->invoke(std::move(instance), args);
+            }
         }
 
         for(auto &&curr: base()) {

+ 8 - 35
src/entt/meta/node.hpp

@@ -86,14 +86,14 @@ struct meta_data_node {
 struct meta_func_node {
     using size_type = std::size_t;
 
-    id_type id;
-    const meta_traits traits;
-    meta_func_node *next;
-    const size_type arity;
-    meta_type_node *const ret;
-    meta_type (*const arg)(const size_type) noexcept;
-    meta_any (*const invoke)(meta_handle, meta_any *const);
+    id_type watermark;
+    meta_traits traits;
+    size_type arity;
+    meta_type_node *ret;
+    meta_type (*arg)(const size_type) noexcept;
+    meta_any (*invoke)(meta_handle, meta_any *const);
     dense_map<id_type, meta_prop_node, identity> prop{};
+    std::unique_ptr<meta_func_node> next{};
 };
 
 struct meta_template_node {
@@ -122,7 +122,7 @@ struct meta_type_node {
     dense_map<id_type, meta_base_node, identity> base{};
     dense_map<id_type, meta_conv_node, identity> conv{};
     dense_map<id_type, meta_data_node, identity> data{};
-    meta_func_node *func{nullptr};
+    dense_map<id_type, meta_func_node, identity> func{};
     meta_dtor_node dtor{};
 };
 
@@ -213,33 +213,6 @@ template<typename... Args>
     return args[index + 1u];
 }
 
-template<auto Member, typename Type>
-[[nodiscard]] static std::decay_t<decltype(std::declval<internal::meta_type_node>().*Member)> find_by(const Type &info_or_id, const internal::meta_type_node *node) noexcept {
-    for(auto *curr = node->*Member; curr; curr = curr->next) {
-        if constexpr(std::is_same_v<Type, type_info>) {
-            if(*curr->type->info == info_or_id) {
-                return curr;
-            }
-        } else if constexpr(std::is_same_v<decltype(curr), meta_base_node *>) {
-            if(curr->type->id == info_or_id) {
-                return curr;
-            }
-        } else {
-            if(curr->id == info_or_id) {
-                return curr;
-            }
-        }
-    }
-
-    for(auto &&curr: node->base) {
-        if(auto *ret = find_by<Member>(info_or_id, curr.second.type); ret) {
-            return ret;
-        }
-    }
-
-    return nullptr;
-}
-
 } // namespace internal
 
 /**

+ 8 - 12
test/entt/meta/meta_func.cpp

@@ -139,13 +139,17 @@ struct MetaFunc: ::testing::Test {
         std::size_t count = 0;
 
         for(auto func: entt::resolve<func_t>().func()) {
-            count += static_cast<bool>(func);
+            for(auto curr = func.second; curr; curr = curr.next()) {
+                ++count;
+            }
         }
 
         SetUp();
 
         for(auto func: entt::resolve<func_t>().func()) {
-            count -= static_cast<bool>(func);
+            for(auto curr = func.second; curr; curr = curr.next()) {
+                --count;
+            }
         }
 
         return count;
@@ -161,7 +165,6 @@ TEST_F(MetaFunc, Functionalities) {
     func_t instance{};
 
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.id(), "f2"_hs);
     ASSERT_EQ(func.arity(), 2u);
     ASSERT_FALSE(func.is_const());
     ASSERT_FALSE(func.is_static());
@@ -200,7 +203,6 @@ TEST_F(MetaFunc, Const) {
     func_t instance{};
 
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.id(), "f1"_hs);
     ASSERT_EQ(func.arity(), 1u);
     ASSERT_TRUE(func.is_const());
     ASSERT_FALSE(func.is_static());
@@ -237,7 +239,6 @@ TEST_F(MetaFunc, RetVoid) {
     func_t instance{};
 
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.id(), "g"_hs);
     ASSERT_EQ(func.arity(), 1u);
     ASSERT_FALSE(func.is_const());
     ASSERT_FALSE(func.is_static());
@@ -272,7 +273,6 @@ TEST_F(MetaFunc, Static) {
     func_t::value = 2;
 
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.id(), "h"_hs);
     ASSERT_EQ(func.arity(), 1u);
     ASSERT_FALSE(func.is_const());
     ASSERT_TRUE(func.is_static());
@@ -308,7 +308,6 @@ TEST_F(MetaFunc, StaticRetVoid) {
     auto func = entt::resolve<func_t>().func("k"_hs);
 
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.id(), "k"_hs);
     ASSERT_EQ(func.arity(), 1u);
     ASSERT_FALSE(func.is_const());
     ASSERT_TRUE(func.is_static());
@@ -344,7 +343,6 @@ TEST_F(MetaFunc, StaticAsMember) {
     auto any = func.invoke(instance, 42);
 
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.id(), "fake_member"_hs);
     ASSERT_EQ(func.arity(), 1u);
     ASSERT_FALSE(func.is_const());
     ASSERT_FALSE(func.is_static());
@@ -368,7 +366,6 @@ TEST_F(MetaFunc, StaticAsConstMember) {
     auto any = func.invoke(std::as_const(instance));
 
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.id(), "fake_const_member"_hs);
     ASSERT_EQ(func.arity(), 0u);
     ASSERT_TRUE(func.is_const());
     ASSERT_FALSE(func.is_static());
@@ -558,7 +555,6 @@ TEST_F(MetaFunc, ExternalMemberFunction) {
     auto func = entt::resolve<func_t>().func("emplace"_hs);
 
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.id(), "emplace"_hs);
     ASSERT_EQ(func.arity(), 2u);
     ASSERT_FALSE(func.is_const());
     ASSERT_TRUE(func.is_static());
@@ -597,8 +593,8 @@ TEST_F(MetaFunc, ReRegistration) {
         .func<entt::overload<int(int, int)>(&func_t::f)>("f"_hs)
         .func<entt::overload<int(int) const>(&func_t::f)>("f"_hs);
 
-    ASSERT_FALSE(type.func("f1"_hs));
-    ASSERT_FALSE(type.func("f2"_hs));
+    ASSERT_TRUE(type.func("f1"_hs));
+    ASSERT_TRUE(type.func("f2"_hs));
     ASSERT_TRUE(type.func("f"_hs));
 
     ASSERT_TRUE(type.invoke("f"_hs, instance, 0));