core: reintroduce entt::identity (it's not available everywhere yet, I need to find a solution to inject it when needed)

This commit is contained in:
skypjack
2025-12-01 17:08:22 +01:00
parent cd28e6269b
commit ce2c8b3b91
12 changed files with 78 additions and 49 deletions

View File

@@ -915,6 +915,10 @@ It is not possible to escape the temptation to add utilities of some kind to a
library. In fact, `EnTT` also provides a handful of tools to simplify the
life of developers:
* `entt::identity`: the identity function object that will be available with
C++20. It returns its argument unchanged and nothing more. It is useful as a
sort of _do nothing_ function in template programming.
* `entt::overload`: a tool to disambiguate different overloads from their
function type. It works with both free and member functions.<br/>
Consider the following definition:

View File

@@ -94,7 +94,7 @@ struct radix_sort {
* @param last An iterator past the last element of the range to sort.
* @param getter A valid _getter_ function object.
*/
template<typename It, typename Getter = std::identity>
template<typename It, typename Getter = identity>
void operator()(It first, It last, Getter getter = Getter{}) const {
if(first < last) {
constexpr auto passes = N / Bit;

View File

@@ -6,6 +6,23 @@
namespace entt {
/*! @brief Identity function object (waiting for C++20). */
struct identity {
/*! @brief Indicates that this is a transparent function object. */
using is_transparent = void;
/**
* @brief Returns its argument unchanged.
* @tparam Type Type of the argument.
* @param value The actual argument.
* @return The submitted value as-is.
*/
template<typename Type>
[[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept {
return std::forward<Type>(value);
}
};
/**
* @brief Constant utility to disambiguate overloaded members of a class.
* @tparam Type Type of the desired overload.

View File

@@ -223,7 +223,7 @@ public:
}
private:
dense_map<id_type, basic_any<0u>, std::identity, std::equal_to<>, allocator_type> ctx;
dense_map<id_type, basic_any<0u>, identity, std::equal_to<>, allocator_type> ctx;
};
} // namespace internal
@@ -240,8 +240,8 @@ class basic_registry {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
// std::shared_ptr because of its type erased allocator which is useful here
using pool_container_type = dense_map<id_type, std::shared_ptr<base_type>, std::identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<base_type>>>>;
using group_container_type = dense_map<id_type, std::shared_ptr<internal::group_descriptor>, std::identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<internal::group_descriptor>>>>;
using pool_container_type = dense_map<id_type, std::shared_ptr<base_type>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<base_type>>>>;
using group_container_type = dense_map<id_type, std::shared_ptr<internal::group_descriptor>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<internal::group_descriptor>>>>;
using traits_type = entt_traits<Entity>;
template<typename Type>

View File

@@ -29,9 +29,9 @@ template<typename Allocator>
class basic_flow {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, id_type>, "Invalid value type");
using task_container_type = dense_set<id_type, std::identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<id_type>>;
using task_container_type = dense_set<id_type, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<id_type>>;
using ro_rw_container_type = std::vector<std::pair<std::size_t, bool>, typename alloc_traits::template rebind_alloc<std::pair<std::size_t, bool>>>;
using deps_container_type = dense_map<id_type, ro_rw_container_type, std::identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, ro_rw_container_type>>>;
using deps_container_type = dense_map<id_type, ro_rw_container_type, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, ro_rw_container_type>>>;
using adjacency_matrix_type = adjacency_matrix<directed_tag, typename alloc_traits::template rebind_alloc<std::size_t>>;
void emplace(const id_type res, const bool is_rw) {

View File

@@ -1,7 +1,6 @@
#ifndef ENTT_META_CTX_HPP
#define ENTT_META_CTX_HPP
#include <functional>
#include <memory>
#include "../container/dense_map.hpp"
#include "../core/fwd.hpp"
@@ -16,7 +15,7 @@ namespace internal {
struct meta_type_node;
struct meta_context {
dense_map<id_type, std::unique_ptr<meta_type_node>, std::identity> value;
dense_map<id_type, std::unique_ptr<meta_type_node>, identity> value;
[[nodiscard]] inline static meta_context &from(meta_ctx &);
[[nodiscard]] inline static const meta_context &from(const meta_ctx &);

View File

@@ -154,7 +154,7 @@ class resource_cache {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
using container_allocator = typename alloc_traits::template rebind_alloc<std::pair<const id_type, typename Loader::result_type>>;
using container_type = dense_map<id_type, typename Loader::result_type, std::identity, std::equal_to<>, container_allocator>;
using container_type = dense_map<id_type, typename Loader::result_type, identity, std::equal_to<>, container_allocator>;
public:
/*! @brief Allocator type. */

View File

@@ -115,7 +115,7 @@ class basic_dispatcher {
using alloc_traits = std::allocator_traits<Allocator>;
using container_allocator = typename alloc_traits::template rebind_alloc<std::pair<const key_type, mapped_type>>;
using container_type = dense_map<key_type, mapped_type, std::identity, std::equal_to<>, container_allocator>;
using container_type = dense_map<key_type, mapped_type, identity, std::equal_to<>, container_allocator>;
template<typename Type>
[[nodiscard]] handler_type<Type> &assure(const id_type id) {

View File

@@ -39,7 +39,7 @@ class emitter {
using alloc_traits = std::allocator_traits<Allocator>;
using container_allocator = typename alloc_traits::template rebind_alloc<std::pair<const key_type, mapped_type>>;
using container_type = dense_map<key_type, mapped_type, std::identity, std::equal_to<>, container_allocator>;
using container_type = dense_map<key_type, mapped_type, identity, std::equal_to<>, container_allocator>;
public:
/*! @brief Allocator type. */

View File

@@ -21,7 +21,7 @@
#include "../../common/transparent_equal_to.h"
TEST(DenseMap, Functionalities) {
entt::dense_map<int, int, std::identity, test::transparent_equal_to> map;
entt::dense_map<int, int, entt::identity, test::transparent_equal_to> map;
const auto &cmap = map;
ASSERT_NO_THROW([[maybe_unused]] auto alloc = map.get_allocator());
@@ -115,12 +115,12 @@ TEST(DenseMap, Constructors) {
}
TEST(DenseMap, Copy) {
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
const auto max_load_factor = map.max_load_factor() - .05f;
map.max_load_factor(max_load_factor);
map.emplace(3u, 1u);
entt::dense_map<std::size_t, std::size_t, std::identity> other{map};
entt::dense_map<std::size_t, std::size_t, entt::identity> other{map};
ASSERT_TRUE(map.contains(3u));
ASSERT_TRUE(other.contains(3u));
@@ -148,12 +148,12 @@ TEST(DenseMap, Copy) {
}
TEST(DenseMap, Move) {
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
const auto max_load_factor = map.max_load_factor() - .05f;
map.max_load_factor(max_load_factor);
map.emplace(3u, 1u);
entt::dense_map<std::size_t, std::size_t, std::identity> other{std::move(map)};
entt::dense_map<std::size_t, std::size_t, entt::identity> other{std::move(map)};
test::is_initialized(map);
@@ -396,7 +396,7 @@ TEST(DenseMap, Insert) {
TEST(DenseMap, InsertRehash) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
ASSERT_EQ(map.size(), 0u);
ASSERT_EQ(map.bucket_count(), minimum_bucket_count);
@@ -430,7 +430,7 @@ TEST(DenseMap, InsertRehash) {
TEST(DenseMap, InsertSameBucket) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
ASSERT_EQ(map.cbegin(next), map.cend(next));
@@ -599,7 +599,7 @@ TEST(DenseMap, Emplace) {
TEST(DenseMap, EmplaceRehash) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
ASSERT_EQ(map.size(), 0u);
ASSERT_EQ(map.bucket_count(), minimum_bucket_count);
@@ -634,7 +634,7 @@ TEST(DenseMap, EmplaceRehash) {
TEST(DenseMap, EmplaceSameBucket) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
ASSERT_EQ(map.cbegin(next), map.cend(next));
@@ -682,7 +682,7 @@ TEST(DenseMap, TryEmplace) {
TEST(DenseMap, TryEmplaceRehash) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
ASSERT_EQ(map.size(), 0u);
ASSERT_EQ(map.bucket_count(), minimum_bucket_count);
@@ -716,7 +716,7 @@ TEST(DenseMap, TryEmplaceRehash) {
TEST(DenseMap, TryEmplaceSameBucket) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
ASSERT_EQ(map.cbegin(next), map.cend(next));
@@ -750,7 +750,7 @@ TEST(DenseMap, TryEmplaceMovableType) {
TEST(DenseMap, Erase) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
for(std::size_t next{}, last = minimum_bucket_count + 1u; next < last; ++next) {
map.emplace(next, next);
@@ -812,7 +812,7 @@ TEST(DenseMap, EraseWithMovableKeyValue) {
TEST(DenseMap, EraseFromBucket) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
ASSERT_EQ(map.bucket_count(), minimum_bucket_count);
ASSERT_EQ(map.size(), 0u);
@@ -921,7 +921,7 @@ TEST(DenseMap, Swap) {
}
TEST(DenseMap, EqualRange) {
entt::dense_map<int, int, std::identity, test::transparent_equal_to> map;
entt::dense_map<int, int, entt::identity, test::transparent_equal_to> map;
const auto &cmap = map;
map.emplace(4, 1);
@@ -960,7 +960,7 @@ TEST(DenseMap, EqualRange) {
}
TEST(DenseMap, Indexing) {
entt::dense_map<int, int, std::identity, test::transparent_equal_to> map;
entt::dense_map<int, int, entt::identity, test::transparent_equal_to> map;
const auto &cmap = map;
const auto key = 1;
@@ -979,7 +979,7 @@ TEST(DenseMap, Indexing) {
}
ENTT_DEBUG_TEST(DenseMapDeathTest, Indexing) {
entt::dense_map<int, int, std::identity, test::transparent_equal_to> map;
entt::dense_map<int, int, entt::identity, test::transparent_equal_to> map;
const auto &cmap = map;
ASSERT_DEATH([[maybe_unused]] auto value = map.at(3), "");
@@ -990,14 +990,14 @@ ENTT_DEBUG_TEST(DenseMapDeathTest, Indexing) {
}
TEST(DenseMap, LocalIterator) {
using iterator = typename entt::dense_map<std::size_t, std::size_t, std::identity>::local_iterator;
using iterator = typename entt::dense_map<std::size_t, std::size_t, entt::identity>::local_iterator;
testing::StaticAssertTypeEq<iterator::value_type, std::pair<const std::size_t &, std::size_t &>>();
testing::StaticAssertTypeEq<iterator::pointer, entt::input_iterator_pointer<std::pair<const std::size_t &, std::size_t &>>>();
testing::StaticAssertTypeEq<iterator::reference, std::pair<const std::size_t &, std::size_t &>>();
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
map.emplace(3u, 2u);
map.emplace(3u + minimum_bucket_count, 1u);
@@ -1018,14 +1018,14 @@ TEST(DenseMap, LocalIterator) {
}
TEST(DenseMap, ConstLocalIterator) {
using iterator = typename entt::dense_map<std::size_t, std::size_t, std::identity>::const_local_iterator;
using iterator = typename entt::dense_map<std::size_t, std::size_t, entt::identity>::const_local_iterator;
testing::StaticAssertTypeEq<iterator::value_type, std::pair<const std::size_t &, const std::size_t &>>();
testing::StaticAssertTypeEq<iterator::pointer, entt::input_iterator_pointer<std::pair<const std::size_t &, const std::size_t &>>>();
testing::StaticAssertTypeEq<iterator::reference, std::pair<const std::size_t &, const std::size_t &>>();
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
map.emplace(3u, 2u);
map.emplace(3u + minimum_bucket_count, 1u);
@@ -1066,7 +1066,7 @@ TEST(DenseMap, LocalIteratorConversion) {
TEST(DenseMap, Rehash) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::identity> map;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
map[32u] = 2u;
ASSERT_EQ(map.bucket_count(), minimum_bucket_count);

View File

@@ -18,7 +18,7 @@
#include "../../common/transparent_equal_to.h"
TEST(DenseSet, Functionalities) {
entt::dense_set<int, std::identity, test::transparent_equal_to> set;
entt::dense_set<int, entt::identity, test::transparent_equal_to> set;
const auto &cset = set;
ASSERT_NO_THROW([[maybe_unused]] auto alloc = set.get_allocator());
@@ -112,12 +112,12 @@ TEST(DenseSet, Constructors) {
}
TEST(DenseSet, Copy) {
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
const auto max_load_factor = set.max_load_factor() - .05f;
set.max_load_factor(max_load_factor);
set.emplace(3u);
entt::dense_set<std::size_t, std::identity> other{set};
entt::dense_set<std::size_t, entt::identity> other{set};
ASSERT_TRUE(set.contains(3u));
ASSERT_TRUE(other.contains(3u));
@@ -141,12 +141,12 @@ TEST(DenseSet, Copy) {
}
TEST(DenseSet, Move) {
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
const auto max_load_factor = set.max_load_factor() - .05f;
set.max_load_factor(max_load_factor);
set.emplace(3u);
entt::dense_set<std::size_t, std::identity> other{std::move(set)};
entt::dense_set<std::size_t, entt::identity> other{std::move(set)};
test::is_initialized(set);
@@ -462,7 +462,7 @@ TEST(DenseSet, Insert) {
TEST(DenseSet, InsertRehash) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
ASSERT_EQ(set.size(), 0u);
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
@@ -493,7 +493,7 @@ TEST(DenseSet, InsertRehash) {
TEST(DenseSet, InsertSameBucket) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
ASSERT_EQ(set.cbegin(next), set.cend(next));
@@ -556,7 +556,7 @@ TEST(DenseSet, Emplace) {
TEST(DenseSet, EmplaceRehash) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
ASSERT_EQ(set.size(), 0u);
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
@@ -588,7 +588,7 @@ TEST(DenseSet, EmplaceRehash) {
TEST(DenseSet, EmplaceSameBucket) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
ASSERT_EQ(set.cbegin(next), set.cend(next));
@@ -608,7 +608,7 @@ TEST(DenseSet, EmplaceSameBucket) {
TEST(DenseSet, Erase) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
for(std::size_t next{}, last = minimum_bucket_count + 1u; next < last; ++next) {
set.emplace(next);
@@ -669,7 +669,7 @@ TEST(DenseSet, EraseWithMovableKeyValue) {
TEST(DenseSet, EraseFromBucket) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
ASSERT_EQ(set.size(), 0u);
@@ -778,7 +778,7 @@ TEST(DenseSet, Swap) {
}
TEST(DenseSet, EqualRange) {
entt::dense_set<int, std::identity, test::transparent_equal_to> set;
entt::dense_set<int, entt::identity, test::transparent_equal_to> set;
const auto &cset = set;
set.emplace(1);
@@ -813,14 +813,14 @@ TEST(DenseSet, EqualRange) {
}
TEST(DenseSet, LocalIterator) {
using iterator = typename entt::dense_set<std::size_t, std::identity>::local_iterator;
using iterator = typename entt::dense_set<std::size_t, entt::identity>::local_iterator;
testing::StaticAssertTypeEq<iterator::value_type, std::size_t>();
testing::StaticAssertTypeEq<iterator::pointer, const std::size_t *>();
testing::StaticAssertTypeEq<iterator::reference, const std::size_t &>();
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
set.emplace(3u);
set.emplace(3u + minimum_bucket_count);
@@ -841,14 +841,14 @@ TEST(DenseSet, LocalIterator) {
}
TEST(DenseSet, ConstLocalIterator) {
using iterator = typename entt::dense_set<std::size_t, std::identity>::const_local_iterator;
using iterator = typename entt::dense_set<std::size_t, entt::identity>::const_local_iterator;
testing::StaticAssertTypeEq<iterator::value_type, std::size_t>();
testing::StaticAssertTypeEq<iterator::pointer, const std::size_t *>();
testing::StaticAssertTypeEq<iterator::reference, const std::size_t &>();
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
set.emplace(3u);
set.emplace(3u + minimum_bucket_count);
@@ -889,7 +889,7 @@ TEST(DenseSet, LocalIteratorConversion) {
TEST(DenseSet, Rehash) {
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::identity> set;
entt::dense_set<std::size_t, entt::identity> set;
set.emplace(32u);
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);

View File

@@ -11,6 +11,15 @@ struct functions {
void bar() {}
};
TEST(Identity, Functionalities) {
const entt::identity identity;
int value = 2;
ASSERT_TRUE(entt::is_transparent_v<entt::identity>);
ASSERT_EQ(identity(value), value);
ASSERT_EQ(&identity(value), &value);
}
TEST(Overload, Functionalities) {
ASSERT_EQ(entt::overload<void(int)>(&functions::foo), static_cast<void (*)(int)>(&functions::foo));
ASSERT_EQ(entt::overload<void()>(&functions::foo), static_cast<void (*)()>(&functions::foo));