diff --git a/TODO b/TODO index 32c8111c9..823598635 100644 --- a/TODO +++ b/TODO @@ -17,14 +17,10 @@ * add take functionality, eg registry.take(entity, other); where it takes the entity and all its components from registry and move them to other * add opaque input iterators to views and groups that return tuples (proxy), multi-pass guaranteed * add fast lane for raw iterations, extend mt doc to describe allowed add/remove with pre-allocations on fast lanes -* review 64 bit id: user defined area + dedicated member on the registry to set it -* early out in views using bitmasks with bloom filter like access based on modulus - - standard each, use bitmask to speed up the whole thing and avoid accessing the pools to test for the page - - iterator based each with a couple of iterators passed from outside (use bitmask + has) -* stable component handle that isn't affected by reallocations * multi component registry::remove and some others? * can I use opaque connection also for the emitter? * built-in support for dual (or N-) buffering +* meta: opaque references and pointers TODO * registry::sort also for types that are part of a group (untracked items only) diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp index 31334221a..29453eeb8 100644 --- a/src/entt/meta/factory.hpp +++ b/src/entt/meta/factory.hpp @@ -244,8 +244,8 @@ public: type, nullptr, &internal::meta_info::resolve, - [](void *instance) -> meta_any { - return static_cast(*static_cast(instance)); + [](const void *instance) -> meta_any { + return static_cast(*static_cast(instance)); }, []() ENTT_NOEXCEPT -> meta_conv { return &node; @@ -260,12 +260,50 @@ public: return *this; } + /** + * @brief Assigns a meta conversion function to a meta type. + * + * Conversion functions can be either free functions or member + * functions.
+ * In case of free functions, they must accept a reference to an instance of + * the parent type as an argument. Otherwise, they must accept no arguments + * at all. + * + * @tparam Candidate The actual function to use for the conversion. + * @return A meta factory for the parent type. + */ + template + meta_factory conv() ENTT_NOEXCEPT { + using conv_type = std::invoke_result_t; + auto * const type = internal::meta_info::resolve(); + + static internal::meta_conv_node node{ + &internal::meta_info::template conv, + type, + nullptr, + &internal::meta_info::resolve, + [](const void *instance) -> meta_any { + return std::invoke(Candidate, *static_cast(instance)); + }, + []() ENTT_NOEXCEPT -> meta_conv { + return &node; + } + }; + + node.next = type->conv; + ENTT_ASSERT((!internal::meta_info::template conv)); + internal::meta_info::template conv = &node; + type->conv = &node; + + return *this; + } + /** * @brief Assigns a meta constructor to a meta type. * - * Free functions can be assigned to meta types in the role of - * constructors. All that is required is that they return an instance of the - * underlying type.
+ * Free functions can be assigned to meta types in the role of constructors. + * All that is required is that they return an instance of the underlying + * type.
* From a client's point of view, nothing changes if a constructor of a meta * type is a built-in one or a free function. * diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index 861b47a45..eb4fc6829 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -63,7 +63,7 @@ struct meta_conv_node { meta_type_node * const parent; meta_conv_node * next; meta_type_node *(* const type)() ENTT_NOEXCEPT; - meta_any(* const conv)(void *); + meta_any(* const conv)(const void *); meta_conv(* const meta)() ENTT_NOEXCEPT; }; @@ -982,7 +982,7 @@ public: * @param instance The instance to convert. * @return An opaque pointer to the instance to convert. */ - meta_any convert(void *instance) const ENTT_NOEXCEPT { + meta_any convert(const void *instance) const ENTT_NOEXCEPT { return node->conv(instance); } diff --git a/test/entt/meta/meta.cpp b/test/entt/meta/meta.cpp index d37f13dff..0e285aa70 100644 --- a/test/entt/meta/meta.cpp +++ b/test/entt/meta/meta.cpp @@ -56,6 +56,9 @@ struct derived_type: base_type { : i{value}, c{character} {} + int f() const { return i; } + static char g(const derived_type &type) { return type.c; } + const int i{}; const char c{}; }; @@ -144,7 +147,9 @@ struct Meta: public ::testing::Test { entt::reflect("derived"_hs, std::make_pair(properties::prop_int, 99)) .base() .ctor(std::make_pair(properties::prop_bool, false)) - .ctor<&derived_factory>(std::make_pair(properties::prop_int, 42)); + .ctor<&derived_factory>(std::make_pair(properties::prop_int, 42)) + .conv<&derived_type::f>() + .conv<&derived_type::g>(); entt::reflect("empty"_hs) .dtor<&empty_type::destroy>(); @@ -849,6 +854,38 @@ TEST_F(Meta, MetaConv) { ASSERT_EQ(any.cast(), 3); } +TEST_F(Meta, MetaConvAsFreeFunctions) { + auto conv = entt::resolve().conv(); + derived_type derived{derived_type{}, 42, 'c'}; + + ASSERT_TRUE(conv); + ASSERT_NE(conv, entt::meta_conv{}); + ASSERT_EQ(conv.parent(), entt::resolve()); + ASSERT_EQ(conv.type(), entt::resolve()); + + auto any = conv.convert(&derived); + + ASSERT_TRUE(any); + ASSERT_EQ(any.type(), entt::resolve()); + ASSERT_EQ(any.cast(), 42); +} + +TEST_F(Meta, MetaConvAsMemberFunctions) { + auto conv = entt::resolve().conv(); + derived_type derived{derived_type{}, 42, 'c'}; + + ASSERT_TRUE(conv); + ASSERT_NE(conv, entt::meta_conv{}); + ASSERT_EQ(conv.parent(), entt::resolve()); + ASSERT_EQ(conv.type(), entt::resolve()); + + auto any = conv.convert(&derived); + + ASSERT_TRUE(any); + ASSERT_EQ(any.type(), entt::resolve()); + ASSERT_EQ(any.cast(), 'c'); +} + TEST_F(Meta, MetaCtor) { auto ctor = entt::resolve().ctor();