From 43932492a7b33aa6d44fe9d2e96a7a6b9d5b9751 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 10 Jun 2019 23:19:19 +0200 Subject: [PATCH] meta: overall improvements --- src/entt/meta/factory.hpp | 28 ++++----- src/entt/meta/meta.hpp | 116 +++++++++++++++++++++++--------------- test/entt/meta/meta.cpp | 23 ++++++++ 3 files changed, 106 insertions(+), 61 deletions(-) diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp index 0d9182a9f..456713bfe 100644 --- a/src/entt/meta/factory.hpp +++ b/src/entt/meta/factory.hpp @@ -64,7 +64,7 @@ class meta_factory { []() -> meta_any { return std::get<1>(prop); }, - []() -> meta_prop { + []() ENTT_NOEXCEPT -> meta_prop { return &node; } }; @@ -93,11 +93,11 @@ class meta_factory { std::is_member_object_pointer_v, std::is_member_function_pointer_v, std::extent_v, - []() -> meta_type { + []() ENTT_NOEXCEPT -> meta_type { return internal::meta_info>::resolve(); }, &internal::destroy, - []() -> meta_type { + []() ENTT_NOEXCEPT -> meta_type { return &node; } }; @@ -209,10 +209,10 @@ public: type, nullptr, &internal::meta_info::resolve, - [](void *instance) -> void * { + [](void *instance) ENTT_NOEXCEPT -> void * { return static_cast(static_cast(instance)); }, - []() -> meta_base { + []() ENTT_NOEXCEPT -> meta_base { return &node; } }; @@ -247,7 +247,7 @@ public: [](void *instance) -> meta_any { return static_cast(*static_cast(instance)); }, - []() -> meta_conv { + []() ENTT_NOEXCEPT -> meta_conv { return &node; } }; @@ -290,7 +290,7 @@ public: [](meta_any * const any) { return internal::invoke(nullptr, any, std::make_index_sequence{}); }, - []() -> meta_ctor { + []() ENTT_NOEXCEPT -> meta_ctor { return &node; } }; @@ -331,7 +331,7 @@ public: [](meta_any * const any) { return internal::construct(any, std::make_index_sequence{}); }, - []() -> meta_ctor { + []() ENTT_NOEXCEPT -> meta_ctor { return &node; } }; @@ -374,7 +374,7 @@ public: ? ((*Func)(static_cast(handle.data())), true) : false; }, - []() -> meta_dtor { + []() ENTT_NOEXCEPT -> meta_dtor { return &node; } }; @@ -418,7 +418,7 @@ public: &internal::meta_info::resolve, [](meta_handle, meta_any, meta_any) { return false; }, [](meta_handle, meta_any) -> meta_any { return Data; }, - []() -> meta_data { + []() ENTT_NOEXCEPT -> meta_data { return &node; } }; @@ -439,7 +439,7 @@ public: &internal::meta_info::resolve, &internal::setter, Type, Data>, &internal::getter, - []() -> meta_data { + []() ENTT_NOEXCEPT -> meta_data { return &node; } }; @@ -461,7 +461,7 @@ public: &internal::meta_info::resolve, &internal::setter, Type, Data>, &internal::getter, - []() -> meta_data { + []() ENTT_NOEXCEPT -> meta_data { return &node; } }; @@ -519,7 +519,7 @@ public: &internal::meta_info::resolve, &internal::setter, &internal::getter, - []() -> meta_data { + []() ENTT_NOEXCEPT -> meta_data { return &node; } }; @@ -569,7 +569,7 @@ public: [](meta_handle handle, meta_any *any) { return internal::invoke(handle, any, std::make_index_sequence{}); }, - []() -> meta_func { + []() ENTT_NOEXCEPT -> meta_func { return &node; } }; diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index 57f450add..976c084af 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -44,7 +44,7 @@ struct meta_prop_node { meta_prop_node * next; meta_any(* const key)(); meta_any(* const value)(); - meta_prop(* const meta)(); + meta_prop(* const meta)() ENTT_NOEXCEPT; }; @@ -52,9 +52,9 @@ struct meta_base_node { meta_base_node ** const underlying; meta_type_node * const parent; meta_base_node * next; - meta_type_node *(* const type)(); - void *(* const cast)(void *); - meta_base(* const meta)(); + meta_type_node *(* const type)() ENTT_NOEXCEPT; + void *(* const cast)(void *) ENTT_NOEXCEPT; + meta_base(* const meta)() ENTT_NOEXCEPT; }; @@ -62,9 +62,9 @@ struct meta_conv_node { meta_conv_node ** const underlying; meta_type_node * const parent; meta_conv_node * next; - meta_type_node *(* const type)(); + meta_type_node *(* const type)() ENTT_NOEXCEPT; meta_any(* const conv)(void *); - meta_conv(* const meta)(); + meta_conv(* const meta)() ENTT_NOEXCEPT; }; @@ -75,9 +75,9 @@ struct meta_ctor_node { meta_ctor_node * next; meta_prop_node * prop; const size_type size; - meta_type_node *(* const arg)(size_type); + meta_type_node *(* const arg)(size_type) ENTT_NOEXCEPT; meta_any(* const invoke)(meta_any * const); - meta_ctor(* const meta)(); + meta_ctor(* const meta)() ENTT_NOEXCEPT; }; @@ -85,7 +85,7 @@ struct meta_dtor_node { meta_dtor_node ** const underlying; meta_type_node * const parent; bool(* const invoke)(meta_handle); - meta_dtor(* const meta)(); + meta_dtor(* const meta)() ENTT_NOEXCEPT; }; @@ -97,10 +97,10 @@ struct meta_data_node { meta_prop_node * prop; const bool is_const; const bool is_static; - meta_type_node *(* const type)(); + meta_type_node *(* const type)() ENTT_NOEXCEPT; bool(* const set)(meta_handle, meta_any, meta_any); meta_any(* const get)(meta_handle, meta_any); - meta_data(* const meta)(); + meta_data(* const meta)() ENTT_NOEXCEPT; }; @@ -114,10 +114,10 @@ struct meta_func_node { const size_type size; const bool is_const; const bool is_static; - meta_type_node *(* const ret)(); - meta_type_node *(* const arg)(size_type); + meta_type_node *(* const ret)() ENTT_NOEXCEPT; + meta_type_node *(* const arg)(size_type) ENTT_NOEXCEPT; meta_any(* const invoke)(meta_handle, meta_any *); - meta_func(* const meta)(); + meta_func(* const meta)() ENTT_NOEXCEPT; }; @@ -138,9 +138,9 @@ struct meta_type_node { const bool is_member_object_pointer; const bool is_member_function_pointer; const size_type extent; - meta_type(* const remove_pointer)(); + meta_type(* const remove_pointer)() ENTT_NOEXCEPT; bool(* const destroy)(meta_handle); - meta_type(* const meta)(); + meta_type(* const meta)() ENTT_NOEXCEPT; meta_base_node *base{nullptr}; meta_conv_node *conv{nullptr}; meta_ctor_node *ctor{nullptr}; @@ -303,23 +303,24 @@ class meta_any { friend class meta_handle; using storage_type = std::aligned_storage_t; - using compare_fn_type = bool(*)(const void *, const void *); - using copy_fn_type = void *(*)(storage_type &, const void *); - using destroy_fn_type = void(*)(storage_type &); + using compare_fn_type = bool(const void *, const void *) ENTT_NOEXCEPT; + using copy_fn_type = void *(storage_type &, const void *); + using destroy_fn_type = void(storage_type &); + using steal_fn_type = void *(storage_type &, storage_type &, destroy_fn_type *, void *) ENTT_NOEXCEPT; template - static auto compare(int, const Type &lhs, const Type &rhs) + static auto compare(int, const Type &lhs, const Type &rhs) ENTT_NOEXCEPT -> decltype(lhs == rhs, bool{}) { return lhs == rhs; } template - static bool compare(char, const Type &lhs, const Type &rhs) { + static bool compare(char, const Type &lhs, const Type &rhs) ENTT_NOEXCEPT { return &lhs == &rhs; } template - static bool compare(const void *lhs, const void *rhs) { + static bool compare(const void *lhs, const void *rhs) ENTT_NOEXCEPT { return compare(0, *static_cast(lhs), *static_cast(rhs)); } @@ -331,9 +332,27 @@ class meta_any { template static void * copy_object(storage_type &storage, const void *instance) { using chunk_type = std::aligned_storage_t; - auto *chunk = new chunk_type; - new (&storage) chunk_type *{chunk}; - return new (chunk) Type{*static_cast(instance)}; + auto chunk = std::make_unique(); + new (&storage) chunk_type *{chunk.get()}; + auto *other = new (chunk.get()) Type{*static_cast(instance)}; + chunk.release(); + return other; + } + + template + static void * steal_storage(storage_type &to, storage_type &from, destroy_fn_type *destroy_fn, void *) noexcept { + void *instance = new (&to) Type{std::move(*reinterpret_cast(&from))}; + destroy_fn(from); + return instance; + } + + template + static void * steal_object(storage_type &to, storage_type &from, destroy_fn_type *, void *instance) noexcept { + using chunk_type = std::aligned_storage_t; + auto *chunk = *reinterpret_cast(&from); + new (&to) chunk_type *{chunk}; + chunk->~chunk_type(); + return instance; } template @@ -361,7 +380,8 @@ public: node{nullptr}, destroy_fn{nullptr}, compare_fn{nullptr}, - copy_fn{nullptr} + copy_fn{nullptr}, + steal_fn{nullptr} {} /** @@ -381,15 +401,18 @@ public: template meta_any(std::in_place_type_t, Args &&... args) { using actual_type = std::remove_cv_t>; - constexpr auto sbo_allowed = sizeof(actual_type) <= sizeof(void *); node = internal::meta_info::resolve(); compare_fn = &compare; + constexpr auto sbo_allowed = sizeof(actual_type) <= sizeof(void *) + && std::is_nothrow_move_constructible_v; + if constexpr(sbo_allowed) { instance = new (&storage) actual_type{std::forward(args)...}; destroy_fn = &destroy_storage; copy_fn = ©_storage; + steal_fn = &steal_storage; } else { using chunk_type = std::aligned_storage_t; @@ -400,6 +423,7 @@ public: destroy_fn = &destroy_object; copy_fn = ©_object; + steal_fn = &steal_object; } } @@ -434,6 +458,7 @@ public: destroy_fn = other.destroy_fn; compare_fn = other.compare_fn; copy_fn = other.copy_fn; + steal_fn = other.steal_fn; } } @@ -543,7 +568,7 @@ public: * one otherwise. */ template - meta_any convert() const ENTT_NOEXCEPT { + meta_any convert() const { const auto *type = internal::meta_info::resolve(); meta_any any{}; @@ -568,7 +593,7 @@ public: * @return True if the conversion is possible, false otherwise. */ template - bool convert() ENTT_NOEXCEPT { + bool convert() { bool valid = (node == internal::meta_info::resolve()); if(!valid) { @@ -601,7 +626,7 @@ public: * @return False if the container is empty, true otherwise. */ explicit operator bool() const ENTT_NOEXCEPT { - return destroy_fn; + return instance; } /** @@ -619,24 +644,19 @@ public: * @param lhs A valid meta any object. * @param rhs A valid meta any object. */ - friend void swap(meta_any &lhs, meta_any &rhs) { + friend void swap(meta_any &lhs, meta_any &rhs) ENTT_NOEXCEPT { using std::swap; if(lhs && rhs) { storage_type buffer; - void *tmp = lhs.copy_fn(buffer, lhs.instance); - lhs.destroy_fn(lhs.storage); - lhs.instance = rhs.copy_fn(lhs.storage, rhs.instance); - rhs.destroy_fn(rhs.storage); - rhs.instance = lhs.copy_fn(rhs.storage, tmp); - lhs.destroy_fn(buffer); + void *instance = lhs.steal_fn(buffer, lhs.storage, lhs.destroy_fn, lhs.instance); + lhs.instance = rhs.steal_fn(lhs.storage, rhs.storage, rhs.destroy_fn, rhs.instance); + rhs.instance = lhs.steal_fn(rhs.storage, buffer, lhs.destroy_fn, instance); } else if(lhs) { - rhs.instance = lhs.copy_fn(rhs.storage, lhs.instance); - lhs.destroy_fn(lhs.storage); + rhs.instance = lhs.steal_fn(rhs.storage, lhs.storage, lhs.destroy_fn, lhs.instance); lhs.instance = nullptr; } else if(rhs) { - lhs.instance = rhs.copy_fn(lhs.storage, rhs.instance); - rhs.destroy_fn(rhs.storage); + lhs.instance = rhs.steal_fn(lhs.storage, rhs.storage, rhs.destroy_fn, rhs.instance); rhs.instance = nullptr; } @@ -644,15 +664,17 @@ public: std::swap(lhs.destroy_fn, rhs.destroy_fn); std::swap(lhs.compare_fn, rhs.compare_fn); std::swap(lhs.copy_fn, rhs.copy_fn); + std::swap(lhs.steal_fn, rhs.steal_fn); } private: storage_type storage; void *instance; internal::meta_type_node *node; - destroy_fn_type destroy_fn; - compare_fn_type compare_fn; - copy_fn_type copy_fn; + destroy_fn_type *destroy_fn; + compare_fn_type *compare_fn; + copy_fn_type *copy_fn; + steal_fn_type *steal_fn; }; @@ -2071,7 +2093,7 @@ struct meta_function_helper { static constexpr auto size = sizeof...(Args); - static auto arg(typename internal::meta_func_node::size_type index) { + static auto arg(typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT { return std::array{{meta_info::resolve()...}}[index]; } }; @@ -2283,11 +2305,11 @@ inline meta_type_node * meta_node::resolve() ENTT_NOEXCEPT { std::is_member_object_pointer_v, std::is_member_function_pointer_v, std::extent_v, - []() -> meta_type { + []() ENTT_NOEXCEPT -> meta_type { return internal::meta_info>::resolve(); }, &destroy, - []() -> meta_type { + []() ENTT_NOEXCEPT -> meta_type { return &node; } }; diff --git a/test/entt/meta/meta.cpp b/test/entt/meta/meta.cpp index 56cecb4dc..c6f232444 100644 --- a/test/entt/meta/meta.cpp +++ b/test/entt/meta/meta.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -424,6 +425,28 @@ TEST_F(Meta, MetaAnyNoSBOMoveAssignment) { ASSERT_NE(other, fat_type{}); } +TEST_F(Meta, MetaAnySBOMoveInvalidate) { + entt::meta_any any{42}; + entt::meta_any other{std::move(any)}; + entt::meta_any valid = std::move(other); + + ASSERT_FALSE(any); + ASSERT_FALSE(other); + ASSERT_TRUE(valid); +} + +TEST_F(Meta, MetaAnyNoSBOMoveInvalidate) { + int value = 42; + fat_type instance{&value}; + entt::meta_any any{instance}; + entt::meta_any other{std::move(any)}; + entt::meta_any valid = std::move(other); + + ASSERT_FALSE(any); + ASSERT_FALSE(other); + ASSERT_TRUE(valid); +} + TEST_F(Meta, MetaAnySBODestruction) { ASSERT_EQ(empty_type::counter, 0); { entt::meta_any any{empty_type{}}; }