Преглед на файлове

meta: use the hot/cold model with meta_type_node

Michele Caini преди 3 години
родител
ревизия
e4f6293f42

+ 3 - 0
TODO

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

+ 1 - 2
src/entt/meta/context.hpp

@@ -1,7 +1,6 @@
 #ifndef ENTT_META_CTX_HPP
 #define ENTT_META_CTX_HPP
 
-#include <memory>
 #include "../container/dense_map.hpp"
 #include "../core/fwd.hpp"
 #include "../core/utility.hpp"
@@ -20,7 +19,7 @@ namespace internal {
 struct meta_type_node;
 
 struct meta_context {
-    dense_map<id_type, std::unique_ptr<meta_type_node>, identity> value{};
+    dense_map<id_type, meta_type_node, identity> value{};
 
     static inline meta_context &from(meta_ctx &ctx);
     static inline const meta_context &from(const meta_ctx &ctx);

+ 4 - 4
src/entt/meta/factory.hpp

@@ -11,6 +11,7 @@
 #include "../core/fwd.hpp"
 #include "../core/type_info.hpp"
 #include "../core/type_traits.hpp"
+#include "context.hpp"
 #include "meta.hpp"
 #include "node.hpp"
 #include "policy.hpp"
@@ -125,7 +126,7 @@ class meta_factory<Type> {
 public:
     /*! @brief Default constructor. */
     meta_factory() noexcept
-        : owner{internal::resolve<Type>()} {}
+        : owner{&internal::meta_context::from(locator<meta_ctx>::value_or()).value.try_emplace(type_id<Type>().hash(), internal::resolve<Type>()).first->second} {}
 
     /**
      * @brief Assigns a custom unique identifier to a meta type.
@@ -472,9 +473,8 @@ private:
  */
 template<typename Type>
 [[nodiscard]] auto meta() noexcept {
-    auto *const node = internal::resolve<Type>();
     // extended meta factory to allow assigning properties to opaque meta types
-    return meta_factory<Type, internal::meta_type_node>{*node};
+    return meta_factory<Type, internal::meta_type_node>{internal::meta_context::from(locator<meta_ctx>::value_or()).value.try_emplace(type_id<Type>().hash(), internal::resolve<Type>()).first->second};
 }
 
 /**
@@ -492,7 +492,7 @@ inline void meta_reset(const id_type id) noexcept {
     auto &&context = internal::meta_context::from(locator<meta_ctx>::value_or());
 
     for(auto it = context.value.begin(); it != context.value.end();) {
-        if(it->second->id == id) {
+        if(it->second.id == id) {
             it = context.value.erase(it);
         } else {
             ++it;

+ 100 - 100
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::resolve<typename Type::value_type>},
+        : 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},
@@ -64,7 +64,7 @@ public:
     [[nodiscard]] inline explicit operator bool() const noexcept;
 
 private:
-    internal::meta_type_node *(*value_type_node)() noexcept = nullptr;
+    internal::meta_type_node value_type_node = {};
     size_type (*size_fn)(const any &) noexcept = nullptr;
     bool (*resize_fn)(any &, size_type) = nullptr;
     iterator (*iter_fn)(any &, const bool) = nullptr;
@@ -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::resolve<typename Type::key_type>},
-          mapped_type_node{nullptr},
-          value_type_node{&internal::resolve<typename Type::value_type>},
+          key_type_node{internal::resolve<typename Type::key_type>()},
+          mapped_type_node{},
+          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::resolve<typename Type::mapped_type>;
+            mapped_type_node = internal::resolve<typename Type::mapped_type>();
         }
     }
 
@@ -122,9 +122,9 @@ public:
 
 private:
     bool key_only_container{};
-    internal::meta_type_node *(*key_type_node)() noexcept = nullptr;
-    internal::meta_type_node *(*mapped_type_node)() noexcept = nullptr;
-    internal::meta_type_node *(*value_type_node)() noexcept = nullptr;
+    internal::meta_type_node key_type_node = {};
+    internal::meta_type_node mapped_type_node = {};
+    internal::meta_type_node value_type_node = {};
     size_type (*size_fn)(const any &) noexcept = nullptr;
     bool (*clear_fn)(any &) = nullptr;
     iterator (*iter_fn)(any &, const bool) = nullptr;
@@ -181,14 +181,14 @@ class meta_any {
     }
 
     void release() {
-        if(node && node->dtor.dtor && owner()) {
-            node->dtor.dtor(storage.data());
+        if(node.dtor.dtor && owner()) {
+            node.dtor.dtor(storage.data());
         }
     }
 
     meta_any(const meta_any &other, any ref) noexcept
         : storage{std::move(ref)},
-          node{storage ? other.node : nullptr},
+          node{storage ? other.node : internal::meta_type_node{}},
           vtable{storage ? other.vtable : &basic_vtable<void>} {}
 
 public:
@@ -233,7 +233,7 @@ public:
      */
     meta_any(meta_any &&other) noexcept
         : storage{std::move(other.storage)},
-          node{std::exchange(other.node, nullptr)},
+          node{std::exchange(other.node, internal::meta_type_node{})},
           vtable{std::exchange(other.vtable, &basic_vtable<void>)} {}
 
     /*! @brief Frees the internal storage, whatever it means. */
@@ -248,9 +248,9 @@ public:
      */
     meta_any &operator=(const meta_any &other) {
         release();
-        vtable = other.vtable;
         storage = other.storage;
         node = other.node;
+        vtable = other.vtable;
         return *this;
     }
 
@@ -261,9 +261,9 @@ public:
      */
     meta_any &operator=(meta_any &&other) noexcept {
         release();
-        vtable = std::exchange(other.vtable, &basic_vtable<void>);
         storage = std::move(other.storage);
-        node = std::exchange(other.node, nullptr);
+        node = std::exchange(other.node, internal::meta_type_node{});
+        vtable = std::exchange(other.vtable, &basic_vtable<void>);
         return *this;
     }
 
@@ -343,8 +343,8 @@ public:
     [[nodiscard]] const Type *try_cast() const {
         auto *self = any_cast<Type>(&storage);
 
-        if(!self && node && node->details) {
-            for(auto it = node->details->base.cbegin(), last = node->details->base.cend(); it != last && !self; ++it) {
+        if(!self && node.details) {
+            for(auto it = node.details->base.cbegin(), last = node.details->base.cend(); it != last && !self; ++it) {
                 const auto &as_const = it->second.cast(as_ref());
                 self = as_const.template try_cast<Type>();
             }
@@ -358,8 +358,8 @@ public:
     [[nodiscard]] Type *try_cast() {
         auto *self = any_cast<Type>(&storage);
 
-        if(!self && node && node->details) {
-            for(auto it = node->details->base.cbegin(), last = node->details->base.cend(); it != last && !self; ++it) {
+        if(!self && node.details) {
+            for(auto it = node.details->base.cbegin(), last = node.details->base.cend(); it != last && !self; ++it) {
                 self = it->second.cast(as_ref()).template try_cast<Type>();
             }
         }
@@ -452,9 +452,9 @@ public:
     template<typename Type, typename... Args>
     void emplace(Args &&...args) {
         release();
-        vtable = &basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
         storage.emplace<Type>(std::forward<Args>(args)...);
         node = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>();
+        vtable = &basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
     }
 
     /*! @copydoc any::assign */
@@ -466,9 +466,9 @@ public:
     /*! @copydoc any::reset */
     void reset() {
         release();
-        vtable = &basic_vtable<void>;
         storage.reset();
-        node = nullptr;
+        node = {};
+        vtable = &basic_vtable<void>;
     }
 
     /**
@@ -525,12 +525,12 @@ public:
      * @return False if the wrapper is invalid, true otherwise.
      */
     [[nodiscard]] explicit operator bool() const noexcept {
-        return !(node == nullptr);
+        return !(node.info == nullptr);
     }
 
     /*! @copydoc any::operator== */
     [[nodiscard]] bool operator==(const meta_any &other) const noexcept {
-        return (!node && !other.node) || (node && other.node && *node->info == *other.node->info && storage == other.storage);
+        return (!node.info && !other.node.info) || (node.info && other.node.info && *node.info == *other.node.info && storage == other.storage);
     }
 
     /*! @copydoc any::operator!= */
@@ -555,7 +555,7 @@ public:
 
 private:
     any storage;
-    internal::meta_type_node *node;
+    internal::meta_type_node node;
     vtable_type *vtable;
 };
 
@@ -669,7 +669,7 @@ struct meta_prop {
      * @return A wrapper containing the value stored with the property.
      */
     [[nodiscard]] meta_any value() const {
-        return node.value ? node.type()->from_void(nullptr, node.value.get()) : meta_any{};
+        return node.value ? node.type().from_void(nullptr, node.value.get()) : meta_any{};
     }
 
     /**
@@ -947,8 +947,8 @@ class meta_type {
                     if(const auto &info = other.info(); info == type.info()) {
                         ++direct;
                     } else {
-                        ext += (type.node->details && (type.node->details->base.contains(info.hash()) || type.node->details->conv.contains(info.hash())))
-                               || (type.node->conversion_helper && other.node->conversion_helper);
+                        ext += (type.node.details && (type.node.details->base.contains(info.hash()) || type.node.details->conv.contains(info.hash())))
+                               || (type.node.conversion_helper && other.node.conversion_helper);
                     }
                 }
 
@@ -976,22 +976,22 @@ public:
     using size_type = typename node_type::size_type;
 
     /*! @copydoc meta_prop::meta_prop */
-    meta_type(const node_type *curr = nullptr) noexcept
+    meta_type(const node_type &curr = {}) noexcept
         : node{curr} {}
 
     /**
      * @brief Constructs an instance from a given base node.
      * @param curr The base node with which to construct the instance.
      */
-    meta_type(const base_node_type *curr) noexcept
-        : node{curr ? curr->type() : nullptr} {}
+    meta_type(const base_node_type &curr) noexcept
+        : meta_type{curr.type ? curr.type() : meta_type{}} {}
 
     /**
      * @brief Returns the type info object of the underlying type.
      * @return The type info object of the underlying type.
      */
     [[nodiscard]] const type_info &info() const noexcept {
-        return *node->info;
+        return *node.info;
     }
 
     /**
@@ -999,7 +999,7 @@ public:
      * @return The identifier assigned to the type.
      */
     [[nodiscard]] id_type id() const noexcept {
-        return node->id;
+        return node.id;
     }
 
     /**
@@ -1007,7 +1007,7 @@ public:
      * @return The size of the underlying type if known, 0 otherwise.
      */
     [[nodiscard]] size_type size_of() const noexcept {
-        return node->size_of;
+        return node.size_of;
     }
 
     /**
@@ -1016,7 +1016,7 @@ public:
      * otherwise.
      */
     [[nodiscard]] bool is_arithmetic() const noexcept {
-        return static_cast<bool>(node->traits & internal::meta_traits::is_arithmetic);
+        return static_cast<bool>(node.traits & internal::meta_traits::is_arithmetic);
     }
 
     /**
@@ -1024,7 +1024,7 @@ public:
      * @return True if the underlying type is an integral type, false otherwise.
      */
     [[nodiscard]] bool is_integral() const noexcept {
-        return static_cast<bool>(node->traits & internal::meta_traits::is_integral);
+        return static_cast<bool>(node.traits & internal::meta_traits::is_integral);
     }
 
     /**
@@ -1032,7 +1032,7 @@ public:
      * @return True if the underlying type is a signed type, false otherwise.
      */
     [[nodiscard]] bool is_signed() const noexcept {
-        return static_cast<bool>(node->traits & internal::meta_traits::is_signed);
+        return static_cast<bool>(node.traits & internal::meta_traits::is_signed);
     }
 
     /**
@@ -1040,7 +1040,7 @@ public:
      * @return True if the underlying type is an array type, false otherwise.
      */
     [[nodiscard]] bool is_array() const noexcept {
-        return static_cast<bool>(node->traits & internal::meta_traits::is_array);
+        return static_cast<bool>(node.traits & internal::meta_traits::is_array);
     }
 
     /**
@@ -1048,7 +1048,7 @@ public:
      * @return True if the underlying type is an enum, false otherwise.
      */
     [[nodiscard]] bool is_enum() const noexcept {
-        return static_cast<bool>(node->traits & internal::meta_traits::is_enum);
+        return static_cast<bool>(node.traits & internal::meta_traits::is_enum);
     }
 
     /**
@@ -1056,7 +1056,7 @@ public:
      * @return True if the underlying type is a class, false otherwise.
      */
     [[nodiscard]] bool is_class() const noexcept {
-        return static_cast<bool>(node->traits & internal::meta_traits::is_class);
+        return static_cast<bool>(node.traits & internal::meta_traits::is_class);
     }
 
     /**
@@ -1064,7 +1064,7 @@ public:
      * @return True if the underlying type is a pointer, false otherwise.
      */
     [[nodiscard]] bool is_pointer() const noexcept {
-        return node != node->remove_pointer();
+        return node.info && (node.info->hash() != node.remove_pointer().info->hash());
     }
 
     /**
@@ -1073,7 +1073,7 @@ public:
      * doesn't refer to a pointer type.
      */
     [[nodiscard]] meta_type remove_pointer() const noexcept {
-        return node->remove_pointer();
+        return node.remove_pointer();
     }
 
     /**
@@ -1082,7 +1082,7 @@ public:
      * otherwise.
      */
     [[nodiscard]] bool is_pointer_like() const noexcept {
-        return static_cast<bool>(node->traits & internal::meta_traits::is_meta_pointer_like);
+        return static_cast<bool>(node.traits & internal::meta_traits::is_meta_pointer_like);
     }
 
     /**
@@ -1090,7 +1090,7 @@ public:
      * @return True if the type is a sequence container, false otherwise.
      */
     [[nodiscard]] bool is_sequence_container() const noexcept {
-        return static_cast<bool>(node->traits & internal::meta_traits::is_meta_sequence_container);
+        return static_cast<bool>(node.traits & internal::meta_traits::is_meta_sequence_container);
     }
 
     /**
@@ -1098,7 +1098,7 @@ public:
      * @return True if the type is an associative container, false otherwise.
      */
     [[nodiscard]] bool is_associative_container() const noexcept {
-        return static_cast<bool>(node->traits & internal::meta_traits::is_meta_associative_container);
+        return static_cast<bool>(node.traits & internal::meta_traits::is_meta_associative_container);
     }
 
     /**
@@ -1108,7 +1108,7 @@ public:
      * false otherwise.
      */
     [[nodiscard]] bool is_template_specialization() const noexcept {
-        return (node->templ.arity != 0u);
+        return (node.templ.arity != 0u);
     }
 
     /**
@@ -1116,7 +1116,7 @@ public:
      * @return The number of template arguments.
      */
     [[nodiscard]] size_type template_arity() const noexcept {
-        return node->templ.arity;
+        return node.templ.arity;
     }
 
     /**
@@ -1127,7 +1127,7 @@ public:
      * @return The tag for the class template of the underlying type.
      */
     [[nodiscard]] inline meta_type template_type() const noexcept {
-        return node->templ.type ? node->templ.type() : nullptr;
+        return node.templ.type ? meta_type{node.templ.type()} : meta_type{};
     }
 
     /**
@@ -1136,7 +1136,7 @@ public:
      * @return The type of the i-th template argument of a type.
      */
     [[nodiscard]] inline meta_type template_arg(const size_type index) const noexcept {
-        return index < template_arity() ? node->templ.arg(index) : meta_type{};
+        return index < template_arity() ? meta_type{node.templ.arg(index)} : meta_type{};
     }
 
     /**
@@ -1144,8 +1144,8 @@ public:
      * @return An iterable range to visit registered top-level base meta types.
      */
     [[nodiscard]] meta_range<meta_type, typename decltype(internal::meta_type_node::cold_data_t::base)::const_iterator> base() const noexcept {
-        if(node->details) {
-            return {node->details->base.cbegin(), node->details->base.cend()};
+        if(node.details) {
+            return {node.details->base.cbegin(), node.details->base.cend()};
         }
 
         return {};
@@ -1156,8 +1156,8 @@ public:
      * @return An iterable range to visit registered top-level meta data.
      */
     [[nodiscard]] meta_range<meta_data, typename decltype(internal::meta_type_node::cold_data_t::data)::const_iterator> data() const noexcept {
-        if(node->details) {
-            return {node->details->data.cbegin(), node->details->data.cend()};
+        if(node.details) {
+            return {node.details->data.cbegin(), node.details->data.cend()};
         }
 
         return {};
@@ -1172,8 +1172,8 @@ public:
      * @return The registered meta data for the given identifier, if any.
      */
     [[nodiscard]] meta_data data(const id_type id) const {
-        if(node->details) {
-            if(auto it = node->details->data.find(id); it != node->details->data.cend()) {
+        if(node.details) {
+            if(auto it = node.details->data.find(id); it != node.details->data.cend()) {
                 return it->second;
             }
         }
@@ -1192,8 +1192,8 @@ public:
      * @return An iterable range to visit registered top-level functions.
      */
     [[nodiscard]] meta_range<meta_func, typename decltype(internal::meta_type_node::cold_data_t::func)::const_iterator> func() const noexcept {
-        if(node->details) {
-            return {node->details->func.cbegin(), node->details->func.cend()};
+        if(node.details) {
+            return {node.details->func.cbegin(), node.details->func.cend()};
         }
 
         return {};
@@ -1210,8 +1210,8 @@ public:
      * @return The registered meta function for the given identifier, if any.
      */
     [[nodiscard]] meta_func func(const id_type id) const {
-        if(node->details) {
-            if(auto it = node->details->func.find(id); it != node->details->func.cend()) {
+        if(node.details) {
+            if(auto it = node.details->func.find(id); it != node.details->func.cend()) {
                 return it->second;
             }
         }
@@ -1237,8 +1237,8 @@ public:
      * @return A wrapper containing the new instance, if any.
      */
     [[nodiscard]] meta_any construct(meta_any *const args, const size_type sz) const {
-        if(node->details) {
-            const auto *candidate = lookup(args, sz, [first = node->details->ctor.cbegin(), last = node->details->ctor.cend()]() mutable {
+        if(node.details) {
+            const auto *candidate = lookup(args, sz, [first = node.details->ctor.cbegin(), last = node.details->ctor.cend()]() mutable {
                 return first == last ? nullptr : &(first++)->second;
             });
 
@@ -1247,8 +1247,8 @@ public:
             }
         }
 
-        if(sz == 0u && node->default_constructor) {
-            return node->default_constructor();
+        if(sz == 0u && node.default_constructor) {
+            return node.default_constructor();
         }
 
         return {};
@@ -1275,12 +1275,12 @@ public:
      * @return A wrapper that references the given instance.
      */
     meta_any from_void(void *element) const {
-        return (element && node->from_void) ? node->from_void(element, nullptr) : meta_any{};
+        return (element && node.from_void) ? node.from_void(element, nullptr) : meta_any{};
     }
 
     /*! @copydoc from_void */
     meta_any from_void(const void *element) const {
-        return (element && node->from_void) ? node->from_void(nullptr, element) : meta_any{};
+        return (element && node.from_void) ? node.from_void(nullptr, element) : meta_any{};
     }
 
     /**
@@ -1298,8 +1298,8 @@ 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(node->details) {
-            if(auto it = node->details->func.find(id); it != node->details->func.cend()) {
+        if(node.details) {
+            if(auto it = node.details->func.find(id); it != node.details->func.cend()) {
                 const auto *candidate = lookup(args, sz, [curr = &it->second]() mutable {
                     return curr ? std::exchange(curr, curr->next.get()) : nullptr;
                 });
@@ -1376,8 +1376,8 @@ public:
      * @return An iterable range to visit registered top-level meta properties.
      */
     [[nodiscard]] meta_range<meta_prop, typename decltype(internal::meta_type_node::cold_data_t::prop)::const_iterator> prop() const noexcept {
-        if(node->details) {
-            return {node->details->prop.cbegin(), node->details->prop.cend()};
+        if(node.details) {
+            return {node.details->prop.cbegin(), node.details->prop.cend()};
         }
 
         return {};
@@ -1392,8 +1392,8 @@ public:
      * @return The registered meta property for the given key, if any.
      */
     [[nodiscard]] meta_prop prop(const id_type key) const {
-        if(node->details) {
-            if(auto it = node->details->prop.find(key); it != node->details->prop.cend()) {
+        if(node.details) {
+            if(auto it = node.details->prop.find(key); it != node.details->prop.cend()) {
                 return it->second;
             }
         }
@@ -1412,7 +1412,7 @@ public:
      * @return True if the object is valid, false otherwise.
      */
     [[nodiscard]] explicit operator bool() const noexcept {
-        return !(node == nullptr);
+        return !(node.info == nullptr);
     }
 
     /**
@@ -1421,11 +1421,11 @@ public:
      * @return True if the objects refer to the same type, false otherwise.
      */
     [[nodiscard]] bool operator==(const meta_type &other) const noexcept {
-        return (!node && !other.node) || (node && other.node && *node->info == *other.node->info);
+        return (!node.info && !other.node.info) || (node.info && other.node.info && *node.info == *other.node.info);
     }
 
 private:
-    const node_type *node;
+    node_type node;
 };
 
 /**
@@ -1466,31 +1466,31 @@ bool meta_any::set(const id_type id, Type &&value) {
 }
 
 [[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const {
-    if(const auto &info = type.info(); node && *node->info == info) {
+    if(node.info && *node.info == type.info()) {
         return as_ref();
-    } else if(node) {
-        if(node->details) {
-            if(auto it = node->details->conv.find(info.hash()); it != node->details->conv.cend()) {
-                return it->second.conv(*this);
-            }
-        }
+    }
 
-        if(node->conversion_helper && (type.is_arithmetic() || type.is_enum())) {
-            // exploits the fact that arithmetic types and enums are also default constructible
-            auto other = type.construct();
-            ENTT_ASSERT(other.node->conversion_helper, "Conversion helper not found");
-            const auto value = node->conversion_helper(nullptr, storage.data());
-            other.node->conversion_helper(other.storage.data(), &value);
-            return other;
+    if(node.details) {
+        if(auto it = node.details->conv.find(type.info().hash()); it != node.details->conv.cend()) {
+            return it->second.conv(*this);
         }
+    }
 
-        if(node->details) {
-            for(auto &&curr: node->details->base) {
-                const auto &as_const = curr.second.cast(as_ref());
+    if(node.conversion_helper && (type.is_arithmetic() || type.is_enum())) {
+        // exploits the fact that arithmetic types and enums are also default constructible
+        auto other = type.construct();
+        ENTT_ASSERT(other.node.conversion_helper, "Conversion helper not found");
+        const auto value = node.conversion_helper(nullptr, storage.data());
+        other.node.conversion_helper(other.storage.data(), &value);
+        return other;
+    }
 
-                if(auto other = as_const.allow_cast(type); other) {
-                    return other;
-                }
+    if(node.details) {
+        for(auto &&curr: node.details->base) {
+            const auto &as_const = curr.second.cast(as_ref());
+
+            if(auto other = as_const.allow_cast(type); other) {
+                return other;
             }
         }
     }
@@ -1504,7 +1504,7 @@ inline bool meta_any::assign(const meta_any &other) {
 }
 
 inline bool meta_any::assign(meta_any &&other) {
-    if(*node->info == *other.node->info) {
+    if(*node.info == *other.node.info) {
         return storage.assign(std::move(other.storage));
     }
 
@@ -1710,7 +1710,7 @@ private:
  * @return The meta value type of the container.
  */
 [[nodiscard]] inline meta_type meta_sequence_container::value_type() const noexcept {
-    return value_type_node();
+    return value_type_node;
 }
 
 /**
@@ -1806,7 +1806,7 @@ inline meta_sequence_container::iterator meta_sequence_container::erase(iterator
  * @return The meta key type of the a container.
  */
 [[nodiscard]] inline meta_type meta_associative_container::key_type() const noexcept {
-    return key_type_node();
+    return key_type_node;
 }
 
 /**
@@ -1814,12 +1814,12 @@ inline meta_sequence_container::iterator meta_sequence_container::erase(iterator
  * @return The meta mapped type of the a container.
  */
 [[nodiscard]] inline meta_type meta_associative_container::mapped_type() const noexcept {
-    return mapped_type_node ? mapped_type_node() : nullptr;
+    return mapped_type_node;
 }
 
 /*! @copydoc meta_sequence_container::value_type */
 [[nodiscard]] inline meta_type meta_associative_container::value_type() const noexcept {
-    return value_type_node();
+    return value_type_node;
 }
 
 /*! @copydoc meta_sequence_container::size */

+ 14 - 16
src/entt/meta/node.hpp

@@ -48,12 +48,12 @@ enum class meta_traits : std::uint32_t {
 struct meta_type_node;
 
 struct meta_prop_node {
-    meta_type_node *(*type)() noexcept {};
+    meta_type_node (*type)() noexcept {};
     std::shared_ptr<void> value{};
 };
 
 struct meta_base_node {
-    meta_type_node *(*type)() noexcept {};
+    meta_type_node (*type)() noexcept {};
     meta_any (*cast)(meta_any) noexcept {};
 };
 
@@ -82,7 +82,7 @@ struct meta_data_node {
 
     meta_traits traits{meta_traits::is_none};
     size_type arity{0u};
-    meta_type_node *(*type)() noexcept {};
+    meta_type_node (*type)() noexcept {};
     meta_type (*arg)(const size_type) noexcept {};
     bool (*set)(meta_handle, meta_any){};
     meta_any (*get)(meta_handle){};
@@ -98,7 +98,7 @@ struct meta_func_node {
 
     meta_traits traits{meta_traits::is_none};
     size_type arity{0u};
-    meta_type_node *(*ret)() noexcept {};
+    meta_type_node (*ret)() noexcept {};
     meta_type (*arg)(const size_type) noexcept {};
     meta_any (*invoke)(meta_handle, meta_any *const){};
     std::shared_ptr<meta_func_node> next{};
@@ -109,8 +109,8 @@ struct meta_template_node {
     using size_type = std::size_t;
 
     size_type arity{0u};
-    meta_type_node *(*type)() noexcept {};
-    meta_type_node *(*arg)(const size_type) noexcept {};
+    meta_type_node (*type)() noexcept {};
+    meta_type_node (*arg)(const size_type) noexcept {};
 };
 
 struct meta_type_node {
@@ -129,7 +129,7 @@ struct meta_type_node {
     id_type id{};
     meta_traits traits{meta_traits::is_none};
     size_type size_of{0u};
-    meta_type_node *(*remove_pointer)() noexcept {};
+    meta_type_node (*remove_pointer)() noexcept {};
     meta_any (*default_constructor)(){};
     double (*conversion_helper)(void *, const void *){};
     meta_any (*from_void)(void *, const void *){};
@@ -139,11 +139,11 @@ struct meta_type_node {
 };
 
 template<typename Type>
-meta_type_node *resolve() noexcept;
+meta_type_node resolve() noexcept;
 
 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::resolve<std::remove_cv_t<std::remove_reference_t<Args>>>()...};
+[[nodiscard]] meta_type_node meta_arg_node(type_list<Args...>, const std::size_t index) noexcept {
+    meta_type_node args[sizeof...(Args) + 1u]{{}, internal::resolve<std::remove_cv_t<std::remove_reference_t<Args>>>()...};
     return args[index + 1u];
 }
 
@@ -202,21 +202,21 @@ template<typename 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); }};
+            +[](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{};
     }
 }
 
 template<typename Type>
-[[nodiscard]] meta_type_node *resolve() noexcept {
+[[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{
+        return meta_type_node{
             &type_id<Type>(),
             type_id<Type>().hash(),
             (std::is_arithmetic_v<Type> ? internal::meta_traits::is_arithmetic : internal::meta_traits::is_none)
@@ -234,11 +234,9 @@ template<typename Type>
             meta_conversion_helper<Type>(),
             meta_from_void<Type>(),
             meta_template_info<Type>()};
-
-        it = context.value.insert_or_assign(node.info->hash(), std::make_unique<meta_type_node>(std::move(node))).first;
     }
 
-    return it->second.get();
+    return it->second;
 }
 
 } // namespace internal

+ 3 - 18
src/entt/meta/range.hpp

@@ -17,22 +17,7 @@ namespace entt {
 namespace internal {
 
 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 &*value;
-    }
-
-    template<typename Value>
-    Type to_value(char, const Value &value) const {
-        if constexpr(std::is_same_v<std::decay_t<Value>, internal::meta_prop_node> || std::is_same_v<std::decay_t<Value>, internal::meta_data_node> || std::is_same_v<std::decay_t<Value>, internal::meta_func_node>) {
-            return value;
-        } else {
-            return &value;
-        }
-    }
-
-public:
+struct meta_range_iterator final {
     using difference_type = std::ptrdiff_t;
     using value_type = std::pair<id_type, Type>;
     using pointer = input_iterator_pointer<value_type>;
@@ -82,7 +67,7 @@ public:
     }
 
     [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
-        return {it[value].first, to_value(0, it[value].second)};
+        return {it[value].first, it[value].second};
     }
 
     [[nodiscard]] constexpr pointer operator->() const noexcept {
@@ -90,7 +75,7 @@ public:
     }
 
     [[nodiscard]] constexpr reference operator*() const noexcept {
-        return {it->first, to_value(0, it->second)};
+        return {it->first, it->second};
     }
 
     template<typename... Args>

+ 1 - 1
src/entt/meta/resolve.hpp

@@ -54,7 +54,7 @@ template<typename Type>
     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 it->second;
     }
 
     return {};

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

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

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

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

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

@@ -205,10 +205,10 @@ TEST_F(MetaCtor, NonDefaultConstructibleType) {
 TEST_F(MetaCtor, ReRegistration) {
     SetUp();
 
-    auto *node = entt::internal::resolve<double>();
+    auto &&node = entt::internal::resolve<double>();
 
-    ASSERT_TRUE(node->details);
-    ASSERT_FALSE(node->details->ctor.empty());
+    ASSERT_TRUE(node.details);
+    ASSERT_FALSE(node.details->ctor.empty());
     // implicitly generated default constructor is not cleared
-    ASSERT_NE(node->default_constructor, nullptr);
+    ASSERT_NE(node.default_constructor, nullptr);
 }

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

@@ -643,18 +643,18 @@ TEST_F(MetaData, ReRegistration) {
 
     SetUp();
 
-    auto *node = entt::internal::resolve<base_t>();
+    auto &&node = entt::internal::resolve<base_t>();
     auto type = entt::resolve<base_t>();
 
-    ASSERT_TRUE(node->details);
-    ASSERT_FALSE(node->details->data.empty());
-    ASSERT_EQ(node->details->data.size(), 1u);
+    ASSERT_TRUE(node.details);
+    ASSERT_FALSE(node.details->data.empty());
+    ASSERT_EQ(node.details->data.size(), 1u);
     ASSERT_TRUE(type.data("value"_hs));
 
     entt::meta<base_t>().data<&base_t::value>("field"_hs);
 
-    ASSERT_TRUE(node->details);
-    ASSERT_EQ(node->details->data.size(), 2u);
+    ASSERT_TRUE(node.details);
+    ASSERT_EQ(node.details->data.size(), 2u);
     ASSERT_TRUE(type.data("value"_hs));
     ASSERT_TRUE(type.data("field"_hs));
 }

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

@@ -101,9 +101,9 @@ TEST_F(MetaDtor, AsRefConstruction) {
 TEST_F(MetaDtor, ReRegistration) {
     SetUp();
 
-    auto *node = entt::internal::resolve<clazz_t>();
+    auto &&node = entt::internal::resolve<clazz_t>();
 
-    ASSERT_NE(node->dtor.dtor, nullptr);
+    ASSERT_NE(node.dtor.dtor, nullptr);
 
     entt::meta<clazz_t>().dtor<&clazz_t::destroy_incr>();
     entt::resolve<clazz_t>().construct().reset();

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

@@ -86,12 +86,12 @@ TEST_F(MetaProp, ReRegistration) {
 
     SetUp();
 
-    auto *node = entt::internal::resolve<base_1_t>();
+    auto &&node = entt::internal::resolve<base_1_t>();
     auto type = entt::resolve<base_1_t>();
 
-    ASSERT_TRUE(node->details);
-    ASSERT_FALSE(node->details->prop.empty());
-    ASSERT_EQ(node->details->prop.size(), 1u);
+    ASSERT_TRUE(node.details);
+    ASSERT_FALSE(node.details->prop.empty());
+    ASSERT_EQ(node.details->prop.size(), 1u);
 
     ASSERT_TRUE(type.prop("int"_hs));
     ASSERT_EQ(type.prop("int"_hs).value().cast<int>(), 42);
@@ -99,9 +99,9 @@ TEST_F(MetaProp, ReRegistration) {
     entt::meta<base_1_t>().prop("int"_hs, 0);
     entt::meta<base_1_t>().prop("double"_hs, 3.);
 
-    ASSERT_TRUE(node->details);
-    ASSERT_FALSE(node->details->prop.empty());
-    ASSERT_EQ(node->details->prop.size(), 2u);
+    ASSERT_TRUE(node.details);
+    ASSERT_FALSE(node.details->prop.empty());
+    ASSERT_EQ(node.details->prop.size(), 2u);
 
     ASSERT_TRUE(type.prop("int"_hs));
     ASSERT_TRUE(type.prop("double"_hs));