diff --git a/src/entt/meta/container.hpp b/src/entt/meta/container.hpp index eaa7704c0..5afcd304c 100644 --- a/src/entt/meta/container.hpp +++ b/src/entt/meta/container.hpp @@ -48,72 +48,69 @@ template struct basic_meta_sequence_container_traits { static_assert(std::is_same_v>>, "Unexpected type"); - using iterator = meta_sequence_container::iterator; - using size_type = std::size_t; + using operation = internal::meta_sequence_container_operation; + using size_type = typename meta_sequence_container::size_type; + using iterator = typename meta_sequence_container::iterator; - [[nodiscard]] static size_type size(const void *container) noexcept { - return static_cast(container)->size(); - } - - [[nodiscard]] static bool clear(void *container) { - if constexpr(dynamic_sequence_container::value) { - static_cast(container)->clear(); - return true; - } else { - return false; - } - } - - [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { - if constexpr(reserve_aware_container::value) { - static_cast(container)->reserve(sz); - return true; - } else { - return false; - } - } - - [[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { - if constexpr(dynamic_sequence_container::value) { - static_cast(container)->resize(sz); - return true; - } else { - return false; - } - } - - [[nodiscard]] static iterator iter(const meta_ctx &ctx, const void *container, const bool as_const, const bool as_end) { - if(as_const) { - const auto it = as_end ? static_cast(container)->end() : static_cast(container)->begin(); - return iterator{ctx, it}; - } else { - const auto it = as_end ? static_cast(const_cast(container))->end() : static_cast(const_cast(container))->begin(); - return iterator{ctx, it}; - } - } - - [[nodiscard]] static iterator insert_or_erase([[maybe_unused]] const meta_ctx &ctx, [[maybe_unused]] void *container, [[maybe_unused]] const any &handle, [[maybe_unused]] meta_any &value) { - if constexpr(dynamic_sequence_container::value) { - typename Type::const_iterator it{}; - - if(auto *const non_const = any_cast(&handle); non_const) { - it = *non_const; + static size_type basic_vtable(const operation op, const meta_ctx &ctx, const void *container, const void *value, iterator *it) { + switch(const Type *cont = static_cast(container); op) { + case operation::size: + return cont->size(); + case operation::clear: + if constexpr(dynamic_sequence_container::value) { + const_cast(cont)->clear(); + return true; } else { - it = any_cast(handle); + break; } + case operation::reserve: + if constexpr(reserve_aware_container::value) { + const_cast(cont)->reserve(*static_cast(value)); + return true; + } else { + break; + } + case operation::resize: + if constexpr(dynamic_sequence_container::value) { + const_cast(cont)->resize(*static_cast(value)); + return true; + } else { + break; + } + case operation::begin: + *it = iterator{ctx, const_cast(cont)->begin()}; + return true; + case operation::end: + *it = iterator{ctx, const_cast(cont)->end()}; + return true; + case operation::cbegin: + *it = iterator{ctx, cont->begin()}; + return true; + case operation::cend: + *it = iterator{ctx, cont->end()}; + return true; + case operation::insert: + case operation::erase: + if constexpr(dynamic_sequence_container::value) { + auto *const non_const = any_cast(&it->base()); + typename Type::const_iterator underlying{non_const ? *non_const : any_cast(it->base())}; - if(auto *const cont = static_cast(container); value) { - // this abomination is necessary because only on macos value_type and const_reference are different types for std::vector - if(value.allow_cast() || value.allow_cast()) { - const auto *element = value.try_cast>(); - return iterator{ctx, cont->insert(it, element ? *element : value.cast())}; + if(op == operation::insert) { + // this abomination is necessary because only on macos value_type and const_reference are different types for std::vector + if(static_cast(const_cast(value))->allow_cast() || static_cast(const_cast(value))->allow_cast()) { + const auto *element = static_cast(const_cast(value))->try_cast>(); + *it = iterator{ctx, const_cast(cont)->insert(underlying, element ? *element : static_cast(const_cast(value))->cast())}; + return true; + } + } else { + *it = iterator{ctx, const_cast(cont)->erase(underlying)}; + return true; } - } else { - return iterator{ctx, cont->erase(it)}; } + break; } - return iterator{}; + return false; } }; @@ -121,8 +118,8 @@ template struct basic_meta_associative_container_traits { static_assert(std::is_same_v>>, "Unexpected type"); - using iterator = meta_associative_container::iterator; - using size_type = std::size_t; + using size_type = typename meta_associative_container::size_type; + using iterator = typename meta_associative_container::iterator; static constexpr auto key_only = key_only_associative_container::value; diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index 6e6cd5079..1863f4156 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -26,9 +26,37 @@ namespace entt { class meta_any; class meta_type; +/** + * @cond TURN_OFF_DOXYGEN + * Internal details not to be documented. + */ + +namespace internal { + +enum class meta_sequence_container_operation { + size, + clear, + reserve, + resize, + begin, + end, + cbegin, + cend, + insert, + erase +}; + +} // namespace internal + +/** + * Internal details not to be documented. + * @endcond + */ + /*! @brief Proxy object for sequence containers. */ class meta_sequence_container { class meta_iterator; + using operation = internal::meta_sequence_container_operation; public: /*! @brief Unsigned integer type. */ @@ -52,12 +80,7 @@ public: void rebind(any instance) noexcept { ENTT_ASSERT(instance.type() == type_id(), "Unexpected type"); value_type_node = &internal::resolve; - size_fn = &meta_sequence_container_traits::size; - clear_fn = &meta_sequence_container_traits::clear; - reserve_fn = &meta_sequence_container_traits::reserve; - resize_fn = &meta_sequence_container_traits::resize; - iter_fn = &meta_sequence_container_traits::iter; - insert_or_erase_fn = &meta_sequence_container_traits::insert_or_erase; + vtable = &meta_sequence_container_traits::basic_vtable; storage = std::move(instance); } @@ -76,12 +99,7 @@ public: private: const meta_ctx *ctx{}; internal::meta_type_node (*value_type_node)(const internal::meta_context &){}; - size_type (*size_fn)(const void *) noexcept {}; - bool (*clear_fn)(void *){}; - bool (*reserve_fn)(void *, const size_type){}; - bool (*resize_fn)(void *, const size_type){}; - iterator (*iter_fn)(const meta_ctx &, const void *, const bool, const bool){}; - iterator (*insert_or_erase_fn)(const meta_ctx &, void *, const any &, meta_any &){}; + size_type (*vtable)(const operation, const meta_ctx &, const void *, const void *, iterator *){}; any storage{}; }; @@ -1675,8 +1693,6 @@ inline bool meta_any::assign(meta_any &&other) { */ class meta_sequence_container::meta_iterator final { - friend class meta_sequence_container; - using vtable_type = void(const void *, const std::ptrdiff_t, meta_any *); template @@ -1750,6 +1766,10 @@ public: return !(*this == other); } + [[nodiscard]] const any &base() const noexcept { + return handle; + } + private: const meta_ctx *ctx; vtable_type *vtable; @@ -1847,7 +1867,7 @@ private: * @return The size of the container. */ [[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const noexcept { - return size_fn(storage.data()); + return vtable(operation::size, *ctx, std::as_const(storage).data(), nullptr, nullptr); } /** @@ -1856,7 +1876,7 @@ private: * @return True in case of success, false otherwise. */ inline bool meta_sequence_container::resize(const size_type sz) { - return (storage.policy() != any_policy::cref) && resize_fn(storage.data(), sz); + return (storage.policy() != any_policy::cref) && vtable(operation::resize, *ctx, storage.data(), &sz, nullptr); } /** @@ -1864,7 +1884,7 @@ inline bool meta_sequence_container::resize(const size_type sz) { * @return True in case of success, false otherwise. */ inline bool meta_sequence_container::clear() { - return (storage.policy() != any_policy::cref) && clear_fn(storage.data()); + return (storage.policy() != any_policy::cref) && vtable(operation::clear, *ctx, storage.data(), nullptr, nullptr); } /** @@ -1873,7 +1893,7 @@ inline bool meta_sequence_container::clear() { * @return True in case of success, false otherwise. */ inline bool meta_sequence_container::reserve(const size_type sz) { - return (storage.policy() != any_policy::cref) && reserve_fn(storage.data(), sz); + return (storage.policy() != any_policy::cref) && vtable(operation::reserve, *ctx, storage.data(), &sz, nullptr); } /** @@ -1881,7 +1901,9 @@ inline bool meta_sequence_container::reserve(const size_type sz) { * @return An iterator to the first element of the container. */ [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() { - return iter_fn(*ctx, std::as_const(storage).data(), (storage.policy() == any_policy::cref), false); + iterator it{}; + vtable(storage.policy() == any_policy::cref ? operation::cbegin : operation::begin, *ctx, std::as_const(storage).data(), nullptr, &it); + return it; } /** @@ -1889,7 +1911,9 @@ inline bool meta_sequence_container::reserve(const size_type sz) { * @return An iterator that is past the last element of the container. */ [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() { - return iter_fn(*ctx, std::as_const(storage).data(), (storage.policy() == any_policy::cref), true); + iterator it{}; + vtable(storage.policy() == any_policy::cref ? operation::cend : operation::end, *ctx, std::as_const(storage).data(), nullptr, &it); + return it; } /** @@ -1899,7 +1923,7 @@ inline bool meta_sequence_container::reserve(const size_type sz) { * @return A possibly invalid iterator to the inserted element. */ inline meta_sequence_container::iterator meta_sequence_container::insert(iterator it, meta_any value) { - return (storage.policy() != any_policy::cref) ? insert_or_erase_fn(*ctx, storage.data(), it.handle, value) : iterator{}; + return ((storage.policy() != any_policy::cref) && vtable(operation::insert, *ctx, storage.data(), &value, &it)) ? it : iterator{}; } /** @@ -1908,7 +1932,7 @@ inline meta_sequence_container::iterator meta_sequence_container::insert(iterato * @return A possibly invalid iterator following the last removed element. */ inline meta_sequence_container::iterator meta_sequence_container::erase(iterator it) { - return insert(it, {}); + return ((storage.policy() != any_policy::cref) && vtable(operation::erase, *ctx, storage.data(), nullptr, &it)) ? it : iterator{}; } /**