Просмотр исходного кода

meta: iterable base types as instances of meta_type

Michele Caini 5 лет назад
Родитель
Сommit
0ec755fccf
4 измененных файлов с 53 добавлено и 15 удалено
  1. 5 11
      docs/md/meta.md
  2. 27 0
      src/entt/meta/meta.hpp
  3. 5 4
      src/entt/meta/range.hpp
  4. 16 0
      test/entt/meta/meta_type.cpp

+ 5 - 11
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<derived_type>().base("base"_hs);
   auto base = entt::resolve<derived_type>().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.<br/>
-  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
 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:
 converted to a boolean value to check if they are valid:
@@ -325,7 +322,7 @@ if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
 ```
 ```
 
 
 Furthermore, all them are also returned by specific overloads that provide the
 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
 ```cpp
 for(auto data = entt::resolve<my_type>().data()) {
 for(auto data = entt::resolve<my_type>().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,
 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
 they have no name, cannot be searched and wouldn't have member functions to
 expose anyway.<br/>
 expose anyway.<br/>
-Similarly, conversion functions and base types aren't directly accessible. They
-are used internally by `meta_any` and the meta objects when needed.<br/>
-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
 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
 plethora of functions in addition to those listed whose purposes and uses go

+ 27 - 0
src/entt/meta/meta.hpp

@@ -1180,6 +1180,8 @@ class meta_type {
 public:
 public:
     /*! @brief Node type. */
     /*! @brief Node type. */
     using node_type = internal::meta_type_node;
     using node_type = internal::meta_type_node;
+    /*! @brief Node type. */
+    using base_node_type = internal::meta_base_node;
     /*! @brief Unsigned integer type. */
     /*! @brief Unsigned integer type. */
     using size_type = typename node_type::size_type;
     using size_type = typename node_type::size_type;
 
 
@@ -1188,6 +1190,14 @@ public:
         : node{curr}
         : 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.
      * @brief Returns the type info object of the underlying type.
      * @return 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();
         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<meta_type, internal::meta_base_node> 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.
      * @brief Returns a range to use to visit top-level constructors.
      * @return An iterable range to use to visit top-level constructors.
      * @return An iterable range to use to visit top-level constructors.

+ 5 - 4
src/entt/meta/range.hpp

@@ -11,9 +11,10 @@ namespace entt {
 
 
 /**
 /**
  * @brief Iterable range to use to iterate all types of meta objects.
  * @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<typename Type>
+template<typename Type, typename Node = typename Type::node_type>
 class meta_range {
 class meta_range {
     struct range_iterator {
     struct range_iterator {
         using difference_type = std::ptrdiff_t;
         using difference_type = std::ptrdiff_t;
@@ -21,7 +22,7 @@ class meta_range {
         using pointer = void;
         using pointer = void;
         using reference = value_type;
         using reference = value_type;
         using iterator_category = std::input_iterator_tag;
         using iterator_category = std::input_iterator_tag;
-        using node_type = typename Type::node_type;
+        using node_type = Node;
 
 
         range_iterator() ENTT_NOEXCEPT = default;
         range_iterator() ENTT_NOEXCEPT = default;
 
 
@@ -56,7 +57,7 @@ class meta_range {
 
 
 public:
 public:
     /*! @brief Node type. */
     /*! @brief Node type. */
-    using node_type = typename Type::node_type;
+    using node_type = Node;
     /*! @brief Input iterator type. */
     /*! @brief Input iterator type. */
     using iterator = range_iterator;
     using iterator = range_iterator;
 
 

+ 16 - 0
test/entt/meta/meta_type.cpp

@@ -251,6 +251,22 @@ TEST_F(MetaType, RemoveExtent) {
     ASSERT_EQ(entt::resolve<derived_t>().remove_extent(), entt::resolve<derived_t>());
     ASSERT_EQ(entt::resolve<derived_t>().remove_extent(), entt::resolve<derived_t>());
 }
 }
 
 
+TEST_F(MetaType, Base) {
+    using namespace entt::literals;
+
+    auto type = entt::resolve<derived_t>();
+    bool iterate = false;
+
+    for(auto curr: type.base()) {
+        ASSERT_EQ(curr, entt::resolve<base_t>());
+        iterate = true;
+    }
+
+    ASSERT_TRUE(iterate);
+    ASSERT_EQ(type.base("base"_hs), entt::resolve<base_t>());
+    ASSERT_FALSE(type.base("esabe"_hs));
+}
+
 TEST_F(MetaType, Ctor) {
 TEST_F(MetaType, Ctor) {
     auto type = entt::resolve<clazz_t>();
     auto type = entt::resolve<clazz_t>();
     int counter{};
     int counter{};