Browse Source

type_info:
* make the API closer to that of std::type_info
* remove the ::seq member function
* rename :.hash to ::hash_code

Michele Caini 4 years ago
parent
commit
6943822fed

+ 64 - 39
docs/md/core.md

@@ -17,7 +17,8 @@
   * [Small buffer optimization](#small-buffer-optimization)
   * [Small buffer optimization](#small-buffer-optimization)
   * [Alignment requirement](#alignment-requirement)
   * [Alignment requirement](#alignment-requirement)
 * [Type support](#type-support)
 * [Type support](#type-support)
-  * [Type info](#type-info)
+  * [Built-in RTTI support](#built-in-rtti-support)
+    * [Type info](#type-info)
     * [Almost unique identifiers](#almost-unique-identifiers)
     * [Almost unique identifiers](#almost-unique-identifiers)
   * [Type traits](#type-traits)
   * [Type traits](#type-traits)
     * [Size of](#size-of)
     * [Size of](#size-of)
@@ -369,30 +370,19 @@ that won't be able to interoperate with each other.
 It also offers additional features that are not yet available in the standard
 It also offers additional features that are not yet available in the standard
 library or that will never be.
 library or that will never be.
 
 
-## Type info
+## Built-in RTTI support
 
 
-The `type_info` class isn't a drop-in replacement for `std::type_info` but can
-provide similar information which are not implementation defined and don't
-require to enable RTTI.<br/>
-Therefore, they can sometimes be even more reliable than those obtained
-otherwise.
+Runtime type identification support (or RTTI) is one of the most frequently
+disabled features in the C++ world, especially in the gaming sector. Regardless
+of the reasons for this, it's often a shame not to be able to rely on opaque
+type information at runtime.<br/>
+The library tries to fill this gap by offering a built-in system that doesn't
+serve as a replacement but comes very close to being one and offers similar
+information to that provided by its counterpart.
 
 
-A type info object is an opaque class that is also copy and move constructible.
-This class is returned by the `type_id` function template:
-
-```cpp
-auto info = entt::type_id<a_type>();
-```
-
-These are the information made available by this object:
-
-* The unique, sequential identifier associated with a given type:
-
-  ```cpp
-  auto index = entt::type_id<a_type>().seq();
-  ```
+Basically, the whole system relies on a handful of classes. In particular:
 
 
-  This is also an alias for the following:
+* An unique, sequential identifier associated with a given type:
 
 
   ```cpp
   ```cpp
   auto index = entt::type_seq<a_type>::value();
   auto index = entt::type_seq<a_type>::value();
@@ -426,13 +416,7 @@ These are the information made available by this object:
   The tool is widely used within `EnTT`. Generating indices not sequentially
   The tool is widely used within `EnTT`. Generating indices not sequentially
   would break an assumption and would likely lead to undesired behaviors.
   would break an assumption and would likely lead to undesired behaviors.
 
 
-* The hash value associated with a given type:
-
-  ```cpp
-  auto hash = entt::type_id<a_type>().hash();
-  ```
-
-  This is also an alias for the following:
+* A hash value associated with a given type:
 
 
   ```cpp
   ```cpp
   auto hash = entt::type_hash<a_type>::value();
   auto hash = entt::type_hash<a_type>::value();
@@ -440,9 +424,7 @@ These are the information made available by this object:
 
 
   In general, the `value` function exposed by `type_hash` is also `constexpr`
   In general, the `value` function exposed by `type_hash` is also `constexpr`
   but this isn't guaranteed for all compilers and platforms (although it's valid
   but this isn't guaranteed for all compilers and platforms (although it's valid
-  with the most well-known and popular ones).<br/>
-  The `hash` function offered by the type info object isn't `constexpr` in any
-  case instead.
+  with the most well-known and popular ones).
 
 
   This function **can** use non-standard features of the language for its own
   This function **can** use non-standard features of the language for its own
   purposes. This makes it possible to provide compile-time identifiers that
   purposes. This makes it possible to provide compile-time identifiers that
@@ -456,13 +438,7 @@ These are the information made available by this object:
   specialized in order to customize its behavior globally or on a per-type or
   specialized in order to customize its behavior globally or on a per-type or
   per-traits basis.
   per-traits basis.
 
 
-* The name associated with a given type:
-
-  ```cpp
-  auto name = entt::type_id<my_type>().name();
-  ```
-
-  This is also an alias for the following:
+* A name associated with a given type:
 
 
   ```cpp
   ```cpp
   auto name = entt::type_name<a_type>::value();
   auto name = entt::type_name<a_type>::value();
@@ -495,6 +471,55 @@ These are the information made available by this object:
   specialized in order to customize its behavior globally or on a per-type or
   specialized in order to customize its behavior globally or on a per-type or
   per-traits basis.
   per-traits basis.
 
 
+These are then combined into utilities that aim to offer an API that is somewhat
+similar to that offered by the language.
+
+### Type info
+
+The `type_info` class isn't a drop-in replacement for `std::type_info` but can
+provide similar information which are not implementation defined and don't
+require to enable RTTI.<br/>
+Therefore, they can sometimes be even more reliable than those obtained
+otherwise.
+
+A type info object is an opaque class that is also copy and move constructible.
+This class is returned by the `type_id` function template:
+
+```cpp
+auto info = entt::type_id<a_type>();
+```
+
+These are the information made available by this object:
+
+* An unique, sequential identifier associated with a given type:
+
+  ```cpp
+  auto index = entt::type_id<a_type>().seq();
+  ```
+
+  This is also an alias for the following:
+
+  ```cpp
+  auto index = entt::type_seq<a_type>::value();
+  ```
+
+* A hash value associated with a given type:
+
+  ```cpp
+  auto hash = entt::type_id<a_type>().hash_code();
+  ```
+
+  This is also an alias for the following:
+
+  ```cpp
+  auto hash = entt::type_hash<a_type>::value();
+  ```
+
+Where all accessed features are available at compile-time, the `type_info` class
+is also fully `constexpr`. However, this cannot be guaranteed in advance and
+depends mainly on the compiler in use and any specializations of the classes
+described above.
+
 ### Almost unique identifiers
 ### Almost unique identifiers
 
 
 Since the default non-standard, compile-time implementation of `type_hash` makes
 Since the default non-standard, compile-time implementation of `type_hash` makes

+ 3 - 14
src/entt/core/type_info.hpp

@@ -151,8 +151,7 @@ struct type_name final {
 struct type_info final {
 struct type_info final {
     /*! @brief Default constructor. */
     /*! @brief Default constructor. */
     constexpr type_info() ENTT_NOEXCEPT
     constexpr type_info() ENTT_NOEXCEPT
-        : index{},
-          identifier{},
+        : identifier{},
           alias{}
           alias{}
     {}
     {}
 
 
@@ -167,8 +166,7 @@ struct type_info final {
      */
      */
     template<typename Type>
     template<typename Type>
     constexpr type_info(std::in_place_type_t<Type>) ENTT_NOEXCEPT
     constexpr type_info(std::in_place_type_t<Type>) ENTT_NOEXCEPT
-        : index{&type_seq<std::remove_reference_t<std::remove_const_t<Type>>>::value},
-          identifier{type_hash<std::remove_reference_t<std::remove_const_t<Type>>>::value()},
+        : identifier{type_hash<std::remove_reference_t<std::remove_const_t<Type>>>::value()},
           alias{type_name<std::remove_reference_t<std::remove_const_t<Type>>>::value()}
           alias{type_name<std::remove_reference_t<std::remove_const_t<Type>>>::value()}
     {}
     {}
 
 
@@ -192,19 +190,11 @@ struct type_info final {
         return alias.data() != nullptr;
         return alias.data() != nullptr;
     }
     }
 
 
-    /**
-     * @brief Type sequential identifier.
-     * @return Type sequential identifier.
-     */
-    [[nodiscard]] constexpr id_type seq() const ENTT_NOEXCEPT {
-        return index();
-    }
-
     /**
     /**
      * @brief Type hash.
      * @brief Type hash.
      * @return Type hash.
      * @return Type hash.
      */
      */
-    [[nodiscard]] constexpr id_type hash() const ENTT_NOEXCEPT {
+    [[nodiscard]] constexpr id_type hash_code() const ENTT_NOEXCEPT {
         return identifier;
         return identifier;
     }
     }
 
 
@@ -226,7 +216,6 @@ struct type_info final {
     }
     }
 
 
 private:
 private:
-    id_type(* index)();
     id_type identifier;
     id_type identifier;
     std::string_view alias;
     std::string_view alias;
 };
 };

+ 8 - 6
src/entt/entity/registry.hpp

@@ -183,14 +183,16 @@ public:
      * empty and thus invalid element otherwise.
      * empty and thus invalid element otherwise.
      */
      */
     poly_storage & storage(const type_info info) {
     poly_storage & storage(const type_info info) {
-        ENTT_ASSERT(info.seq() < pools.size() && pools[info.seq()].poly, "Storage not available");
-        return pools[info.seq()].poly;
+        auto it = std::find_if(pools.begin(), pools.end(), [info](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash_code() == info.hash_code(); });
+        ENTT_ASSERT(it != pools.end(), "Storage not available");
+        return it->poly;
     }
     }
 
 
     /*! @copydoc storage */
     /*! @copydoc storage */
     const poly_storage & storage(const type_info info) const {
     const poly_storage & storage(const type_info info) const {
-        ENTT_ASSERT(info.seq() < pools.size() && pools[info.seq()].poly, "Storage not available");
-        return pools[info.seq()].poly;
+        auto it = std::find_if(pools.cbegin(), pools.cend(), [info](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash_code() == info.hash_code(); });
+        ENTT_ASSERT(it != pools.cend(), "Storage not available");
+        return it->poly;
     }
     }
 
 
     /**
     /**
@@ -1165,12 +1167,12 @@ public:
         std::vector<const basic_common_type *> filter(std::distance(from, to));
         std::vector<const basic_common_type *> filter(std::distance(from, to));
 
 
         std::transform(first, last, component.begin(), [this](const auto ctype) {
         std::transform(first, last, component.begin(), [this](const auto ctype) {
-            const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash() == ctype; });
+            const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash_code() == ctype; });
             return it == pools.cend() ? nullptr : it->pool.get();
             return it == pools.cend() ? nullptr : it->pool.get();
         });
         });
 
 
         std::transform(from, to, filter.begin(), [this](const auto ctype) {
         std::transform(from, to, filter.begin(), [this](const auto ctype) {
-            const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash() == ctype; });
+            const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash_code() == ctype; });
             return it == pools.cend() ? nullptr : it->pool.get();
             return it == pools.cend() ? nullptr : it->pool.get();
         });
         });
 
 

+ 4 - 5
test/entt/core/type_info.cpp

@@ -62,8 +62,7 @@ TEST(TypeInfo, Functionalities) {
     ASSERT_TRUE(info == info);
     ASSERT_TRUE(info == info);
     ASSERT_FALSE(info != info);
     ASSERT_FALSE(info != info);
 
 
-    ASSERT_EQ(info.seq(), entt::type_seq<int>::value());
-    ASSERT_EQ(info.hash(), entt::type_hash<int>::value());
+    ASSERT_EQ(info.hash_code(), entt::type_hash<int>::value());
     ASSERT_EQ(info.name(), entt::type_name<int>::value());
     ASSERT_EQ(info.name(), entt::type_name<int>::value());
 
 
     ASSERT_TRUE(info);
     ASSERT_TRUE(info);
@@ -73,15 +72,15 @@ TEST(TypeInfo, Functionalities) {
     empty = info;
     empty = info;
 
 
     ASSERT_TRUE(empty);
     ASSERT_TRUE(empty);
-    ASSERT_EQ(empty.hash(), info.hash());
+    ASSERT_EQ(empty.hash_code(), info.hash_code());
 
 
     empty = {};
     empty = {};
 
 
     ASSERT_FALSE(empty);
     ASSERT_FALSE(empty);
-    ASSERT_NE(empty.hash(), info.hash());
+    ASSERT_NE(empty.hash_code(), info.hash_code());
 
 
     empty = std::move(info);
     empty = std::move(info);
 
 
     ASSERT_TRUE(empty);
     ASSERT_TRUE(empty);
-    ASSERT_EQ(empty.hash(), info.hash());
+    ASSERT_EQ(empty.hash_code(), info.hash_code());
 }
 }

+ 10 - 10
test/entt/entity/registry.cpp

@@ -79,7 +79,7 @@ TEST(Registry, Context) {
     auto count = 0;
     auto count = 0;
 
 
     registry.ctx([&count](auto info) {
     registry.ctx([&count](auto info) {
-        ASSERT_EQ(info.hash(), entt::type_hash<char>::value());
+        ASSERT_EQ(info.hash_code(), entt::type_hash<char>::value());
         ++count;
         ++count;
     });
     });
 
 
@@ -1881,9 +1881,9 @@ TEST(Registry, Visit) {
     bool hasType[3]{};
     bool hasType[3]{};
 
 
     registry.visit([&hasType](auto info) {
     registry.visit([&hasType](auto info) {
-        hasType[0] = hasType[0] || (info.hash() == entt::type_hash<int>::value());
-        hasType[1] = hasType[1] || (info.hash() == entt::type_hash<double>::value());
-        hasType[2] = hasType[2] || (info.hash() == entt::type_hash<char>::value());
+        hasType[0] = hasType[0] || (info.hash_code() == entt::type_hash<int>::value());
+        hasType[1] = hasType[1] || (info.hash_code() == entt::type_hash<double>::value());
+        hasType[2] = hasType[2] || (info.hash_code() == entt::type_hash<char>::value());
     });
     });
 
 
     ASSERT_TRUE(hasType[0] && hasType[1] && hasType[2]);
     ASSERT_TRUE(hasType[0] && hasType[1] && hasType[2]);
@@ -1891,9 +1891,9 @@ TEST(Registry, Visit) {
     hasType[0] = hasType[1] = hasType[2] = false;
     hasType[0] = hasType[1] = hasType[2] = false;
 
 
     registry.visit(entity, [&hasType](auto info) {
     registry.visit(entity, [&hasType](auto info) {
-        hasType[0] = hasType[0] || (info.hash() == entt::type_hash<int>::value());
-        hasType[1] = hasType[1] || (info.hash() == entt::type_hash<double>::value());
-        hasType[2] = hasType[2] || (info.hash() == entt::type_hash<char>::value());
+        hasType[0] = hasType[0] || (info.hash_code() == entt::type_hash<int>::value());
+        hasType[1] = hasType[1] || (info.hash_code() == entt::type_hash<double>::value());
+        hasType[2] = hasType[2] || (info.hash_code() == entt::type_hash<char>::value());
     });
     });
 
 
     ASSERT_TRUE(hasType[0] && !hasType[1] && hasType[2]);
     ASSERT_TRUE(hasType[0] && !hasType[1] && hasType[2]);
@@ -1901,9 +1901,9 @@ TEST(Registry, Visit) {
     hasType[0] = hasType[2] = false;
     hasType[0] = hasType[2] = false;
 
 
     registry.visit(other, [&hasType](auto info) {
     registry.visit(other, [&hasType](auto info) {
-        hasType[0] = hasType[0] || (info.hash() == entt::type_hash<int>::value());
-        hasType[1] = hasType[1] || (info.hash() == entt::type_hash<double>::value());
-        hasType[2] = hasType[2] || (info.hash() == entt::type_hash<char>::value());
+        hasType[0] = hasType[0] || (info.hash_code() == entt::type_hash<int>::value());
+        hasType[1] = hasType[1] || (info.hash_code() == entt::type_hash<double>::value());
+        hasType[2] = hasType[2] || (info.hash_code() == entt::type_hash<char>::value());
     });
     });
 
 
     ASSERT_TRUE(!hasType[0] && hasType[1] && !hasType[2]);
     ASSERT_TRUE(!hasType[0] && hasType[1] && !hasType[2]);