Browse Source

review ident

Michele Caini 7 years ago
parent
commit
d810e0ba7d
3 changed files with 55 additions and 64 deletions
  1. 8 8
      README.md
  2. 36 45
      src/entt/core/ident.hpp
  3. 11 11
      test/entt/core/ident.cpp

+ 8 - 8
README.md

@@ -1591,21 +1591,21 @@ There are plenty of different solutions out there and I could have used one of
 them. However, I decided to spend my time to define a compact and versatile tool
 that fully embraces what the modern C++ has to offer.
 
-The _result of my efforts_ is the `ident` `constexpr` variable:
+The _result of my efforts_ is the `Identifier` class template:
 
 ```cpp
 #include <ident.hpp>
 
 // defines the identifiers for the given types
-constexpr auto identifiers = entt::ident<AType, AnotherType>;
+using ID = entt::Identifier<AType, AnotherType>;
 
 // ...
 
 switch(aTypeIdentifier) {
-case identifers.get<AType>():
+case ID::get<AType>():
     // ...
     break;
-case identifers.get<AnotherType>():
+case ID::get<AnotherType>():
     // ...
     break;
 default:
@@ -1613,9 +1613,9 @@ default:
 }
 ```
 
-This is all what the variable has to offer: a `get` member function that returns
-a numerical identifier for the given type. It can be used in any context where
-constant expressions are required.
+This is all what the class template has to offer: a static `get` member function
+that returns a numerical identifier for the given type. It can be used in any
+context where constant expressions are required.
 
 As long as the list remains unchanged, identifiers are also guaranteed to be the
 same for every run. In case they have been used in a production environment and
@@ -1625,7 +1625,7 @@ identifiers unchanged:
 ```cpp
 template<typename> struct IgnoreType {};
 
-constexpr auto identifiers = entt::ident<
+using ID = entt::Identifier<
     ATypeStillValid,
     IgnoreType<ATypeNoLongerValid>,
     AnotherTypeStillValid

+ 36 - 45
src/entt/core/ident.hpp

@@ -5,6 +5,8 @@
 #include <type_traits>
 #include <cstddef>
 #include <utility>
+#include <tuple>
+#include <algorithm>
 #include "../config/config.h"
 
 
@@ -20,38 +22,14 @@ namespace internal {
  */
 
 
-template<typename... Types>
-struct Identifier final: Identifier<Types>... {
-    using identifier_type = std::size_t;
-
-    template<std::size_t... Indexes>
-    constexpr Identifier(std::index_sequence<Indexes...>) ENTT_NOEXCEPT
-        : Identifier<Types>{std::index_sequence<Indexes>{}}...
-    {}
-
-    template<typename Type>
-    constexpr std::size_t get() const ENTT_NOEXCEPT {
-        return Identifier<std::decay_t<Type>>::get();
-    }
-};
+template<typename...>
+struct IsPartOf;
 
+template<typename Type, typename Current, typename... Other>
+struct IsPartOf<Type, Current, Other...>: std::conditional_t<std::is_same<Type, Current>::value, std::true_type, IsPartOf<Type, Other...>> {};
 
 template<typename Type>
-struct Identifier<Type> {
-    using identifier_type = std::size_t;
-
-    template<std::size_t Index>
-    constexpr Identifier(std::index_sequence<Index>) ENTT_NOEXCEPT
-        : index{Index}
-    {}
-
-    constexpr std::size_t get() const ENTT_NOEXCEPT {
-        return index;
-    }
-
-private:
-    const std::size_t index;
-};
+struct IsPartOf<Type>: std::false_type {};
 
 
 /**
@@ -64,23 +42,23 @@ private:
 
 
 /**
- * @brief Types identifers.
+ * @brief Types identifiers.
  *
  * Variable template used to generate identifiers at compile-time for the given
- * types. Use the `constexpr` `get` member function to know what's the
- * identifier associated to the specific type.
+ * types. Use the `get` member function to know what's the identifier associated
+ * to the specific type.
  *
  * @note
  * Identifiers are constant expression and can be used in any context where such
  * an expression is required. As an example:
  * @code{.cpp}
- * constexpr auto identifiers = entt::ident<AType, AnotherType>;
+ * using ID = entt::Identifier<AType, AnotherType>;
  *
  * switch(aTypeIdentifier) {
- * case identifers.get<AType>():
+ * case ID::get<AType>():
  *     // ...
  *     break;
- * case identifers.get<AnotherType>():
+ * case ID::get<AnotherType>():
  *     // ...
  *     break;
  * default:
@@ -88,19 +66,32 @@ private:
  * }
  * @endcode
  *
- * @note
- * In case of single type list, `get` isn't a member function template:
- * @code{.cpp}
- * func(std::integral_constant<
- *     entt::ident<AType>::identifier_type,
- *     entt::ident<AType>::get()
- * >{});
- * @endcode
- *
  * @tparam Types List of types for which to generate identifiers.
  */
 template<typename... Types>
-constexpr auto ident = internal::Identifier<std::decay_t<Types>...>{std::make_index_sequence<sizeof...(Types)>{}};
+class Identifier final {
+    using tuple_type = std::tuple<std::decay_t<Types>...>;
+
+    template<typename Type, std::size_t... Indexes>
+    static constexpr std::size_t get(std::index_sequence<Indexes...>) ENTT_NOEXCEPT {
+        static_assert(internal::IsPartOf<Type, Types...>::value, "!");
+        return std::max({ (std::is_same<Type, std::tuple_element_t<Indexes, tuple_type>>::value ? Indexes : std::size_t{})... });
+    }
+
+public:
+    /*! @brief Unsigned integer type. */
+    using identifier_type = std::size_t;
+
+    /**
+     * @brief Returns the identifier associated with a given type.
+     * @tparam Type of which to return the identifier.
+     * @return The identifier associated with the given type.
+     */
+    template<typename Type>
+    static constexpr identifier_type get() ENTT_NOEXCEPT {
+        return get<std::decay_t<Type>>(std::make_index_sequence<sizeof...(Types)>{});
+    }
+};
 
 
 }

+ 11 - 11
test/entt/core/ident.cpp

@@ -6,28 +6,28 @@ struct AType {};
 struct AnotherType {};
 
 TEST(Identifier, Uniqueness) {
-    constexpr auto ID = entt::ident<AType, AnotherType>;
+    using ID = entt::Identifier<AType, AnotherType>;
     constexpr AType anInstance;
     constexpr AnotherType anotherInstance;
 
-    ASSERT_NE(ID.get<AType>(), ID.get<AnotherType>());
-    ASSERT_EQ(ID.get<AType>(), ID.get<decltype(anInstance)>());
-    ASSERT_NE(ID.get<AType>(), ID.get<decltype(anotherInstance)>());
-    ASSERT_EQ(ID.get<AType>(), ID.get<AType>());
-    ASSERT_EQ(ID.get<AnotherType>(), ID.get<AnotherType>());
+    ASSERT_NE(ID::get<AType>(), ID::get<AnotherType>());
+    ASSERT_EQ(ID::get<AType>(), ID::get<decltype(anInstance)>());
+    ASSERT_NE(ID::get<AType>(), ID::get<decltype(anotherInstance)>());
+    ASSERT_EQ(ID::get<AType>(), ID::get<AType>());
+    ASSERT_EQ(ID::get<AnotherType>(), ID::get<AnotherType>());
 
     // test uses in constant expressions
-    switch(ID.get<AnotherType>()) {
-    case ID.get<AType>():
+    switch(ID::get<AnotherType>()) {
+    case ID::get<AType>():
         FAIL();
         break;
-    case ID.get<AnotherType>():
+    case ID::get<AnotherType>():
         SUCCEED();
     }
 }
 
 TEST(Identifier, SingleType) {
-    constexpr auto ID = entt::ident<AType>;
-    std::integral_constant<decltype(ID)::identifier_type, ID.get()> ic;
+    using ID = entt::Identifier<AType>;
+    std::integral_constant<ID::identifier_type, ID::get<AType>()> ic;
     (void)ic;
 }