From 0ec755fccf2e2c8a6f804c1f02b6fe1f4a264a3a Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Fri, 15 Jan 2021 14:34:27 +0100 Subject: [PATCH] meta: iterable base types as instances of meta_type --- docs/md/meta.md | 16 +++++----------- src/entt/meta/meta.hpp | 27 +++++++++++++++++++++++++++ src/entt/meta/range.hpp | 9 +++++---- test/entt/meta/meta_type.cpp | 16 ++++++++++++++++ 4 files changed, 53 insertions(+), 15 deletions(-) diff --git a/docs/md/meta.md b/docs/md/meta.md index be5f333d3..362ecefb0 100644 --- a/docs/md/meta.md +++ b/docs/md/meta.md @@ -309,11 +309,8 @@ The meta objects that compose a meta type are accessed in the following ways: auto base = entt::resolve().base("base"_hs); ``` - The returned type is `meta_base` and may be invalid if there is no meta base - object associated with the given identifier.
- Meta bases aren't meant to be used directly, even though they are freely - accessible. They expose only a few methods to use to know the meta type of the - base class and to convert a raw pointer between types. + The returned type is `meta_type` and may be invalid if there is no meta base + object associated with the given identifier. All the objects thus obtained as well as the meta types can be explicitly converted to a boolean value to check if they are valid: @@ -325,7 +322,7 @@ if(auto func = entt::resolve().func("member"_hs); func) { ``` Furthermore, all them are also returned by specific overloads that provide the -caller with iterable objects. As an example: +caller with iterable ranges of top-level elements. As an example: ```cpp for(auto data = entt::resolve().data()) { @@ -345,11 +342,8 @@ member function in its API. Destructors are invoked implicitly by `meta_any` behind the scenes and users have not to deal with them explicitly. Furthermore, they have no name, cannot be searched and wouldn't have member functions to expose anyway.
-Similarly, conversion functions and base types aren't directly accessible. They -are used internally by `meta_any` and the meta objects when needed.
-It wouldn't make sense to give direct access to these elements and to open the -doors to the possibility of making mistakes. On the other side, the library -already offers enough ways to use them correctly. +Similarly, conversion functions aren't directly accessible. They are used +internally by `meta_any` and the meta objects when needed. Meta types and meta objects in general contain much more than what is said: a plethora of functions in addition to those listed whose purposes and uses go diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index b6ff1f24b..f48d383d4 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -1180,6 +1180,8 @@ class meta_type { public: /*! @brief Node type. */ using node_type = internal::meta_type_node; + /*! @brief Node type. */ + using base_node_type = internal::meta_base_node; /*! @brief Unsigned integer type. */ using size_type = typename node_type::size_type; @@ -1188,6 +1190,14 @@ public: : node{curr} {} + /** + * @brief Constructs an instance from a given base node. + * @param curr The base node with which to construct the instance. + */ + meta_type(base_node_type *curr) ENTT_NOEXCEPT + : node{curr ? curr->type() : nullptr} + {} + /** * @brief Returns the type info object of the underlying type. * @return The type info object of the underlying type. @@ -1366,6 +1376,23 @@ public: return node->remove_extent(); } + /** + * @brief Returns a range to use to visit top-level base meta types. + * @return An iterable range to use to visit top-level base meta types. + */ + [[nodiscard]] meta_range base() const ENTT_NOEXCEPT { + return node->base; + } + + /** + * @brief Returns the base meta type associated with a given identifier. + * @param id Unique identifier. + * @return The base meta type associated with the given identifier, if any. + */ + [[nodiscard]] meta_type base(const id_type id) const { + return internal::meta_visit<&node_type::base>([id](const auto *curr) { return curr->type()->id == id; }, node); + } + /** * @brief Returns a range to use to visit top-level constructors. * @return An iterable range to use to visit top-level constructors. diff --git a/src/entt/meta/range.hpp b/src/entt/meta/range.hpp index 7f30e4e43..7b54525fd 100644 --- a/src/entt/meta/range.hpp +++ b/src/entt/meta/range.hpp @@ -11,9 +11,10 @@ namespace entt { /** * @brief Iterable range to use to iterate all types of meta objects. - * @tparam Type Type of meta objects iterated. + * @tparam Type Type of meta objects returned. + * @tparam Node Type of meta nodes iterated. */ -template +template class meta_range { struct range_iterator { using difference_type = std::ptrdiff_t; @@ -21,7 +22,7 @@ class meta_range { using pointer = void; using reference = value_type; using iterator_category = std::input_iterator_tag; - using node_type = typename Type::node_type; + using node_type = Node; range_iterator() ENTT_NOEXCEPT = default; @@ -56,7 +57,7 @@ class meta_range { public: /*! @brief Node type. */ - using node_type = typename Type::node_type; + using node_type = Node; /*! @brief Input iterator type. */ using iterator = range_iterator; diff --git a/test/entt/meta/meta_type.cpp b/test/entt/meta/meta_type.cpp index b3ed3d4cf..2b0750fb4 100644 --- a/test/entt/meta/meta_type.cpp +++ b/test/entt/meta/meta_type.cpp @@ -251,6 +251,22 @@ TEST_F(MetaType, RemoveExtent) { ASSERT_EQ(entt::resolve().remove_extent(), entt::resolve()); } +TEST_F(MetaType, Base) { + using namespace entt::literals; + + auto type = entt::resolve(); + bool iterate = false; + + for(auto curr: type.base()) { + ASSERT_EQ(curr, entt::resolve()); + iterate = true; + } + + ASSERT_TRUE(iterate); + ASSERT_EQ(type.base("base"_hs), entt::resolve()); + ASSERT_FALSE(type.base("esabe"_hs)); +} + TEST_F(MetaType, Ctor) { auto type = entt::resolve(); int counter{};