diff --git a/TODO b/TODO index a45258fafd..fddd2be301 100644 --- a/TODO +++ b/TODO @@ -39,9 +39,8 @@ TODO: * refine the storage fallback mechanism for views (ie alloc?) * don't pass reactive storage by default to callback * runtime types support for meta for types that aren't backed by C++ types -* dtor, traits and custom should be part of meta descriptor maybe (?) +* dtor, traits and custom should be part of meta descriptor (update meta_factory tests then) * allow attaching const values of non-Type type to meta types * built-in no-pagination storage - no_pagination page size as limits::max * meta_any ownership construction and from_void -* meta_factory() isn't fully tested yet -* entt::meta isn't required anymore, we can do everything with entt::meta_factory and avoid symbol duplication +* sparse_set shrink_to_fit argument for sparse array shrink policy (none, empty, deep, whatever) diff --git a/docs/md/meta.md b/docs/md/meta.md index 8230eead21..dda6c0dae5 100644 --- a/docs/md/meta.md +++ b/docs/md/meta.md @@ -49,13 +49,13 @@ identifier is required, it's likely that a user defined literal is used as follows: ```cpp -auto factory = entt::meta().type("reflected_type"_hs); +entt::meta_factory{}.type("reflected_type"_hs); ``` For what it's worth, this is completely equivalent to: ```cpp -auto factory = entt::meta().type(42u); +entt::meta_factory{}.type(42u); ``` Obviously, human-readable identifiers are more convenient to use and highly @@ -65,10 +65,10 @@ recommended. Reflection always starts from actual C++ types. Users cannot reflect _imaginary_ types.
-The `meta` function is where it all starts: +The `meta_factory` class is where it all starts: ```cpp -auto factory = entt::meta(); +entt::meta_factory factory{}; ``` The returned value is a _factory object_ to use to continue building the meta @@ -79,7 +79,7 @@ runtime type identification system built-in in `EnTT`.
However, it's also possible to assign custom identifiers to meta types: ```cpp -auto factory = entt::meta().type("reflected_type"_hs); +entt::meta_factory{}.type("reflected_type"_hs); ``` Identifiers are used to _retrieve_ meta types at runtime by _name_ other than by @@ -98,7 +98,7 @@ generally used to create the following: function or an actual constructor: ```cpp - entt::meta().ctor().ctor<&factory>(); + entt::meta_factory{}.ctor().ctor<&factory>(); ``` Meta default constructors are implicitly generated, if possible. @@ -106,7 +106,7 @@ generally used to create the following: * _Destructors_. Both free functions and member functions are valid destructors: ```cpp - entt::meta().dtor<&destroy>(); + entt::meta_factory{}.dtor<&destroy>(); ``` The purpose is to offer the possibility to free up resources that require @@ -120,7 +120,7 @@ generally used to create the following: type appear as if they were part of the type itself: ```cpp - entt::meta() + entt::meta_factory{} .data<&my_type::static_variable>("static"_hs) .data<&my_type::data_member>("member"_hs) .data<&global_variable>("global"_hs); @@ -133,13 +133,13 @@ generally used to create the following: convenient to create read-only properties from a non-const data member: ```cpp - entt::meta().data("member"_hs); + entt::meta_factory{}.data("member"_hs); ``` Multiple setters are also supported by means of a `value_list` object: ```cpp - entt::meta().data, &my_type::data_member>("member"_hs); + entt::meta_factory{}.data, &my_type::data_member>("member"_hs); ``` * _Member functions_. Meta member functions are actual member functions of the @@ -148,7 +148,7 @@ generally used to create the following: were part of the type itself: ```cpp - entt::meta() + entt::meta_factory{} .func<&my_type::static_function>("static"_hs) .func<&my_type::member_function>("member"_hs) .func<&free_function>("free"_hs); @@ -163,7 +163,7 @@ generally used to create the following: derived from it: ```cpp - entt::meta().base(); + entt::meta_factory{}.base(); ``` The reflection system tracks the relationship and allows for implicit casts at @@ -174,7 +174,7 @@ generally used to create the following: that are implicitly performed by the reflection system when required: ```cpp - entt::meta().conv(); + entt::meta_factory{}.conv(); ``` This is everything users need to create meta types. Refer to the inline @@ -669,7 +669,7 @@ If this were to be translated into explicit registrations with the reflection system, it would result in a long series of instructions such as the following: ```cpp -entt::meta() +entt::meta_factory{} .conv() .conv() // ... @@ -683,7 +683,7 @@ underlying types and offers what it takes to do the same for scoped enums. It would result in the following if it were to be done explicitly: ```cpp -entt::meta() +entt::meta_factory{} .conv>(); ``` @@ -776,7 +776,7 @@ There are a few alternatives available at the moment: thus making it appear as if its type were `void`: ```cpp - entt::meta().func<&my_type::member_function, entt::as_void_t>("member"_hs); + entt::meta_factory{}.func<&my_type::member_function, entt::as_void_t>("member"_hs); ``` If the use with functions is obvious, perhaps less so is use with constructors @@ -792,7 +792,7 @@ There are a few alternatives available at the moment: the wrapper itself: ```cpp - entt::meta().data<&my_type::data_member, entt::as_ref_t>("member"_hs); + entt::meta_factory{}.data<&my_type::data_member, entt::as_ref_t>("member"_hs); ``` These policies work with constructors (for example, when objects are taken @@ -819,11 +819,11 @@ between enums and classes in C++ directly in the space of the reflected types. Exposing constant values or elements from an enum is quite simple: ```cpp -entt::meta() +entt::meta_factory{} .data("a_value"_hs) .data("another_value"_hs); -entt::meta().data<2048>("max_int"_hs); +entt::meta_factory{}.data<2048>("max_int"_hs); ``` Accessing them is trivial as well. It's a matter of doing the following, as with @@ -859,7 +859,7 @@ and meta functions. User-defined traits are set via a meta factory: ```cpp -entt::meta().traits(my_traits::required | my_traits::hidden); +entt::meta_factory{}.traits(my_traits::required | my_traits::hidden); ``` In the example above, `EnTT` bitmask enum support is used but any integral value @@ -872,7 +872,7 @@ Likewise, users can also set traits on meta objects later if needed, as long as the factory is reset to the meta object of interest: ```cpp -entt::meta() +entt::meta_factory{} .data<&my_type::data_member, entt::as_ref_t>("member"_hs) .traits(my_traits::internal); ``` @@ -893,7 +893,7 @@ correctly. Custom arbitrary data are set via a meta factory: ```cpp -entt::meta().custom("name"); +entt::meta_factory{}.custom("name"); ``` The way to do this is by specifying the data type to the `custom` function and @@ -906,7 +906,7 @@ Likewise, users can also set custom data on meta objects later if needed, as long as the factory is reset to the meta object of interest: ```cpp -entt::meta() +entt::meta_factory{} .func<&my_type::member_function>("member"_hs) .custom("tooltip"); ``` @@ -976,11 +976,11 @@ If _replacing_ the default context isn't enough, `EnTT` also offers the ability to use multiple and externally managed contexts with the runtime reflection system.
For example, to create new meta types within a context other than the default -one, simply pass it as an argument to the `meta` call: +one, simply pass it as an argument to the `meta_factory` constructor: ```cpp entt::meta_ctx context{}; -auto factory = entt::meta(context).type("reflected_type"_hs); +entt::meta_factory{context}.type("reflected_type"_hs); ``` By doing so, the new meta type isn't available in the default context but is diff --git a/src/entt/entity/sparse_set.hpp b/src/entt/entity/sparse_set.hpp index 633d0340ad..8f368f8aec 100644 --- a/src/entt/entity/sparse_set.hpp +++ b/src/entt/entity/sparse_set.hpp @@ -164,7 +164,8 @@ class basic_sparse_set { static constexpr auto max_size = static_cast(traits_type::to_entity(null)); - [[nodiscard]] auto policy_to_head() const noexcept { + // it could be auto but gcc complains and emits a warning due to a false positive + [[nodiscard]] std::size_t policy_to_head() const noexcept { return static_cast(max_size * static_cast(mode != deletion_policy::swap_only)); } diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp index 37214f91c9..34b49fecc1 100644 --- a/src/entt/meta/factory.hpp +++ b/src/entt/meta/factory.hpp @@ -119,17 +119,16 @@ class basic_meta_factory { } public: - basic_meta_factory(const id_type id, meta_ctx &area) + basic_meta_factory(meta_ctx &area, meta_type_node node) : ctx{&area}, - parent{id}, - bucket{id} { - auto &&elem = meta_context::from(*ctx).value[parent]; - - if(!elem.details) { - elem.details = std::make_shared(); + parent{node.info->hash()}, + bucket{parent} { + if(!node.details) { + node.details = std::make_shared(); } - details = elem.details.get(); + details = node.details.get(); + meta_context::from(*ctx).value.try_emplace(parent, std::move(node)); } private: @@ -172,14 +171,14 @@ class meta_factory: private internal::basic_meta_factory { public: /*! @brief Default constructor. */ meta_factory() noexcept - : internal::basic_meta_factory{type_id().hash(), locator::value_or()} {} + : meta_factory{locator::value_or()} {} /** * @brief Context aware constructor. * @param area The context into which to construct meta types. */ meta_factory(meta_ctx &area) noexcept - : internal::basic_meta_factory{type_id().hash(), area} {} + : base_type{area, internal::resolve(internal::meta_context::from(area))} {} /** * @brief Assigns a custom unique identifier to a meta type. @@ -515,10 +514,7 @@ class meta_factory: private internal::basic_meta_factory { * @return A meta factory for the given type. */ template -[[nodiscard]] auto meta(meta_ctx &ctx) noexcept { - auto &&context = internal::meta_context::from(ctx); - // make sure the type exists in the context before returning a factory - context.value.try_emplace(type_id().hash(), internal::resolve(context)); +[[nodiscard]] [[deprecated("use meta_factory directly instead")]] auto meta(meta_ctx &ctx) noexcept { return meta_factory{ctx}; } @@ -534,7 +530,7 @@ template * @return A meta factory for the given type. */ template -[[nodiscard]] auto meta() noexcept { +[[nodiscard]] [[deprecated("use meta_factory directly instead")]] auto meta() noexcept { return meta(locator::value_or()); } diff --git a/test/entt/meta/meta_any.cpp b/test/entt/meta/meta_any.cpp index 0c300ccab2..fe687dfa6b 100644 --- a/test/entt/meta/meta_any.cpp +++ b/test/entt/meta/meta_any.cpp @@ -89,16 +89,16 @@ struct MetaAny: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("empty"_hs) .dtor(); - entt::meta() + entt::meta_factory{} .type("fat"_hs) .base() .dtor(); - entt::meta() + entt::meta_factory{} .type("clazz"_hs) .data<&clazz::value>("value"_hs) .func<&clazz::member>("member"_hs) diff --git a/test/entt/meta/meta_base.cpp b/test/entt/meta/meta_base.cpp index 7bd33c9655..a69e35432d 100644 --- a/test/entt/meta/meta_base.cpp +++ b/test/entt/meta/meta_base.cpp @@ -37,18 +37,18 @@ struct MetaBase: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .data<&base_1::value_1>("value_1"_hs); - entt::meta() + entt::meta_factory{} .conv() .data<&base_2::value_2>("value_2"_hs); - entt::meta() + entt::meta_factory{} .base() .data<&base_3::value_3>("value_3"_hs); - entt::meta() + entt::meta_factory{} .type("derived"_hs) .base() .base() diff --git a/test/entt/meta/meta_context.cpp b/test/entt/meta/meta_context.cpp index 5c1ea34b11..90d92b7f09 100644 --- a/test/entt/meta/meta_context.cpp +++ b/test/entt/meta/meta_context.cpp @@ -78,13 +78,13 @@ class MetaContext: public ::testing::Test { static void init_global_context() { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .data("marker"_hs); - entt::meta() + entt::meta_factory{} .conv<&argument::get>(); - entt::meta() + entt::meta_factory{} .type("foo"_hs) .custom(3) .ctor() @@ -92,27 +92,27 @@ class MetaContext: public ::testing::Test { .data<&clazz::value>("rw"_hs) .func<&clazz::func>("func"_hs); - entt::meta>() + entt::meta_factory>{} .type("template"_hs); } void init_local_context() { using namespace entt::literals; - entt::meta(context) + entt::meta_factory{context} .data("marker"_hs); - entt::meta(context) + entt::meta_factory{context} .type("quux"_hs); - entt::meta(context) + entt::meta_factory{context} .conv<&argument::get_mul>(); - entt::meta(context) + entt::meta_factory{context} .data<&base::value>("char"_hs) .func<&base::get>("get"_hs); - entt::meta(context) + entt::meta_factory{context} .type("bar"_hs) .custom('c') .base() @@ -122,7 +122,7 @@ class MetaContext: public ::testing::Test { .data<&clazz::value>("rw"_hs) .func<&clazz::cfunc>("func"_hs); - entt::meta>(context) + entt::meta_factory>{context} .type("template"_hs); } diff --git a/test/entt/meta/meta_conv.cpp b/test/entt/meta/meta_conv.cpp index 2d4d6785d3..944f903a0b 100644 --- a/test/entt/meta/meta_conv.cpp +++ b/test/entt/meta/meta_conv.cpp @@ -30,7 +30,7 @@ struct MetaConv: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("clazz"_hs) .conv() .conv<&clazz::to_bool>() diff --git a/test/entt/meta/meta_ctor.cpp b/test/entt/meta/meta_ctor.cpp index 10e7e3e1db..f8e89f06cb 100644 --- a/test/entt/meta/meta_ctor.cpp +++ b/test/entt/meta/meta_ctor.cpp @@ -50,15 +50,15 @@ struct MetaCtor: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("double"_hs) .ctor(); - entt::meta() + entt::meta_factory{} .type("derived"_hs) .base(); - entt::meta() + entt::meta_factory{} .type("clazz"_hs) .ctor<&entt::registry::emplace_or_replace, entt::as_ref_t>() .ctor() diff --git a/test/entt/meta/meta_custom.cpp b/test/entt/meta/meta_custom.cpp index 64319e6750..e093f7b042 100644 --- a/test/entt/meta/meta_custom.cpp +++ b/test/entt/meta/meta_custom.cpp @@ -22,7 +22,7 @@ struct MetaCustom: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("clazz"_hs) .custom('c') .data<&clazz::i>("i"_hs) @@ -132,7 +132,7 @@ TEST_F(MetaCustom, ReRegistration) { ASSERT_NE(static_cast(type.custom()), nullptr); ASSERT_EQ(*static_cast(type.custom()), 'c'); - entt::meta().custom(1); + entt::meta_factory{}.custom(1); type = entt::resolve(); ASSERT_NE(static_cast(type.custom()), nullptr); diff --git a/test/entt/meta/meta_data.cpp b/test/entt/meta/meta_data.cpp index 8aecb406bc..3a5ec40403 100644 --- a/test/entt/meta/meta_data.cpp +++ b/test/entt/meta/meta_data.cpp @@ -91,18 +91,18 @@ struct MetaData: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("base"_hs) .dtor() .data<&base::value>("value"_hs); - entt::meta() + entt::meta_factory{} .type("derived"_hs) .base() .dtor() .data<&base::value>("value_from_base"_hs); - entt::meta() + entt::meta_factory{} .type("clazz"_hs) .data<&clazz::i, entt::as_ref_t>("i"_hs) .custom('c') @@ -118,7 +118,7 @@ struct MetaData: ::testing::Test { .data<&clazz::i, entt::as_void_t>("void"_hs) .conv(); - entt::meta() + entt::meta_factory{} .type("setter_getter"_hs) .data<&setter_getter::static_setter, &setter_getter::static_getter>("x"_hs) .data<&setter_getter::setter, &setter_getter::getter>("y"_hs) @@ -127,11 +127,11 @@ struct MetaData: ::testing::Test { .data("z_ro"_hs) .data("value"_hs); - entt::meta() + entt::meta_factory{} .type("multi_setter"_hs) .data, &multi_setter::value>("value"_hs); - entt::meta() + entt::meta_factory{} .type("array"_hs) .data<&array::global>("global"_hs) .data<&array::local>("local"_hs); @@ -163,7 +163,7 @@ ENTT_DEBUG_TEST_F(MetaDataDeathTest, UserTraits) { using traits_type = entt::internal::meta_traits; constexpr auto value = traits_type{static_cast>(traits_type::_user_defined_traits) + 1u}; - ASSERT_DEATH(entt::meta().data<&clazz::i>("j"_hs).traits(value), ""); + ASSERT_DEATH(entt::meta_factory{}.data<&clazz::i>("j"_hs).traits(value), ""); } TEST_F(MetaData, Custom) { @@ -640,14 +640,14 @@ TEST_F(MetaData, ReRegistration) { ASSERT_EQ(node.details->data.size(), 1u); ASSERT_TRUE(type.data("value"_hs)); - entt::meta().data<&base::value>("field"_hs); + entt::meta_factory{}.data<&base::value>("field"_hs); ASSERT_TRUE(node.details); ASSERT_EQ(node.details->data.size(), 2u); ASSERT_TRUE(type.data("value"_hs)); ASSERT_TRUE(type.data("field"_hs)); - entt::meta() + entt::meta_factory{} .data<&base::value>("field"_hs) .traits(test::meta_traits::one) .custom(3) @@ -665,8 +665,8 @@ TEST_F(MetaData, CollisionAndReuse) { ASSERT_FALSE(entt::resolve().data("cj"_hs)); ASSERT_TRUE(entt::resolve().data("j"_hs).is_const()); - ASSERT_NO_THROW(entt::meta().data<&clazz::i>("j"_hs)); - ASSERT_NO_THROW(entt::meta().data<&clazz::j>("cj"_hs)); + ASSERT_NO_THROW(entt::meta_factory{}.data<&clazz::i>("j"_hs)); + ASSERT_NO_THROW(entt::meta_factory{}.data<&clazz::j>("cj"_hs)); ASSERT_TRUE(entt::resolve().data("j"_hs)); ASSERT_TRUE(entt::resolve().data("cj"_hs)); diff --git a/test/entt/meta/meta_dtor.cpp b/test/entt/meta/meta_dtor.cpp index a45bb34939..eaf653c8b9 100644 --- a/test/entt/meta/meta_dtor.cpp +++ b/test/entt/meta/meta_dtor.cpp @@ -29,7 +29,7 @@ struct MetaDtor: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("clazz"_hs) .ctor() .dtor(); @@ -108,7 +108,7 @@ TEST_F(MetaDtor, ReRegistration) { ASSERT_NE(node.dtor.dtor, nullptr); - entt::meta().dtor<&clazz::destroy_incr>(); + entt::meta_factory{}.dtor<&clazz::destroy_incr>(); entt::resolve().construct(entt::forward_as_meta(counter)).reset(); ASSERT_EQ(counter, 2); diff --git a/test/entt/meta/meta_factory.cpp b/test/entt/meta/meta_factory.cpp index a13d32bc41..076e465f7f 100644 --- a/test/entt/meta/meta_factory.cpp +++ b/test/entt/meta/meta_factory.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -8,9 +9,12 @@ #include #include #include +#include "../../common/boxed_type.h" #include "../../common/config.h" +#include "../../common/meta_traits.h" struct base { + char member{}; }; struct clazz: base { @@ -18,20 +22,44 @@ struct clazz: base { : value{val} {} explicit operator int() const noexcept { + return get_int(); + } + + void set_int(int val) noexcept { + value = val; + } + + void set_boxed_int(test::boxed_int val) noexcept { + value = val.value; + } + + int get_int() const noexcept { return value; } + static std::string to_string(const clazz &instance) { + return std::to_string(instance.get_int()); + } + + static clazz from_string(const std::string &value) { + return clazz{std::stoi(value)}; + } + private: int value{}; }; -std::string clazz_to_string(const clazz &instance) { - return std::to_string(static_cast(instance)); -} +struct dtor_callback { + dtor_callback(bool &ref) + : cb{&ref} {} -clazz string_to_clazz(const std::string &value) { - return clazz{std::stoi(value)}; -} + static void on_destroy(dtor_callback &instance) { + *instance.cb = !*instance.cb; + } + +private: + bool *cb; +}; struct MetaFactory: ::testing::Test { void TearDown() override { @@ -51,23 +79,19 @@ TEST_F(MetaFactory, Constructors) { ASSERT_NE(entt::resolve(entt::type_id()), entt::meta_type{}); ASSERT_EQ(entt::resolve(ctx, entt::type_id()), entt::meta_type{}); - - // this is because of entt::meta, which should be deprecated nowadays - ASSERT_FALSE(entt::resolve(entt::type_id()).is_integral()); + ASSERT_TRUE(entt::resolve(entt::type_id()).is_integral()); factory = entt::meta_factory{ctx}; ASSERT_NE(entt::resolve(entt::type_id()), entt::meta_type{}); ASSERT_NE(entt::resolve(ctx, entt::type_id()), entt::meta_type{}); - - // this is because of entt::meta, which should be deprecated nowadays - ASSERT_FALSE(entt::resolve(ctx, entt::type_id()).is_integral()); + ASSERT_TRUE(entt::resolve(ctx, entt::type_id()).is_integral()); } TEST_F(MetaFactory, Type) { using namespace entt::literals; - auto factory = entt::meta(); + entt::meta_factory factory{}; ASSERT_EQ(entt::resolve("foo"_hs), entt::meta_type{}); @@ -86,8 +110,8 @@ TEST_F(MetaFactory, Type) { ENTT_DEBUG_TEST_F(MetaFactoryDeathTest, Type) { using namespace entt::literals; - auto factory = entt::meta(); - auto other = entt::meta(); + entt::meta_factory factory{}; + entt::meta_factory other{}; factory.type("foo"_hs); @@ -95,7 +119,7 @@ ENTT_DEBUG_TEST_F(MetaFactoryDeathTest, Type) { } TEST_F(MetaFactory, Base) { - auto factory = entt::meta(); + entt::meta_factory factory{}; decltype(std::declval().base()) range{}; ASSERT_NE(entt::resolve(entt::type_id()), entt::meta_type{}); @@ -116,29 +140,29 @@ TEST_F(MetaFactory, Base) { } TEST_F(MetaFactory, Conv) { - clazz instance{3}; - auto factory = entt::meta(); + const clazz instance{3}; + entt::meta_factory factory{}; const entt::meta_any any = entt::forward_as_meta(instance); ASSERT_FALSE(any.allow_cast()); ASSERT_FALSE(any.allow_cast()); - factory.conv().conv<&clazz_to_string>(); + factory.conv().conv<&clazz::to_string>(); ASSERT_TRUE(any.allow_cast()); ASSERT_TRUE(any.allow_cast()); - ASSERT_EQ(any.allow_cast().cast(), static_cast(instance)); - ASSERT_EQ(any.allow_cast().cast(), clazz_to_string(instance)); + ASSERT_EQ(any.allow_cast().cast(), instance.get_int()); + ASSERT_EQ(any.allow_cast().cast(), clazz::to_string(instance)); } TEST_F(MetaFactory, Ctor) { - const int values[]{1, 3}; - auto factory = entt::meta(); + const std::array values{1, 3}; + entt::meta_factory factory{}; ASSERT_FALSE(entt::resolve().construct(values[0u])); ASSERT_FALSE(entt::resolve().construct(std::to_string(values[1u]))); - factory.ctor().ctor<&string_to_clazz>(); + factory.ctor().ctor<&clazz::from_string>(); const auto instance = entt::resolve().construct(values[0u]); const auto other = entt::resolve().construct(std::to_string(values[1u])); @@ -147,6 +171,339 @@ TEST_F(MetaFactory, Ctor) { ASSERT_TRUE(other); ASSERT_TRUE(instance.allow_cast()); ASSERT_TRUE(other.allow_cast()); - ASSERT_EQ(static_cast(instance.cast()), values[0u]); - ASSERT_EQ(static_cast(other.cast()), values[1u]); + ASSERT_EQ(instance.cast().get_int(), values[0u]); + ASSERT_EQ(other.cast().get_int(), values[1u]); +} + +TEST_F(MetaFactory, Dtor) { + bool check = false; + entt::meta_factory factory{}; + entt::meta_any any{std::in_place_type, check}; + + any.reset(); + + ASSERT_FALSE(check); + + factory.dtor<&dtor_callback::on_destroy>(); + any.emplace(check); + any.reset(); + + ASSERT_TRUE(check); +} + +TEST_F(MetaFactory, DataMemberObject) { + using namespace entt::literals; + + base instance{'c'}; + entt::meta_factory factory{}; + entt::meta_type type = entt::resolve(); + + ASSERT_FALSE(type.data("member"_hs)); + + factory.data<&base::member>("member"_hs); + type = entt::resolve(); + + ASSERT_TRUE(type.data("member"_hs)); + ASSERT_EQ(type.get("member"_hs, std::as_const(instance)), instance.member); + ASSERT_EQ(type.get("member"_hs, instance), instance.member); + ASSERT_FALSE(type.set("member"_hs, std::as_const(instance), instance.member)); + ASSERT_TRUE(type.set("member"_hs, instance, instance.member)); +} + +TEST_F(MetaFactory, DataPointer) { + using namespace entt::literals; + + entt::meta_factory factory{}; + entt::meta_type type = entt::resolve(); + + ASSERT_FALSE(type.data("value"_hs)); + + static int value = 1; + factory.data<&value>("value"_hs); + type = entt::resolve(); + + ASSERT_TRUE(type.data("value"_hs)); + ASSERT_EQ(type.get("value"_hs, {}), value); + ASSERT_TRUE(type.set("value"_hs, {}, value)); +} + +TEST_F(MetaFactory, DataValue) { + using namespace entt::literals; + + constexpr int value = 1; + entt::meta_factory factory{}; + entt::meta_type type = entt::resolve(); + + ASSERT_FALSE(type.data("value"_hs)); + + factory.data("value"_hs); + type = entt::resolve(); + + ASSERT_TRUE(type.data("value"_hs)); + ASSERT_EQ(type.get("value"_hs, {}), value); + ASSERT_FALSE(type.set("value"_hs, {}, value)); +} + +TEST_F(MetaFactory, DataGetterOnly) { + using namespace entt::literals; + + clazz instance{1}; + entt::meta_factory factory{}; + entt::meta_type type = entt::resolve(); + + ASSERT_FALSE(type.data("value"_hs)); + + factory.data("value"_hs); + type = entt::resolve(); + + ASSERT_TRUE(type.data("value"_hs)); + ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int()); + ASSERT_EQ(type.get("value"_hs, instance), instance.get_int()); + ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int())); + ASSERT_FALSE(type.set("value"_hs, instance, instance.get_int())); +} + +TEST_F(MetaFactory, DataSetterGetter) { + using namespace entt::literals; + + clazz instance{1}; + entt::meta_factory factory{}; + entt::meta_type type = entt::resolve(); + + ASSERT_FALSE(type.data("value"_hs)); + + factory.data<&clazz::set_int, &clazz::get_int>("value"_hs); + type = entt::resolve(); + + ASSERT_TRUE(type.data("value"_hs)); + ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int()); + ASSERT_EQ(type.get("value"_hs, instance), instance.get_int()); + ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int())); + ASSERT_TRUE(type.set("value"_hs, instance, instance.get_int())); +} + +TEST_F(MetaFactory, DataMultiSetterGetter) { + using namespace entt::literals; + + clazz instance{1}; + entt::meta_factory factory{}; + entt::meta_type type = entt::resolve(); + + ASSERT_FALSE(type.data("value"_hs)); + + factory.data, &clazz::get_int>("value"_hs); + type = entt::resolve(); + + ASSERT_TRUE(type.data("value"_hs)); + ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int()); + ASSERT_EQ(type.get("value"_hs, instance), instance.get_int()); + ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int())); + ASSERT_TRUE(type.set("value"_hs, instance, instance.get_int())); + ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), test::boxed_int{instance.get_int()})); + ASSERT_TRUE(type.set("value"_hs, instance, test::boxed_int{instance.get_int()})); +} + +TEST_F(MetaFactory, DataOverwrite) { + using namespace entt::literals; + + entt::meta_factory factory{}; + entt::meta_type type = entt::resolve(); + + ASSERT_FALSE(type.data("value"_hs)); + + factory.data("value"_hs); + type = entt::resolve(); + + ASSERT_TRUE(type.data("value"_hs)); + ASSERT_TRUE(type.data("value"_hs).is_const()); + + factory.data<&clazz::set_int, &clazz::get_int>("value"_hs); + type = entt::resolve(); + + ASSERT_TRUE(type.data("value"_hs)); + ASSERT_FALSE(type.data("value"_hs).is_const()); +} + +TEST_F(MetaFactory, Func) { + using namespace entt::literals; + + const clazz instance{1}; + entt::meta_factory factory{}; + entt::meta_type type = entt::resolve(); + + ASSERT_FALSE(type.func("func"_hs)); + + factory.func<&clazz::get_int>("func"_hs); + type = entt::resolve(); + + ASSERT_TRUE(type.func("func"_hs)); + ASSERT_TRUE(type.invoke("func"_hs, instance)); + ASSERT_EQ(type.invoke("func"_hs, instance).cast(), instance.get_int()); + ASSERT_FALSE(type.invoke("func"_hs, {})); +} + +TEST_F(MetaFactory, FuncOverload) { + using namespace entt::literals; + + clazz instance{1}; + entt::meta_factory factory{}; + entt::meta_type type = entt::resolve(); + + ASSERT_FALSE(type.func("func"_hs)); + + factory.func<&clazz::set_int>("func"_hs); + + ASSERT_TRUE(type.func("func"_hs)); + ASSERT_FALSE(type.func("func"_hs).next()); + + factory.func<&clazz::set_boxed_int>("func"_hs); + + ASSERT_TRUE(type.func("func"_hs)); + ASSERT_TRUE(type.func("func"_hs).next()); + ASSERT_FALSE(type.func("func"_hs).next().next()); + + ASSERT_TRUE(type.invoke("func"_hs, instance, 2)); + ASSERT_EQ(instance.get_int(), 2); + + ASSERT_TRUE(type.invoke("func"_hs, instance, test::boxed_int{3})); + ASSERT_EQ(instance.get_int(), 3); +} + +TEST_F(MetaFactory, Traits) { + using namespace entt::literals; + + entt::meta_factory{} + .data<&base::member>("member"_hs) + .func<&clazz::set_int>("func"_hs) + .func<&clazz::set_boxed_int>("func"_hs); + + entt::meta_type type = entt::resolve(); + + ASSERT_EQ(type.traits(), test::meta_traits::none); + ASSERT_EQ(type.data("member"_hs).traits(), test::meta_traits::none); + ASSERT_EQ(type.func("func"_hs).traits(), test::meta_traits::none); + ASSERT_EQ(type.func("func"_hs).next().traits(), test::meta_traits::none); + + entt::meta_factory{} + .traits(test::meta_traits::one | test::meta_traits::three) + .data<&base::member>("member"_hs) + .traits(test::meta_traits::one) + .func<&clazz::set_int>("func"_hs) + .traits(test::meta_traits::two) + .func<&clazz::set_boxed_int>("func"_hs) + .traits(test::meta_traits::three); + + // traits are copied and never refreshed + type = entt::resolve(); + + ASSERT_EQ(type.traits(), test::meta_traits::one | test::meta_traits::three); + ASSERT_EQ(type.data("member"_hs).traits(), test::meta_traits::one); + ASSERT_EQ(type.func("func"_hs).traits(), test::meta_traits::two); + ASSERT_EQ(type.func("func"_hs).next().traits(), test::meta_traits::three); +} + +TEST_F(MetaFactory, Custom) { + using namespace entt::literals; + + entt::meta_factory{} + .data<&base::member>("member"_hs) + .func<&clazz::set_int>("func"_hs) + .func<&clazz::set_boxed_int>("func"_hs); + + entt::meta_type type = entt::resolve(); + + ASSERT_EQ(static_cast(type.custom()), nullptr); + ASSERT_EQ(static_cast(type.data("member"_hs).custom()), nullptr); + ASSERT_EQ(static_cast(type.func("func"_hs).custom()), nullptr); + ASSERT_EQ(static_cast(type.func("func"_hs).next().custom()), nullptr); + + entt::meta_factory{} + .custom(0) + .data<&base::member>("member"_hs) + .custom(1) + .func<&clazz::set_int>("func"_hs) + .custom(2) + .func<&clazz::set_boxed_int>("func"_hs) + .custom(3); + + // custom data pointers are copied and never refreshed + type = entt::resolve(); + + ASSERT_EQ(static_cast(type.custom()), 0); + ASSERT_EQ(static_cast(type.data("member"_hs).custom()), 1); + ASSERT_EQ(static_cast(type.func("func"_hs).custom()), 2); + ASSERT_EQ(static_cast(type.func("func"_hs).next().custom()), 3); +} + +TEST_F(MetaFactory, Meta) { + entt::meta_ctx ctx{}; + + ASSERT_EQ(entt::resolve(entt::type_id()), entt::meta_type{}); + ASSERT_EQ(entt::resolve(ctx, entt::type_id()), entt::meta_type{}); + + auto factory = entt::meta(); + + ASSERT_NE(entt::resolve(entt::type_id()), entt::meta_type{}); + ASSERT_EQ(entt::resolve(ctx, entt::type_id()), entt::meta_type{}); + ASSERT_TRUE(entt::resolve(entt::type_id()).is_integral()); + + factory = entt::meta(ctx); + + ASSERT_NE(entt::resolve(entt::type_id()), entt::meta_type{}); + ASSERT_NE(entt::resolve(ctx, entt::type_id()), entt::meta_type{}); + ASSERT_TRUE(entt::resolve(ctx, entt::type_id()).is_integral()); +} + +TEST_F(MetaFactory, MetaReset) { + using namespace entt::literals; + + entt::meta_ctx ctx{}; + + entt::meta_factory{}.type("global"_hs); + entt::meta_factory{ctx}.type("local"_hs); + + ASSERT_TRUE(entt::resolve(entt::type_id())); + ASSERT_TRUE(entt::resolve(ctx, entt::type_id())); + + entt::meta_reset(); + + ASSERT_FALSE(entt::resolve(entt::type_id())); + ASSERT_TRUE(entt::resolve(ctx, entt::type_id())); + + entt::meta_reset(ctx); + + ASSERT_FALSE(entt::resolve(entt::type_id())); + ASSERT_FALSE(entt::resolve(ctx, entt::type_id())); + + entt::meta_factory{}.type("global"_hs); + entt::meta_factory{ctx}.type("local"_hs); + + ASSERT_TRUE(entt::resolve(entt::type_id())); + ASSERT_TRUE(entt::resolve(ctx, entt::type_id())); + + entt::meta_reset(); + + ASSERT_FALSE(entt::resolve(entt::type_id())); + ASSERT_TRUE(entt::resolve(ctx, entt::type_id())); + + entt::meta_reset(ctx); + + ASSERT_FALSE(entt::resolve(entt::type_id())); + ASSERT_FALSE(entt::resolve(ctx, entt::type_id())); + + entt::meta_factory{}.type("global"_hs); + entt::meta_factory{ctx}.type("local"_hs); + + ASSERT_TRUE(entt::resolve(entt::type_id())); + ASSERT_TRUE(entt::resolve(ctx, entt::type_id())); + + entt::meta_reset("global"_hs); + + ASSERT_FALSE(entt::resolve(entt::type_id())); + ASSERT_TRUE(entt::resolve(ctx, entt::type_id())); + + entt::meta_reset(ctx, "local"_hs); + + ASSERT_FALSE(entt::resolve(entt::type_id())); + ASSERT_FALSE(entt::resolve(ctx, entt::type_id())); } diff --git a/test/entt/meta/meta_func.cpp b/test/entt/meta/meta_func.cpp index e9e6901eab..5bce15fc03 100644 --- a/test/entt/meta/meta_func.cpp +++ b/test/entt/meta/meta_func.cpp @@ -93,24 +93,24 @@ struct MetaFunc: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("double"_hs) .func<&double_member>("member"_hs); - entt::meta() + entt::meta_factory{} .type("base"_hs) .func<&base::setter>("setter"_hs) .func("fake_member"_hs) .func("fake_const_member"_hs); - entt::meta() + entt::meta_factory{} .type("derived"_hs) .base() .func<&base::setter>("setter_from_base"_hs) .func<&base::getter>("getter_from_base"_hs) .func<&base::static_setter>("static_setter_from_base"_hs); - entt::meta() + entt::meta_factory{} .type("func"_hs) .func<&entt::registry::emplace_or_replace, entt::as_ref_t>("emplace"_hs) .traits(test::meta_traits::one | test::meta_traits::two | test::meta_traits::three) @@ -175,7 +175,7 @@ ENTT_DEBUG_TEST_F(MetaFuncDeathTest, UserTraits) { using traits_type = entt::internal::meta_traits; constexpr auto value = traits_type{static_cast>(traits_type::_user_defined_traits) + 1u}; - ASSERT_DEATH(entt::meta().func<&function::g>("g"_hs).traits(value), ""); + ASSERT_DEATH(entt::meta_factory{}.func<&function::g>("g"_hs).traits(value), ""); } TEST_F(MetaFunc, Custom) { @@ -591,7 +591,7 @@ TEST_F(MetaFunc, Overloaded) { ASSERT_FALSE(type.func("f2"_hs).next()); - entt::meta() + entt::meta_factory{} // this should not overwrite traits and custom data .func(&function::f)>("f2"_hs) // this should put traits and custom data on the new overload instead @@ -615,7 +615,7 @@ TEST_F(MetaFunc, Overloaded) { TEST_F(MetaFunc, OverloadedOrder) { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .func(&function::f)>("f2"_hs) .func(&function::f)>("f2"_hs); @@ -655,7 +655,7 @@ TEST_F(MetaFunc, ReRegistration) { ASSERT_TRUE(type.invoke("f1"_hs, instance, 0)); ASSERT_FALSE(type.invoke("f1"_hs, instance, 0, 0)); - entt::meta() + entt::meta_factory{} .func(&function::f)>("f"_hs) .func(&function::f)>("f"_hs); @@ -666,7 +666,7 @@ TEST_F(MetaFunc, ReRegistration) { ASSERT_TRUE(type.invoke("f"_hs, instance, 0)); ASSERT_TRUE(type.invoke("f"_hs, instance, 0, 0)); - entt::meta() + entt::meta_factory{} .func(&function::f)>("f"_hs) .traits(test::meta_traits::one) .custom(3) diff --git a/test/entt/meta/meta_handle.cpp b/test/entt/meta/meta_handle.cpp index 55c9ec7f98..cfc8cc53b9 100644 --- a/test/entt/meta/meta_handle.cpp +++ b/test/entt/meta/meta_handle.cpp @@ -20,7 +20,7 @@ struct MetaHandle: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("clazz"_hs) .func<&clazz::incr>("incr"_hs) .func<&clazz::decr>("decr"_hs); diff --git a/test/entt/meta/meta_range.cpp b/test/entt/meta/meta_range.cpp index f30a71d940..50a9d57c55 100644 --- a/test/entt/meta/meta_range.cpp +++ b/test/entt/meta/meta_range.cpp @@ -12,7 +12,9 @@ struct MetaRange: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta().type("int"_hs).data<2>("answer"_hs); + entt::meta_factory{} + .type("int"_hs) + .data<2>("answer"_hs); } void TearDown() override { @@ -73,7 +75,7 @@ TEST_F(MetaRange, Iterator) { ASSERT_GT(end, begin); ASSERT_GE(end, range.end()); - entt::meta().type("double"_hs); + entt::meta_factory{}.type("double"_hs); range = entt::resolve(); begin = range.begin(); diff --git a/test/entt/meta/meta_type.cpp b/test/entt/meta/meta_type.cpp index 36ed3b3cbd..2fe4f9b08b 100644 --- a/test/entt/meta/meta_type.cpp +++ b/test/entt/meta/meta_type.cpp @@ -105,37 +105,37 @@ struct MetaType: ::testing::Test { void SetUp() override { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("double"_hs) .traits(test::meta_traits::one) .data, get>("var"_hs); - entt::meta() + entt::meta_factory{} .type("unsigned int"_hs) .traits(test::meta_traits::two) .data<0u>("min"_hs) .data<128u>("max"_hs); - entt::meta() + entt::meta_factory{} .type("base"_hs) .data<&base::value>("value"_hs); - entt::meta() + entt::meta_factory{} .type("derived"_hs) .traits(test::meta_traits::one | test::meta_traits::three) .base(); - entt::meta() + entt::meta_factory{} .type("abstract"_hs) .func<&abstract::func>("func"_hs) .func<&abstract::base_only>("base_only"_hs); - entt::meta() + entt::meta_factory{} .type("concrete"_hs) .base() .base(); - entt::meta() + entt::meta_factory{} .type("overloaded_func"_hs) .func(&overloaded_func::f)>("f"_hs) .func(&overloaded_func::f)>("f"_hs) @@ -143,14 +143,14 @@ struct MetaType: ::testing::Test { .func(&overloaded_func::f)>("f"_hs) .func(&overloaded_func::f)>("f"_hs); - entt::meta() + entt::meta_factory{} .type("property"_hs) .traits(test::meta_traits::two | test::meta_traits::three) .data("value"_hs) .data("other"_hs) .data, get>("var"_hs); - entt::meta() + entt::meta_factory{} .type("class"_hs) .custom('c') .ctor() @@ -202,7 +202,7 @@ TEST_F(MetaType, UserTraits) { ENTT_DEBUG_TEST_F(MetaTypeDeathTest, UserTraits) { using traits_type = entt::internal::meta_traits; constexpr auto value = traits_type{static_cast>(traits_type::_user_defined_traits) + 1u}; - ASSERT_DEATH(entt::meta().traits(value), ""); + ASSERT_DEATH(entt::meta_factory{}.traits(value), ""); } TEST_F(MetaType, Custom) { @@ -602,7 +602,7 @@ TEST_F(MetaType, Reset) { // implicitly generated default constructor is not cleared ASSERT_TRUE(entt::resolve().construct()); - entt::meta().type("class"_hs); + entt::meta_factory{}.type("class"_hs); ASSERT_TRUE(entt::resolve("class"_hs)); } @@ -735,7 +735,7 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) { ASSERT_FALSE(entt::resolve().data("value"_hs)); ASSERT_FALSE(entt::resolve().func("member"_hs)); - entt::meta().type("double"_hs); + entt::meta_factory{}.type("double"_hs); entt::meta_any any{3.}; ASSERT_TRUE(any); @@ -745,14 +745,14 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) { ASSERT_FALSE(entt::resolve("derived"_hs)); ASSERT_TRUE(entt::resolve("double"_hs)); - entt::meta() + entt::meta_factory{} .traits(test::meta_traits::one) .custom(3) // this should not overwrite traits and custom data .type("base"_hs); // this should not overwrite traits and custom data - [[maybe_unused]] auto factory = entt::meta(); + [[maybe_unused]] entt::meta_factory factory{}; ASSERT_EQ(entt::resolve().traits(), test::meta_traits::one); ASSERT_NE(static_cast(entt::resolve("base"_hs).custom()), nullptr); @@ -776,13 +776,13 @@ TEST_F(MetaType, ReRegistration) { ASSERT_EQ(count, 0); ASSERT_TRUE(entt::resolve("double"_hs)); - entt::meta() + entt::meta_factory{} .type("real"_hs) .traits(test::meta_traits::one) .custom(3); // this should not overwrite traits and custom data - entt::meta().type("real"_hs); + entt::meta_factory{}.type("real"_hs); ASSERT_FALSE(entt::resolve("double"_hs)); ASSERT_TRUE(entt::resolve("real"_hs)); @@ -795,10 +795,10 @@ TEST_F(MetaType, ReRegistration) { TEST_F(MetaType, NameCollision) { using namespace entt::literals; - ASSERT_NO_THROW(entt::meta().type("class"_hs)); + ASSERT_NO_THROW(entt::meta_factory{}.type("class"_hs)); ASSERT_TRUE(entt::resolve("class"_hs)); - ASSERT_NO_THROW(entt::meta().type("quux"_hs)); + ASSERT_NO_THROW(entt::meta_factory{}.type("quux"_hs)); ASSERT_FALSE(entt::resolve("class"_hs)); ASSERT_TRUE(entt::resolve("quux"_hs)); } @@ -806,5 +806,5 @@ TEST_F(MetaType, NameCollision) { ENTT_DEBUG_TEST_F(MetaTypeDeathTest, NameCollision) { using namespace entt::literals; - ASSERT_DEATH(entt::meta().type("abstract"_hs), ""); + ASSERT_DEATH(entt::meta_factory{}.type("abstract"_hs), ""); } diff --git a/test/example/entity_copy.cpp b/test/example/entity_copy.cpp index fc754e71f1..838d005154 100644 --- a/test/example/entity_copy.cpp +++ b/test/example/entity_copy.cpp @@ -29,7 +29,7 @@ meta_mixin::meta_mixin(const allocator_type &allocator) : Type{allocator} { using namespace entt::literals; - entt::meta() + entt::meta_factory{} // cross registry, same type .template func &(const entt::id_type)>(&entt::basic_registry::storage), entt::as_ref_t>("storage"_hs) // cross registry, different types diff --git a/test/lib/meta/plugin/plugin.cpp b/test/lib/meta/plugin/plugin.cpp index 40fe7869b9..dc7cd38619 100644 --- a/test/lib/meta/plugin/plugin.cpp +++ b/test/lib/meta/plugin/plugin.cpp @@ -15,12 +15,12 @@ test::boxed_int create_boxed_int(int value) { void set_up() { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("boxed_int"_hs) .ctor<&create_boxed_int>() .data<&test::boxed_int::value>("value"_hs); - entt::meta() + entt::meta_factory{} .type("empty"_hs) .ctor<>(); } diff --git a/test/lib/meta/plugin_std/plugin.cpp b/test/lib/meta/plugin_std/plugin.cpp index 40fe7869b9..dc7cd38619 100644 --- a/test/lib/meta/plugin_std/plugin.cpp +++ b/test/lib/meta/plugin_std/plugin.cpp @@ -15,12 +15,12 @@ test::boxed_int create_boxed_int(int value) { void set_up() { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("boxed_int"_hs) .ctor<&create_boxed_int>() .data<&test::boxed_int::value>("value"_hs); - entt::meta() + entt::meta_factory{} .type("empty"_hs) .ctor<>(); } diff --git a/test/lib/meta/shared/lib.cpp b/test/lib/meta/shared/lib.cpp index 8c69e37e8a..be9dc6790d 100644 --- a/test/lib/meta/shared/lib.cpp +++ b/test/lib/meta/shared/lib.cpp @@ -18,16 +18,16 @@ ENTT_API void share(const entt::locator::node_type &handle) { ENTT_API void set_up() { using namespace entt::literals; - entt::meta() + entt::meta_factory{} .type("boxed_int"_hs) .ctor<&create_boxed_int>() .data<&test::boxed_int::value>("value"_hs); - entt::meta() + entt::meta_factory{} .type("empty"_hs) .ctor<>(); - static_cast(entt::meta()); + static_cast(entt::meta_factory{}); } ENTT_API void tear_down() {