diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index 0de2c8620..93e8b9f4f 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -164,42 +164,36 @@ private: * of memory allocations if possible. This should improve overall performance. */ class meta_any { - using dereference_operator_type = meta_any(meta_any &); + enum class operation { DEREF, SEQ, ASSOC }; + + using vtable_type = void(const operation, meta_any &, void *); template - [[nodiscard]] static meta_any dereference_operator(meta_any &any) { - if constexpr(is_meta_pointer_like_v) { - using pointed_type = std::remove_reference_t())>; + static void basic_vtable(const operation op, [[maybe_unused]] meta_any &from, [[maybe_unused]] void *to) { + switch(op) { + case operation::DEREF: + if constexpr(is_meta_pointer_like_v) { + if(auto ptr = from.cast(); ptr) { + using pointed_type = std::remove_reference_t())>; - if constexpr(std::is_const_v && std::is_copy_constructible_v) { - auto ptr = any.cast(); - return ptr ? std::as_const(*ptr) : meta_any{}; - } else if constexpr(!std::is_const_v) { - auto ptr = any.cast(); - return ptr ? std::ref(*ptr) : meta_any{}; - } else { - return {}; + if constexpr(std::is_const_v && std::is_copy_constructible_v) { + *static_cast(to) = std::as_const(*ptr); + } else if constexpr(!std::is_const_v) { + *static_cast(to) = std::ref(*ptr); + } + } } - } else { - return {}; - } - } - - template - [[nodiscard]] static meta_sequence_container meta_sequence_container_factory([[maybe_unused]] void *container) ENTT_NOEXCEPT { - if constexpr(has_meta_sequence_container_traits_v) { - return static_cast(container); - } else { - return {}; - } - } - - template - [[nodiscard]] static meta_associative_container meta_associative_container_factory([[maybe_unused]] void *container) ENTT_NOEXCEPT { - if constexpr(has_meta_associative_container_traits_v) { - return static_cast(container); - } else { - return {}; + break; + case operation::SEQ: + if constexpr(has_meta_sequence_container_traits_v) { + *static_cast(to) = static_cast(from.data()); + } + break; + case operation::ASSOC: + if constexpr(has_meta_associative_container_traits_v) { + *static_cast(to) = static_cast(from.data()); + } + break; } } @@ -207,10 +201,8 @@ public: /*! @brief Default constructor. */ meta_any() ENTT_NOEXCEPT : storage{}, - node{}, - deref{nullptr}, - seq_factory{nullptr}, - assoc_factory{nullptr} + vtable{}, + node{} {} /** @@ -222,10 +214,8 @@ public: template explicit meta_any(std::in_place_type_t, [[maybe_unused]] Args &&... args) : storage(std::in_place_type, std::forward(args)...), - node{internal::meta_info::resolve()}, - deref{&dereference_operator}, - seq_factory{&meta_sequence_container_factory}, - assoc_factory{&meta_associative_container_factory} + vtable{&basic_vtable}, + node{internal::meta_info::resolve()} {} /** @@ -236,10 +226,8 @@ public: template meta_any(std::reference_wrapper value) : storage{value}, - node{internal::meta_info::resolve()}, - deref{&dereference_operator}, - seq_factory{&meta_sequence_container_factory}, - assoc_factory{&meta_associative_container_factory} + vtable{&basic_vtable}, + node{internal::meta_info::resolve()} {} /** @@ -444,9 +432,7 @@ public: meta_any other{}; other.node = node; other.storage = storage.ref(); - other.deref = deref; - other.seq_factory = seq_factory; - other.assoc_factory = assoc_factory; + other.vtable = vtable; return other; } @@ -455,7 +441,9 @@ public: * @return A sequence container proxy for the underlying object. */ [[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT { - return seq_factory(storage.data()); + meta_sequence_container proxy; + vtable(operation::SEQ, *this, &proxy); + return proxy; } /** @@ -463,7 +451,9 @@ public: * @return An associative container proxy for the underlying object. */ [[nodiscard]] meta_associative_container as_associative_container() ENTT_NOEXCEPT { - return assoc_factory(storage.data()); + meta_associative_container proxy; + vtable(operation::ASSOC, *this, &proxy); + return proxy; } /** @@ -472,7 +462,9 @@ public: * wrapped element is dereferenceable, an invalid meta any otherwise. */ [[nodiscard]] meta_any operator*() ENTT_NOEXCEPT { - return deref(*this); + meta_any any{}; + vtable(operation::DEREF, *this, &any); + return any; } /** @@ -500,18 +492,14 @@ public: friend void swap(meta_any &lhs, meta_any &rhs) { using std::swap; swap(lhs.storage, rhs.storage); + swap(lhs.vtable, rhs.vtable); swap(lhs.node, rhs.node); - swap(lhs.deref, rhs.deref); - swap(lhs.seq_factory, rhs.seq_factory); - swap(lhs.assoc_factory, rhs.assoc_factory); } private: any storage; + vtable_type *vtable; internal::meta_type_node *node; - dereference_operator_type *deref; - meta_sequence_container(* seq_factory)(void *); - meta_associative_container(* assoc_factory)(void *); };