review ident
This commit is contained in:
16
README.md
16
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
|
||||
|
||||
@@ -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)>{});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user