Przeglądaj źródła

meta: meta_type_node is no longer static

Michele Caini 3 lat temu
rodzic
commit
93a1d65103

+ 4 - 0
TODO

@@ -11,6 +11,10 @@ DOC:
 * examples (and credits) from @alanjfs :)
 * update entity doc when the storage based model is in place
 
+TODO:
+* update doc (meta, lib)
+* update meta natvis files
+
 WIP:
 * get rid of observers, storage based views made them pointless - document alternatives
 * add storage getter for filters to views and groups

+ 32 - 26
src/entt/meta/context.hpp

@@ -1,10 +1,15 @@
 #ifndef ENTT_META_CTX_HPP
 #define ENTT_META_CTX_HPP
 
-#include "../core/attribute.h"
+#include <memory>
+#include "../container/dense_map.hpp"
+#include "../core/fwd.hpp"
+#include "../core/utility.hpp"
 
 namespace entt {
 
+class meta_ctx;
+
 /**
  * @cond TURN_OFF_DOXYGEN
  * Internal details not to be documented.
@@ -14,20 +19,11 @@ namespace internal {
 
 struct meta_type_node;
 
-struct ENTT_API meta_context {
-    // we could use the lines below but VS2017 returns with an ICE if combined with ENTT_API despite the code being valid C++
-    //     inline static meta_type_node *local = nullptr;
-    //     inline static meta_type_node **global = &local;
-
-    [[nodiscard]] static meta_type_node *&local() noexcept {
-        static meta_type_node *chain = nullptr;
-        return chain;
-    }
+struct meta_context {
+    dense_map<id_type, std::unique_ptr<meta_type_node>, identity> value{};
 
-    [[nodiscard]] static meta_type_node **&global() noexcept {
-        static meta_type_node **chain = &local();
-        return chain;
-    }
+    static inline meta_context &from(meta_ctx &ctx);
+    static inline const meta_context &from(const meta_ctx &ctx);
 };
 
 } // namespace internal
@@ -37,20 +33,30 @@ struct ENTT_API meta_context {
  * @endcond
  */
 
-/*! @brief Opaque container for a meta context. */
-struct meta_ctx {
-    /**
-     * @brief Binds the meta system to a given context.
-     * @param other A valid context to which to bind.
-     */
-    static void bind(meta_ctx other) noexcept {
-        internal::meta_context::global() = other.ctx;
-    }
-
-private:
-    internal::meta_type_node **ctx{&internal::meta_context::local()};
+/*! @brief Opaque meta context type. */
+class meta_ctx: private internal::meta_context {
+    /*! @brief Attorney idiom like model to access the base class. */
+    friend struct internal::meta_context;
 };
 
+/**
+ * @cond TURN_OFF_DOXYGEN
+ * Internal details not to be documented.
+ */
+
+inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) {
+    return ctx;
+}
+
+inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) {
+    return ctx;
+}
+
+/**
+ * Internal details not to be documented.
+ * @endcond
+ */
+
 } // namespace entt
 
 #endif

+ 26 - 60
src/entt/meta/factory.hpp

@@ -19,30 +19,6 @@
 
 namespace entt {
 
-/**
- * @cond TURN_OFF_DOXYGEN
- * Internal details not to be documented.
- */
-
-namespace internal {
-
-inline void link_type_if_required(meta_type_node *owner, const id_type id) noexcept {
-    ENTT_ASSERT((owner->id = {}, !resolve(id)), "Duplicate identifier");
-    owner->id = id;
-
-    if(!resolve(id)) {
-        owner->next = *meta_context::global();
-        *meta_context::global() = owner;
-    }
-}
-
-} // namespace internal
-
-/**
- * Internal details not to be documented.
- * @endcond
- */
-
 /**
  * @brief Meta factory to be used for reflection purposes.
  *
@@ -82,7 +58,7 @@ public:
     template<typename... Value>
     meta_factory prop(id_type key, Value &&...value) {
         (*container)[key] = internal::meta_prop_node{
-            &internal::meta_node<std::decay_t<Value>>::resolve...,
+            &internal::resolve<std::decay_t<Value>>...,
             std::forward<Value>(value)...};
 
         return *this;
@@ -108,9 +84,9 @@ class meta_factory<Type> {
             /* this is never static */
             (std::is_member_object_pointer_v<decltype(value_list_element_v<Index, Setter>)> && ... && std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
             Setter::size,
-            &internal::meta_node<std::remove_cv_t<std::remove_reference_t<data_type>>>::resolve,
+            &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
             &meta_arg<type_list<type_list_element_t<type_list_element_t<Index, args_type>::size != 1u, type_list_element_t<Index, args_type>>...>>,
-            [](meta_handle instance, meta_any value) -> bool { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
+            +[](meta_handle instance, meta_any value) -> bool { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
             &meta_getter<Type, Getter, Policy>};
 
         auto it = owner->data.insert_or_assign(id, std::move(node)).first;
@@ -120,7 +96,7 @@ class meta_factory<Type> {
 public:
     /*! @brief Default constructor. */
     meta_factory() noexcept
-        : owner{internal::meta_node<Type>::resolve()} {}
+        : owner{internal::resolve<Type>()} {}
 
     /**
      * @brief Makes a meta type _searchable_.
@@ -128,7 +104,8 @@ public:
      * @return An extended meta factory for the given type.
      */
     auto type(const id_type id = type_hash<Type>::value()) noexcept {
-        internal::link_type_if_required(owner, id);
+        ENTT_ASSERT(owner->id == id || !resolve(id), "Duplicate identifier");
+        owner->id = id;
         return meta_factory<Type, decltype(internal::meta_type_node::prop)>{owner->prop};
     }
 
@@ -145,8 +122,8 @@ public:
         static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>, "Invalid base type");
 
         owner->base[type_id<Base>().hash()] = internal::meta_base_node{
-            &internal::meta_node<Base>::resolve,
-            [](meta_any other) noexcept -> meta_any {
+            &internal::resolve<Base>,
+            +[](meta_any other) noexcept -> meta_any {
                 if(auto *ptr = other.data(); ptr) {
                     return forward_as_meta(*static_cast<Base *>(static_cast<Type *>(ptr)));
                 }
@@ -174,7 +151,7 @@ public:
         using conv_type = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
 
         owner->conv[type_id<conv_type>().hash()] = internal::meta_conv_node{
-            [](const meta_any &instance) -> meta_any {
+            +[](const meta_any &instance) -> meta_any {
                 return forward_as_meta(std::invoke(Candidate, *static_cast<const Type *>(instance.data())));
             }};
 
@@ -195,7 +172,7 @@ public:
         using conv_type = std::remove_cv_t<std::remove_reference_t<To>>;
 
         owner->conv[type_id<conv_type>().hash()] = internal::meta_conv_node{
-            [](const meta_any &instance) -> meta_any {
+            +[](const meta_any &instance) -> meta_any {
                 return forward_as_meta(static_cast<To>(*static_cast<const Type *>(instance.data())));
             }};
 
@@ -272,7 +249,7 @@ public:
     template<auto Func>
     auto dtor() noexcept {
         static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
-        owner->dtor.dtor = [](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
+        owner->dtor.dtor = +[](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
         return meta_factory<Type>{};
     }
 
@@ -298,7 +275,7 @@ public:
                 /* this is never static */
                 std::is_const_v<data_type> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
                 1u,
-                &internal::meta_node<std::remove_const_t<data_type>>::resolve,
+                &internal::resolve<std::remove_const_t<data_type>>,
                 &meta_arg<type_list<std::remove_const_t<data_type>>>,
                 &meta_setter<Type, Data>,
                 &meta_getter<Type, Data, Policy>};
@@ -311,7 +288,7 @@ public:
             internal::meta_data_node node{
                 ((std::is_same_v<Type, std::remove_const_t<data_type>> || std::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
                 1u,
-                &internal::meta_node<std::remove_const_t<data_type>>::resolve,
+                &internal::resolve<std::remove_const_t<data_type>>,
                 &meta_arg<type_list<std::remove_const_t<data_type>>>,
                 &meta_setter<Type, Data>,
                 &meta_getter<Type, Data, Policy>};
@@ -351,7 +328,7 @@ public:
                 /* this is never static */
                 internal::meta_traits::is_const,
                 0u,
-                &internal::meta_node<std::remove_cv_t<std::remove_reference_t<data_type>>>::resolve,
+                &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
                 &meta_arg<type_list<>>,
                 &meta_setter<Type, Setter>,
                 &meta_getter<Type, Getter, Policy>};
@@ -365,7 +342,7 @@ public:
                 /* this is never static nor const */
                 internal::meta_traits::is_none,
                 1u,
-                &internal::meta_node<std::remove_cv_t<std::remove_reference_t<data_type>>>::resolve,
+                &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
                 &meta_arg<type_list<type_list_element_t<args_type::size != 1u, args_type>>>,
                 &meta_setter<Type, Setter>,
                 &meta_getter<Type, Getter, Policy>};
@@ -419,7 +396,7 @@ public:
             type_id<type_list_cat_t<type_list<typename descriptor::return_type>, typename 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),
             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,
+            &internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>,
             &meta_arg<typename descriptor::args_type>,
             &meta_invoke<Type, Candidate, Policy>};
 
@@ -458,7 +435,7 @@ private:
  */
 template<typename Type>
 [[nodiscard]] auto meta() noexcept {
-    auto *const node = internal::meta_node<Type>::resolve();
+    auto *const node = internal::resolve<Type>();
     // extended meta factory to allow assigning properties to opaque meta types
     return meta_factory<Type, decltype(internal::meta_type_node::prop)>{node->prop};
 }
@@ -470,25 +447,16 @@ template<typename Type>
  * well as its constructors, destructors and conversion functions if any.<br/>
  * Base classes aren't reset but the link between the two types is removed.
  *
- * The type is also removed from the list of searchable types.
+ * The type is also removed from the set of searchable types.
  *
  * @param id Unique identifier.
  */
 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) {
-            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);
-
-            break;
+    auto &&context = internal::meta_context::from(locator<meta_ctx>::value_or());
+
+    for(auto it = context.value.begin(); it != context.value.end(); ++it) {
+        if(it->second->id == id) {
+            it = context.value.erase(it);
         }
     }
 }
@@ -502,18 +470,16 @@ inline void meta_reset(const id_type id) noexcept {
  */
 template<typename Type>
 void meta_reset() noexcept {
-    meta_reset(internal::meta_node<Type>::resolve()->id);
+    internal::meta_context::from(locator<meta_ctx>::value_or()).value.erase(type_id<Type>().hash());
 }
 
 /**
- * @brief Resets all searchable types.
+ * @brief Resets all meta types.
  *
  * @sa meta_reset
  */
 inline void meta_reset() noexcept {
-    while(*internal::meta_context::global()) {
-        meta_reset((*internal::meta_context::global())->id);
-    }
+    internal::meta_context::from(locator<meta_ctx>::value_or()).value.clear();
 }
 
 } // namespace entt

+ 10 - 10
src/entt/meta/meta.hpp

@@ -45,7 +45,7 @@ public:
      */
     template<typename Type>
     meta_sequence_container(std::in_place_type_t<Type>, any instance) noexcept
-        : value_type_node{&internal::meta_node<typename Type::value_type>::resolve},
+        : value_type_node{&internal::resolve<typename Type::value_type>},
           size_fn{&meta_sequence_container_traits<Type>::size},
           resize_fn{&meta_sequence_container_traits<Type>::resize},
           iter_fn{&meta_sequence_container_traits<Type>::iter},
@@ -93,9 +93,9 @@ public:
     template<typename Type>
     meta_associative_container(std::in_place_type_t<Type>, any instance) noexcept
         : key_only_container{meta_associative_container_traits<Type>::key_only},
-          key_type_node{&internal::meta_node<typename Type::key_type>::resolve},
+          key_type_node{&internal::resolve<typename Type::key_type>},
           mapped_type_node{nullptr},
-          value_type_node{&internal::meta_node<typename Type::value_type>::resolve},
+          value_type_node{&internal::resolve<typename Type::value_type>},
           size_fn{&meta_associative_container_traits<Type>::size},
           clear_fn{&meta_associative_container_traits<Type>::clear},
           iter_fn{&meta_associative_container_traits<Type>::iter},
@@ -103,7 +103,7 @@ public:
           find_fn{&meta_associative_container_traits<Type>::find},
           storage{std::move(instance)} {
         if constexpr(!meta_associative_container_traits<Type>::key_only) {
-            mapped_type_node = &internal::meta_node<typename Type::mapped_type>::resolve;
+            mapped_type_node = &internal::resolve<typename Type::mapped_type>;
         }
     }
 
@@ -207,7 +207,7 @@ public:
     template<typename Type, typename... Args>
     explicit meta_any(std::in_place_type_t<Type>, Args &&...args)
         : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
-          node{internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve()},
+          node{internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>()},
           vtable{&basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>} {}
 
     /**
@@ -218,7 +218,7 @@ public:
     template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
     meta_any(Type &&value)
         : storage{std::forward<Type>(value)},
-          node{internal::meta_node<std::decay_t<Type>>::resolve()},
+          node{internal::resolve<std::decay_t<Type>>()},
           vtable{&basic_vtable<std::decay_t<Type>>} {}
 
     /**
@@ -430,7 +430,7 @@ public:
         if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
             return meta_any{};
         } else {
-            return allow_cast(internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve());
+            return allow_cast(internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>());
         }
     }
 
@@ -442,9 +442,9 @@ public:
     template<typename Type>
     bool allow_cast() {
         if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
-            return allow_cast(internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve()) && (storage.data() != nullptr);
+            return allow_cast(internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>()) && (storage.data() != nullptr);
         } else {
-            return allow_cast(internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve());
+            return allow_cast(internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>());
         }
     }
 
@@ -454,7 +454,7 @@ public:
         release();
         vtable = &basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
         storage.emplace<Type>(std::forward<Args>(args)...);
-        node = internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve();
+        node = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>();
     }
 
     /*! @copydoc any::assign */

+ 80 - 66
src/entt/meta/node.hpp

@@ -12,6 +12,8 @@
 #include "../core/type_info.hpp"
 #include "../core/type_traits.hpp"
 #include "../core/utility.hpp"
+#include "../locator/locator.hpp"
+#include "context.hpp"
 #include "type_traits.hpp"
 
 namespace entt {
@@ -109,13 +111,12 @@ struct meta_type_node {
 
     const type_info *info;
     id_type id;
-    const meta_traits traits;
-    meta_type_node *next;
-    const size_type size_of;
-    meta_type_node *(*const remove_pointer)() noexcept;
-    meta_any (*const default_constructor)();
-    double (*const conversion_helper)(void *, const void *);
-    meta_any (*const from_void)(void *, const void *);
+    meta_traits traits;
+    size_type size_of;
+    meta_type_node *(*remove_pointer)() noexcept;
+    meta_any (*default_constructor)();
+    double (*conversion_helper)(void *, const void *);
+    meta_any (*from_void)(void *, const void *);
     meta_template_node templ;
     dense_map<id_type, meta_prop_node, identity> prop{};
     dense_map<id_type, meta_ctor_node, identity> ctor{};
@@ -126,67 +127,87 @@ struct meta_type_node {
     meta_dtor_node dtor{};
 };
 
+template<typename Type>
+meta_type_node *resolve() noexcept;
+
 template<typename... Args>
-meta_type_node *meta_arg_node(type_list<Args...>, const std::size_t index) noexcept;
+[[nodiscard]] meta_type_node *meta_arg_node(type_list<Args...>, const std::size_t index) noexcept {
+    meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::resolve<std::remove_cv_t<std::remove_reference_t<Args>>>()...};
+    return args[index + 1u];
+}
 
 template<typename Type>
-class ENTT_API meta_node {
+[[nodiscard]] auto *meta_default_constructor() noexcept {
     static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
 
-    [[nodiscard]] static auto *meta_default_constructor() noexcept {
-        if constexpr(std::is_default_constructible_v<Type>) {
-            return +[]() { return meta_any{std::in_place_type<Type>}; };
-        } else {
-            return static_cast<std::decay_t<decltype(meta_type_node::default_constructor)>>(nullptr);
-        }
+    if constexpr(std::is_default_constructible_v<Type>) {
+        return +[]() { return meta_any{std::in_place_type<Type>}; };
+    } else {
+        return static_cast<std::decay_t<decltype(meta_type_node::default_constructor)>>(nullptr);
     }
+}
+
+template<typename Type>
+[[nodiscard]] auto *meta_conversion_helper() noexcept {
+    static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
 
-    [[nodiscard]] static auto *meta_conversion_helper() noexcept {
-        if constexpr(std::is_arithmetic_v<Type>) {
-            return +[](void *bin, const void *value) {
-                return bin ? static_cast<double>(*static_cast<Type *>(bin) = static_cast<Type>(*static_cast<const double *>(value))) : static_cast<double>(*static_cast<const Type *>(value));
-            };
-        } else if constexpr(std::is_enum_v<Type>) {
-            return +[](void *bin, const void *value) {
-                return bin ? static_cast<double>(*static_cast<Type *>(bin) = static_cast<Type>(static_cast<std::underlying_type_t<Type>>(*static_cast<const double *>(value)))) : static_cast<double>(*static_cast<const Type *>(value));
-            };
-        } else {
-            return static_cast<std::decay_t<decltype(meta_type_node::conversion_helper)>>(nullptr);
-        }
+    if constexpr(std::is_arithmetic_v<Type>) {
+        return +[](void *bin, const void *value) {
+            return bin ? static_cast<double>(*static_cast<Type *>(bin) = static_cast<Type>(*static_cast<const double *>(value))) : static_cast<double>(*static_cast<const Type *>(value));
+        };
+    } else if constexpr(std::is_enum_v<Type>) {
+        return +[](void *bin, const void *value) {
+            return bin ? static_cast<double>(*static_cast<Type *>(bin) = static_cast<Type>(static_cast<std::underlying_type_t<Type>>(*static_cast<const double *>(value)))) : static_cast<double>(*static_cast<const Type *>(value));
+        };
+    } else {
+        return static_cast<std::decay_t<decltype(meta_type_node::conversion_helper)>>(nullptr);
     }
+}
+
+template<typename Type>
+[[nodiscard]] auto *meta_from_void() noexcept {
+    static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
 
-    [[nodiscard]] static auto *meta_from_void() noexcept {
-        if constexpr(std::is_same_v<Type, void> || std::is_function_v<Type>) {
-            return static_cast<std::decay_t<decltype(meta_type_node::from_void)>>(nullptr);
-        } else {
-            return +[](void *element, const void *as_const) {
-                using value_type = std::decay_t<Type>;
+    if constexpr(std::is_same_v<Type, void> || std::is_function_v<Type>) {
+        return static_cast<std::decay_t<decltype(meta_type_node::from_void)>>(nullptr);
+    } else {
+        return +[](void *element, const void *as_const) {
+            using value_type = std::decay_t<Type>;
 
-                if(element) {
-                    return meta_any{std::in_place_type<value_type &>, *static_cast<value_type *>(element)};
-                }
+            if(element) {
+                return meta_any{std::in_place_type<value_type &>, *static_cast<value_type *>(element)};
+            }
 
-                return meta_any{std::in_place_type<const value_type &>, *static_cast<const value_type *>(as_const)};
-            };
-        }
+            return meta_any{std::in_place_type<const value_type &>, *static_cast<const value_type *>(as_const)};
+        };
     }
+}
+
+template<typename Type>
+[[nodiscard]] auto meta_template_info() noexcept {
+    static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
 
-    [[nodiscard]] static auto meta_template_info() noexcept {
-        if constexpr(is_complete_v<meta_template_traits<Type>>) {
-            return meta_template_node{
-                meta_template_traits<Type>::args_type::size,
-                &meta_node<typename meta_template_traits<Type>::class_type>::resolve,
-                +[](const std::size_t index) noexcept -> meta_type_node * { return meta_arg_node(typename meta_template_traits<Type>::args_type{}, index); }};
-        } else {
-            return meta_template_node{};
-        }
+    if constexpr(is_complete_v<meta_template_traits<Type>>) {
+        return meta_template_node{
+            meta_template_traits<Type>::args_type::size,
+            &resolve<typename meta_template_traits<Type>::class_type>,
+            +[](const std::size_t index) noexcept -> meta_type_node * { return meta_arg_node(typename meta_template_traits<Type>::args_type{}, index); }};
+    } else {
+        return meta_template_node{};
     }
+}
 
-public:
-    [[nodiscard]] static meta_type_node *resolve() noexcept {
-        static meta_type_node node{
+template<typename Type>
+[[nodiscard]] meta_type_node *resolve() noexcept {
+    static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
+
+    auto &&context = meta_context::from(locator<meta_ctx>::value_or());
+    auto it = context.value.find(type_id<Type>().hash());
+
+    if(it == context.value.end()) {
+        meta_type_node node{
             &type_id<Type>(),
-            {},
+            type_id<Type>().hash(),
             (std::is_arithmetic_v<Type> ? internal::meta_traits::is_arithmetic : internal::meta_traits::is_none)
                 | (std::is_integral_v<Type> ? internal::meta_traits::is_integral : internal::meta_traits::is_none)
                 | (std::is_signed_v<Type> ? internal::meta_traits::is_signed : internal::meta_traits::is_none)
@@ -196,24 +217,17 @@ public:
                 | (is_meta_pointer_like_v<Type> ? internal::meta_traits::is_meta_pointer_like : internal::meta_traits::is_none)
                 | (is_complete_v<meta_sequence_container_traits<Type>> ? internal::meta_traits::is_meta_sequence_container : internal::meta_traits::is_none)
                 | (is_complete_v<meta_associative_container_traits<Type>> ? internal::meta_traits::is_meta_associative_container : internal::meta_traits::is_none),
-            nullptr,
             size_of_v<Type>,
-            &meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
-            meta_default_constructor(),
-            meta_conversion_helper(),
-            meta_from_void(),
-            meta_template_info()
-            // tricks clang-format
-        };
+            &resolve<std::remove_cv_t<std::remove_pointer_t<Type>>>,
+            meta_default_constructor<Type>(),
+            meta_conversion_helper<Type>(),
+            meta_from_void<Type>(),
+            meta_template_info<Type>()};
 
-        return &node;
+        it = context.value.insert_or_assign(node.info->hash(), std::make_unique<meta_type_node>(std::move(node))).first;
     }
-};
 
-template<typename... Args>
-[[nodiscard]] meta_type_node *meta_arg_node(type_list<Args...>, const std::size_t index) noexcept {
-    meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_node<std::remove_cv_t<std::remove_reference_t<Args>>>::resolve()...};
-    return args[index + 1u];
+    return it->second.get();
 }
 
 } // namespace internal

+ 10 - 51
src/entt/meta/range.hpp

@@ -16,52 +16,19 @@ namespace entt {
 
 namespace internal {
 
-template<typename Type, typename Node>
-struct old_meta_range_iterator final {
-    using difference_type = std::ptrdiff_t;
-    using value_type = Type;
-    using pointer = input_iterator_pointer<value_type>;
-    using reference = value_type;
-    using iterator_category = std::input_iterator_tag;
-    using node_type = Node;
-
-    old_meta_range_iterator() noexcept
-        : it{} {}
-
-    old_meta_range_iterator(node_type *head) noexcept
-        : it{head} {}
-
-    old_meta_range_iterator &operator++() noexcept {
-        return (it = it->next), *this;
-    }
-
-    old_meta_range_iterator operator++(int) noexcept {
-        old_meta_range_iterator orig = *this;
-        return ++(*this), orig;
-    }
-
-    [[nodiscard]] reference operator*() const noexcept {
-        return it;
-    }
-
-    [[nodiscard]] pointer operator->() const noexcept {
-        return operator*();
-    }
-
-    [[nodiscard]] bool operator==(const old_meta_range_iterator &other) const noexcept {
-        return it == other.it;
+template<typename Type, typename It>
+class meta_range_iterator final {
+    template<typename Value>
+    auto to_value(int, const Value &value) const -> decltype(*value, Type{}) {
+        return &*it->second;
     }
 
-    [[nodiscard]] bool operator!=(const old_meta_range_iterator &other) const noexcept {
-        return !(*this == other);
+    template<typename Value>
+    Type to_value(char, const Value &value) const {
+        return &it->second;
     }
 
-private:
-    node_type *it;
-};
-
-template<typename Type, typename It>
-struct meta_range_iterator final {
+public:
     using difference_type = std::ptrdiff_t;
     using value_type = std::pair<id_type, Type>;
     using pointer = input_iterator_pointer<value_type>;
@@ -84,7 +51,7 @@ struct meta_range_iterator final {
     }
 
     [[nodiscard]] reference operator*() const noexcept {
-        return std::make_pair(it->first, &it->second);
+        return std::make_pair(it->first, to_value(0, it->second));
     }
 
     [[nodiscard]] pointer operator->() const noexcept {
@@ -110,14 +77,6 @@ private:
  * @endcond
  */
 
-/**
- * @brief Iterable range to use to iterate all types of meta objects.
- * @tparam Type Type of meta objects returned.
- * @tparam Node Type of meta nodes iterated.
- */
-template<typename Type, typename Node = typename Type::node_type>
-using old_meta_range = iterable_adaptor<internal::old_meta_range_iterator<Type, Node>>;
-
 /**
  * @brief Iterable range to use to iterate all types of meta objects.
  * @tparam Type Type of meta objects returned.

+ 11 - 9
src/entt/meta/resolve.hpp

@@ -3,6 +3,7 @@
 
 #include <type_traits>
 #include "../core/type_info.hpp"
+#include "../locator/locator.hpp"
 #include "context.hpp"
 #include "meta.hpp"
 #include "node.hpp"
@@ -17,15 +18,16 @@ namespace entt {
  */
 template<typename Type>
 [[nodiscard]] meta_type resolve() noexcept {
-    return internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve();
+    return internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>();
 }
 
 /**
  * @brief Returns a range to use to visit all meta types.
  * @return An iterable range to use to visit all meta types.
  */
-[[nodiscard]] inline old_meta_range<meta_type> resolve() noexcept {
-    return {*internal::meta_context::global(), nullptr};
+[[nodiscard]] inline meta_range<meta_type, typename decltype(internal::meta_context::value)::const_iterator> resolve() noexcept {
+    auto &&context = internal::meta_context::from(locator<meta_ctx>::value_or());
+    return {context.value.cbegin(), context.value.cend()};
 }
 
 /**
@@ -35,8 +37,8 @@ template<typename Type>
  */
 [[nodiscard]] inline meta_type resolve(const id_type id) noexcept {
     for(auto &&curr: resolve()) {
-        if(curr.id() == id) {
-            return curr;
+        if(curr.second.id() == id) {
+            return curr.second;
         }
     }
 
@@ -49,10 +51,10 @@ template<typename Type>
  * @return The meta type associated with the given type info object, if any.
  */
 [[nodiscard]] inline meta_type resolve(const type_info &info) noexcept {
-    for(auto &&curr: resolve()) {
-        if(curr.info() == info) {
-            return curr;
-        }
+    auto &&context = internal::meta_context::from(locator<meta_ctx>::value_or());
+
+    if(auto it = context.value.find(info.hash()); it != context.value.cend()) {
+        return it->second.get();
     }
 
     return {};

+ 1 - 1
test/entt/meta/meta_base.cpp

@@ -181,7 +181,7 @@ TEST_F(MetaBase, TransferWithMutatingThis) {
 TEST_F(MetaBase, ReRegistration) {
     SetUp();
 
-    auto *node = entt::internal::meta_node<derived_t>::resolve();
+    auto *node = entt::internal::resolve<derived_t>();
 
     ASSERT_FALSE(node->base.empty());
     ASSERT_EQ(node->base.size(), 2u);

+ 1 - 1
test/entt/meta/meta_conv.cpp

@@ -62,7 +62,7 @@ TEST_F(MetaConv, Functionalities) {
 TEST_F(MetaConv, ReRegistration) {
     SetUp();
 
-    auto *node = entt::internal::meta_node<clazz_t>::resolve();
+    auto *node = entt::internal::resolve<clazz_t>();
 
     ASSERT_FALSE(node->conv.empty());
     ASSERT_EQ(node->conv.size(), 3u);

+ 1 - 1
test/entt/meta/meta_ctor.cpp

@@ -205,7 +205,7 @@ TEST_F(MetaCtor, NonDefaultConstructibleType) {
 TEST_F(MetaCtor, ReRegistration) {
     SetUp();
 
-    auto *node = entt::internal::meta_node<double>::resolve();
+    auto *node = entt::internal::resolve<double>();
 
     ASSERT_NE(node->ctor, nullptr);
     // implicitly generated default constructor is not cleared

+ 1 - 1
test/entt/meta/meta_data.cpp

@@ -643,7 +643,7 @@ TEST_F(MetaData, ReRegistration) {
 
     SetUp();
 
-    auto *node = entt::internal::meta_node<base_t>::resolve();
+    auto *node = entt::internal::resolve<base_t>();
     auto type = entt::resolve<base_t>();
 
     ASSERT_FALSE(node->data.empty());

+ 1 - 1
test/entt/meta/meta_dtor.cpp

@@ -101,7 +101,7 @@ TEST_F(MetaDtor, AsRefConstruction) {
 TEST_F(MetaDtor, ReRegistration) {
     SetUp();
 
-    auto *node = entt::internal::meta_node<clazz_t>::resolve();
+    auto *node = entt::internal::resolve<clazz_t>();
 
     ASSERT_NE(node->dtor.dtor, nullptr);
 

+ 1 - 1
test/entt/meta/meta_prop.cpp

@@ -86,7 +86,7 @@ TEST_F(MetaProp, ReRegistration) {
 
     SetUp();
 
-    auto *node = entt::internal::meta_node<base_1_t>::resolve();
+    auto *node = entt::internal::resolve<base_1_t>();
     auto type = entt::resolve<base_1_t>();
 
     ASSERT_FALSE(node->prop.empty());

+ 7 - 5
test/entt/meta/meta_range.cpp

@@ -1,6 +1,7 @@
 #include <type_traits>
 #include <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
+#include <entt/locator/locator.hpp>
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
 #include <entt/meta/range.hpp>
@@ -22,21 +23,22 @@ struct MetaRange: ::testing::Test {
 TEST_F(MetaRange, Range) {
     using namespace entt::literals;
 
-    entt::old_meta_range<entt::meta_type> range{entt::internal::meta_context::local(), nullptr};
+    auto range = entt::resolve();
     auto it = range.begin();
 
     ASSERT_NE(it, range.end());
     ASSERT_TRUE(it != range.end());
     ASSERT_FALSE(it == range.end());
 
-    ASSERT_EQ(it->info(), entt::resolve<double>().info());
-    ASSERT_EQ((++it)->info(), entt::resolve("int"_hs).info());
-    ASSERT_EQ((it++)->info(), entt::resolve<int>().info());
+    ASSERT_EQ(it->second.info(), entt::resolve<int>().info());
+    ASSERT_EQ((++it)->second.info(), entt::resolve("double"_hs).info());
+    ASSERT_EQ((it++)->second.info(), entt::resolve<double>().info());
 
     ASSERT_EQ(it, range.end());
 }
 
 TEST_F(MetaRange, EmptyRange) {
-    entt::old_meta_range<entt::meta_data> range{};
+    entt::meta_reset();
+    auto range = entt::resolve();
     ASSERT_EQ(range.begin(), range.end());
 }

+ 10 - 9
test/entt/meta/meta_type.cpp

@@ -5,6 +5,7 @@
 #include <vector>
 #include <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
+#include <entt/locator/locator.hpp>
 #include <entt/core/type_info.hpp>
 #include <entt/core/utility.hpp>
 #include <entt/meta/container.hpp>
@@ -191,15 +192,15 @@ TEST_F(MetaType, Resolve) {
 
     auto range = entt::resolve();
     // it could be "char"_hs rather than entt::hashed_string::value("char") if it weren't for a bug in VS2017
-    const auto it = std::find_if(range.begin(), range.end(), [](auto type) { return type.id() == entt::hashed_string::value("clazz"); });
+    const auto it = std::find_if(range.begin(), range.end(), [](auto curr) { return curr.second.id() == entt::hashed_string::value("clazz"); });
 
     ASSERT_NE(it, range.end());
-    ASSERT_EQ(*it, entt::resolve<clazz_t>());
+    ASSERT_EQ(it->second, entt::resolve<clazz_t>());
 
     bool found = false;
 
     for(auto curr: entt::resolve()) {
-        found = found || curr == entt::resolve<double>();
+        found = found || curr.second == entt::resolve<double>();
     }
 
     ASSERT_TRUE(found);
@@ -637,7 +638,7 @@ TEST_F(MetaType, PropertiesAndCornerCases) {
 TEST_F(MetaType, ResetAndReRegistrationAfterReset) {
     using namespace entt::literals;
 
-    ASSERT_NE(*entt::internal::meta_context::global(), nullptr);
+    ASSERT_FALSE(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()).value.empty());
 
     entt::meta_reset<double>();
     entt::meta_reset<unsigned int>();
@@ -654,7 +655,7 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) {
     ASSERT_FALSE(entt::resolve("derived"_hs));
     ASSERT_FALSE(entt::resolve("clazz"_hs));
 
-    ASSERT_EQ(*entt::internal::meta_context::global(), nullptr);
+    ASSERT_TRUE(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()).value.empty());
 
     ASSERT_FALSE(entt::resolve<clazz_t>().prop(static_cast<entt::id_type>(property_t::value)));
     // implicitly generated default constructor is not cleared
@@ -687,14 +688,14 @@ TEST_F(MetaType, ReRegistration) {
 
     int count = 0;
 
-    for(auto type: entt::resolve()) {
-        count += static_cast<bool>(type);
+    for([[maybe_unused]] auto type: entt::resolve()) {
+        ++count;
     }
 
     SetUp();
 
-    for(auto type: entt::resolve()) {
-        count -= static_cast<bool>(type);
+    for([[maybe_unused]] auto type: entt::resolve()) {
+        --count;
     }
 
     ASSERT_EQ(count, 0);

+ 4 - 0
test/lib/meta/lib.cpp

@@ -8,6 +8,10 @@ position create_position(int x, int y) {
     return position{x, y};
 }
 
+ENTT_API void share(entt::locator<entt::meta_ctx>::node_type handle) {
+    entt::locator<entt::meta_ctx>::reset(handle);
+}
+
 ENTT_API void set_up() {
     using namespace entt::literals;
 

+ 5 - 0
test/lib/meta/main.cpp

@@ -6,6 +6,7 @@
 #include <entt/meta/resolve.hpp>
 #include "types.h"
 
+ENTT_API void share(entt::locator<entt::meta_ctx>::node_type);
 ENTT_API void set_up();
 ENTT_API void tear_down();
 ENTT_API entt::meta_any wrap_int(int);
@@ -16,6 +17,7 @@ TEST(Lib, Meta) {
     ASSERT_FALSE(entt::resolve("position"_hs));
     ASSERT_FALSE(entt::resolve("velocity"_hs));
 
+    share(entt::locator<entt::meta_ctx>::handle());
     set_up();
     entt::meta<double>().conv<int>();
 
@@ -40,6 +42,9 @@ TEST(Lib, Meta) {
     ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
     ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);
 
+    pos.reset();
+    vel.reset();
+
     ASSERT_EQ(wrap_int(42).type(), entt::resolve<int>());
     ASSERT_EQ(wrap_int(42).cast<int>(), 42);
 

+ 2 - 0
test/lib/meta_plugin/main.cpp

@@ -3,6 +3,7 @@
 #include <gtest/gtest.h>
 #include <cr.h>
 #include <entt/core/hashed_string.hpp>
+#include <entt/locator/locator.hpp>
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
 #include <entt/meta/resolve.hpp>
@@ -14,6 +15,7 @@ TEST(Lib, Meta) {
     ASSERT_FALSE(entt::resolve("position"_hs));
 
     userdata ud{};
+    ud.ctx = entt::locator<entt::meta_ctx>::handle();
 
     cr_plugin ctx;
     cr_plugin_load(ctx, PLUGIN);

+ 2 - 1
test/lib/meta_plugin/plugin.cpp

@@ -1,5 +1,6 @@
 #include <cr.h>
 #include <entt/core/hashed_string.hpp>
+#include <entt/locator/locator.hpp>
 #include <entt/meta/context.hpp>
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
@@ -33,7 +34,7 @@ void tear_down() {
 CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) {
     switch(operation) {
     case CR_LOAD:
-        entt::meta_ctx::bind(static_cast<userdata *>(ctx->userdata)->ctx);
+        entt::locator<entt::meta_ctx>::reset(static_cast<userdata *>(ctx->userdata)->ctx);
         set_up();
         break;
     case CR_STEP:

+ 2 - 1
test/lib/meta_plugin/types.h

@@ -1,6 +1,7 @@
 #ifndef ENTT_LIB_META_PLUGIN_TYPES_H
 #define ENTT_LIB_META_PLUGIN_TYPES_H
 
+#include <entt/locator/locator.hpp>
 #include <entt/meta/meta.hpp>
 
 struct position {
@@ -14,7 +15,7 @@ struct velocity {
 };
 
 struct userdata {
-    entt::meta_ctx ctx;
+    entt::locator<entt::meta_ctx>::node_type ctx;
     entt::meta_any any;
 };
 

+ 1 - 0
test/lib/meta_plugin_std/main.cpp

@@ -14,6 +14,7 @@ TEST(Lib, Meta) {
     ASSERT_FALSE(entt::resolve("position"_hs));
 
     userdata ud{};
+    ud.ctx = entt::locator<entt::meta_ctx>::handle();
 
     cr_plugin ctx;
     cr_plugin_load(ctx, PLUGIN);

+ 1 - 1
test/lib/meta_plugin_std/plugin.cpp

@@ -33,7 +33,7 @@ void tear_down() {
 CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) {
     switch(operation) {
     case CR_LOAD:
-        entt::meta_ctx::bind(static_cast<userdata *>(ctx->userdata)->ctx);
+        entt::locator<entt::meta_ctx>::reset(static_cast<userdata *>(ctx->userdata)->ctx);
         set_up();
         break;
     case CR_STEP:

+ 2 - 2
test/lib/meta_plugin_std/types.h

@@ -15,7 +15,7 @@ struct custom_type_hash;
         static constexpr entt::id_type value() noexcept { \
             return entt::basic_hashed_string<std::remove_const_t<std::remove_pointer_t<std::decay_t<decltype(#clazz)>>>>{#clazz}; \
         } \
-    };
+    }
 
 struct position {
     int x;
@@ -28,7 +28,7 @@ struct velocity {
 };
 
 struct userdata {
-    entt::meta_ctx ctx;
+    entt::locator<entt::meta_ctx>::node_type ctx;
     entt::meta_any any;
 };