Skip to content

Commit 55ebf6d

Browse files
author
Julian LALU
committed
Improve Hashset,Hashmap, Tuple and Pair
1 parent 5162f55 commit 55ebf6d

File tree

9 files changed

+320
-8
lines changed

9 files changed

+320
-8
lines changed

interface/core/containers/hashmap.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,32 @@ namespace hud
124124
static_assert(hud::is_nothrow_copy_constructible_v<value_t, u_value_t>, "value_t(const u_value_t&) copy constructor is throwable. hashmap_storage is not designed to allow throwable copy constructible components");
125125
}
126126

127+
/**
128+
* Constructor that initializes the hashmap_storage with a key and a default value.
129+
* @tparam u_key_t Type of the key.
130+
* @param key The key to initialize with.
131+
*/
132+
template<typename u_key_t>
133+
requires(hud::is_constructible_v<pair_type, const u_key_t &, const value_type &>)
134+
constexpr explicit hashmap_storage(const u_key_t &key) noexcept
135+
: element_(key, value_type {})
136+
{
137+
static_assert(hud::is_nothrow_constructible_v<pair_type, const u_key_t &, const value_type &>);
138+
}
139+
140+
/**
141+
* Constructor that initializes the hashmap_storage with a key and a default value.
142+
* @tparam u_key_t Type of the key.
143+
* @param key The key to initialize with.
144+
*/
145+
template<typename u_key_t>
146+
requires(hud::is_constructible_v<pair_type, u_key_t, value_type>)
147+
constexpr explicit hashmap_storage(u_key_t &&key) noexcept
148+
: element_(hud::forward<u_key_t>(key), value_type {})
149+
{
150+
static_assert(hud::is_nothrow_constructible_v<pair_type, u_key_t, value_type>);
151+
}
152+
127153
/**
128154
* Constructor that initializes the hashmap_storage with a key and a value.
129155
* @tparam u_key_t Type of the key.
@@ -380,6 +406,13 @@ namespace hud
380406
{
381407
return super::add(hud::tag_piecewise_construct, hud::forward<key_tuple_t>(key_tuple), hud::forward<value_tuple_t>(value_tuple));
382408
}
409+
410+
template<typename KeyArgs>
411+
constexpr value_type &operator[](KeyArgs &&args) noexcept
412+
{
413+
iterator it = super::add(hud::forward<KeyArgs>(args));
414+
return it->value();
415+
}
383416
};
384417

385418
/**

interface/core/containers/pair.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,40 @@ namespace hud
515515
}
516516
}
517517

518+
template<typename FirstType, typename SecondType>
519+
struct equal<hud::pair<FirstType, SecondType>>
520+
{
521+
template<typename FirstTypeU, typename SecondTypeU>
522+
[[nodiscard]] constexpr bool operator()(const hud::pair<FirstType, SecondType> &lhs, const hud::pair<FirstTypeU, SecondTypeU> &rhs) const noexcept
523+
{
524+
return lhs == rhs;
525+
}
526+
};
527+
528+
template<typename FirstType, typename SecondType>
529+
struct hash_32<hud::pair<FirstType, SecondType>>
530+
{
531+
[[nodiscard]] constexpr u32 operator()(const hud::pair<FirstType, SecondType> &t) const noexcept
532+
{
533+
hasher_32 hasher;
534+
hasher.hash(t.first);
535+
hasher.hash(t.second);
536+
return hasher.result();
537+
}
538+
};
539+
540+
template<typename FirstType, typename SecondType>
541+
struct hash_64<hud::pair<FirstType, SecondType>>
542+
{
543+
[[nodiscard]] constexpr u64 operator()(const hud::pair<FirstType, SecondType> &t) const noexcept
544+
{
545+
hasher_64 hasher;
546+
hasher.hash(t.first);
547+
hasher.hash(t.second);
548+
return hasher.result();
549+
}
550+
};
551+
518552
} // namespace hud
519553

520554
#endif // HD_INC_CORE_PAIR_H

interface/core/containers/tuple.h

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,39 @@ namespace hud
582582
return tuples_cat_impl_type::concatenate(element_index_seq(), mask_index_seq(), hud::forward<tuple_t>(tuple));
583583
}
584584
};
585+
586+
/**
587+
* Hashes all elements of a tuple and combines them into a single hash value.
588+
* This is a recursive template that processes one element per call.
589+
* @tparam count Number of elements remaining to hash.
590+
*/
591+
template<usize count>
592+
struct tuple_hash
593+
{
594+
/**
595+
* Hashes the elements of the given tuple recursively, starting from the first unprocessed element.
596+
* @tparam Hasher Type of the hasher used.
597+
* @tparam types_t Types of the tuple elements.
598+
* @param hasher The hasher instance used to compute the hash.
599+
* @param t The tuple whose elements are to be hashed.
600+
* @return The final combined hash value.
601+
*/
602+
template<typename Hasher, typename... types_t>
603+
[[nodiscard]] constexpr decltype(hud::declval<Hasher>().result()) operator()(Hasher &hasher, [[maybe_unused]] const tuple<types_t...> &t) noexcept
604+
{
605+
if constexpr (count > 0u)
606+
{
607+
constexpr const usize index_to_hash = tuple_size_v<tuple<types_t...>> - count;
608+
hasher.hash(hud::get<index_to_hash>(t));
609+
return tuple_hash<count - 1u>()(hasher, t);
610+
}
611+
else
612+
{
613+
return hasher.result();
614+
}
615+
}
616+
};
617+
585618
} // namespace details
586619

587620
/**
@@ -978,7 +1011,7 @@ namespace hud
9781011
template<typename... types_t, typename... u_types_t>
9791012
static constexpr void swap(tuple<types_t...> &first, tuple<u_types_t...> &second) noexcept
9801013
{
981-
details::tuple_swap<sizeof...(types_t)>()(first, second);
1014+
details::tuple_swap<sizeof...(types_t)> {}(first, second);
9821015
}
9831016

9841017
/**
@@ -992,7 +1025,7 @@ namespace hud
9921025
template<typename... types_t, typename... u_types_t>
9931026
[[nodiscard]] constexpr bool operator==(const tuple<types_t...> &left, const tuple<u_types_t...> &right) noexcept
9941027
{
995-
return details::tuple_equals<sizeof...(types_t)>()(left, right);
1028+
return details::tuple_equals<sizeof...(types_t)> {}(left, right);
9961029
}
9971030

9981031
/**
@@ -1019,7 +1052,7 @@ namespace hud
10191052
template<typename... types_t, typename... u_types_t>
10201053
[[nodiscard]] constexpr bool operator<(const tuple<types_t...> &left, const tuple<u_types_t...> &right) noexcept
10211054
{
1022-
return details::tuple_less<sizeof...(types_t)>()(left, right);
1055+
return details::tuple_less<sizeof...(types_t)> {}(left, right);
10231056
}
10241057

10251058
/**
@@ -1096,6 +1129,36 @@ namespace hud
10961129
return tuple_cat_result::concatenate(forward_as_tuple(hud::forward<tuples_t>(args)...));
10971130
}
10981131

1132+
template<typename... types_t>
1133+
struct equal<hud::tuple<types_t...>>
1134+
{
1135+
template<typename... u_types_t>
1136+
[[nodiscard]] constexpr bool operator()(const hud::tuple<types_t...> &lhs, const hud::tuple<u_types_t...> &rhs) const noexcept
1137+
{
1138+
return lhs == rhs;
1139+
}
1140+
};
1141+
1142+
template<typename... types_t>
1143+
struct hash_32<hud::tuple<types_t...>>
1144+
{
1145+
[[nodiscard]] constexpr u32 operator()(const hud::tuple<types_t...> &t) const noexcept
1146+
{
1147+
hasher_32 hasher;
1148+
return details::tuple_hash<sizeof...(types_t)> {}(hasher, t);
1149+
}
1150+
};
1151+
1152+
template<typename... types_t>
1153+
struct hash_64<hud::tuple<types_t...>>
1154+
{
1155+
[[nodiscard]] constexpr u64 operator()(const hud::tuple<types_t...> &t) const noexcept
1156+
{
1157+
hasher_64 hasher;
1158+
return details::tuple_hash<sizeof...(types_t)> {}(hasher, t);
1159+
}
1160+
};
1161+
10991162
} // namespace hud
11001163

11011164
namespace std

interface/core/hash.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ namespace hud
164164
{
165165
return hud::hash_32<ansichar *, usize> {}(value, length);
166166
}
167+
168+
[[nodiscard]] constexpr u32 operator()(const ansichar *value) const
169+
{
170+
return hud::hash_32<ansichar *, usize> {}(value, cstring::length(value));
171+
}
167172
};
168173

169174
/** Retrieves the 32 bits hash of a wchar null-terminated string. */
@@ -361,6 +366,11 @@ namespace hud
361366
{
362367
return hud::hash_64<ansichar *, usize> {}(value, length);
363368
}
369+
370+
[[nodiscard]] constexpr u64 operator()(const ansichar *value) const
371+
{
372+
return hud::hash_64<ansichar *, usize> {}(value, cstring::length(value));
373+
}
364374
};
365375

366376
/** Retrieves the 64 bits hash of a wchar null-terminated string. */
@@ -444,7 +454,7 @@ namespace hud
444454

445455
/** Hash the value and combine the value with the current hasher value. */
446456
template<typename... type_t>
447-
[[nodiscard]] constexpr hasher_32 &hash(type_t &&...values) noexcept
457+
constexpr hasher_32 &hash(type_t &&...values) noexcept
448458
{
449459
return (*this)(hud::forward<type_t>(values)...);
450460
}
@@ -485,7 +495,7 @@ namespace hud
485495

486496
/** Hash the value and combine the value with the current hasher value. */
487497
template<typename... type_t>
488-
[[nodiscard]] constexpr hasher_64 &hash(type_t &&...values) noexcept
498+
constexpr hasher_64 &hash(type_t &&...values) noexcept
489499
{
490500
return (*this)(hud::forward<type_t>(values)...);
491501
}

test/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ set( src
121121
pair/pair_destructor.cpp
122122
pair/pair_misc.cpp
123123
pair/pair_swap.cpp
124+
pair/pair_hash.cpp
124125
shared_pointer/multi_thread/shared_pointer_multi_thread_assignments.cpp
125126
shared_pointer/multi_thread/shared_pointer_multi_thread_comparison.cpp
126127
shared_pointer/multi_thread/shared_pointer_multi_thread_constructors.cpp
@@ -285,6 +286,7 @@ set( src
285286
tuple/tuple_swap.cpp
286287
tuple/tuple_element.cpp
287288
tuple/tuple_size.cpp
289+
tuple/tuple_hash.cpp
288290
u128/u128_assign.cpp
289291
u128/u128_cast.cpp
290292
u128/u128_comparisons.cpp

test/hashmap/hashmap_add.cpp

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5068,7 +5068,7 @@ GTEST_TEST(hashmap, add_by_piecewise_construct_non_bitwise_same_type)
50685068
map.reserve(reserved_size);
50695069

50705070
static_assert(hud::is_hashable_64_v<key_type, decltype(hud::forward_as_tuple(1, ptr))>);
5071-
static_assert(hud::is_comparable_with_equal_v<key_type, decltype(hud::forward_as_tuple(2, ptr + 1))>);
5071+
static_assert(hud::is_comparable_with_equal_v<key_type, decltype(hud::forward_as_tuple(1, ptr))>);
50725072

50735073
const auto it = map.add(hud::tag_piecewise_construct, hud::forward_as_tuple(1, ptr), hud::forward_as_tuple(2, ptr + 1));
50745074

@@ -5146,7 +5146,7 @@ GTEST_TEST(hashmap, add_by_piecewise_construct_non_bitwise_different_type)
51465146
map.reserve(reserved_size);
51475147

51485148
static_assert(hud::is_hashable_64_v<key_type, decltype(hud::forward_as_tuple(i64 {1}, ptr))>);
5149-
static_assert(hud::is_comparable_with_equal_v<key_type, decltype(hud::forward_as_tuple(u64 {2}, ptr + 1))>);
5149+
static_assert(hud::is_comparable_with_equal_v<key_type, decltype(hud::forward_as_tuple(i64 {1}, ptr))>);
51505150

51515151
const auto it = map.add(hud::tag_piecewise_construct, hud::forward_as_tuple(i64 {1}, ptr), hud::forward_as_tuple(u64 {2}, ptr + 1));
51525152

@@ -5208,4 +5208,56 @@ GTEST_TEST(hashmap, add_by_piecewise_construct_non_bitwise_different_type)
52085208
hud_assert_true(std::get<13>(result));
52095209
hud_assert_true(std::get<14>(result));
52105210
}
5211-
}
5211+
}
5212+
5213+
GTEST_TEST(hashmap, add_by_piecewise_construct_tuples)
5214+
{
5215+
using key_type = hud::tuple<i32, u64, hud_test::non_bitwise_type>;
5216+
using value_type = hud::tuple<i32, u64, hud_test::non_bitwise_type>;
5217+
using hashmap_type = hud::hashmap<key_type, value_type, hud::hash_64<key_type>, hud::equal<key_type>, hud_test::allocator_watcher<1>>;
5218+
5219+
const auto test = []()
5220+
{
5221+
constexpr usize reserved_size = 2;
5222+
i32 ptr[2];
5223+
hashmap_type map;
5224+
map.reserve(reserved_size);
5225+
5226+
static_assert(hud::is_hashable_64_v<key_type, decltype(hud::forward_as_tuple(1, 2, hud_test::non_bitwise_type {3, ptr}))>);
5227+
static_assert(hud::is_comparable_with_equal_v<key_type, decltype(hud::forward_as_tuple(1, 2, hud_test::non_bitwise_type {3, ptr}))>);
5228+
5229+
const auto it = map.add(hud::tag_piecewise_construct, hud::forward_as_tuple(1, 2, hud_test::non_bitwise_type {3, ptr}), hud::forward_as_tuple(4, 5, hud_test::non_bitwise_type {6, ptr + 1}));
5230+
5231+
const key_type expected_key {
5232+
1,
5233+
2,
5234+
hud_test::non_bitwise_type {3, ptr}
5235+
};
5236+
const value_type expected_value {
5237+
4,
5238+
5,
5239+
hud_test::non_bitwise_type {6, ptr + 1}
5240+
};
5241+
return std::tuple {
5242+
map.count() == 1, // 0
5243+
it->key() == expected_key, // 1
5244+
it->value() == expected_value, // 2
5245+
};
5246+
};
5247+
5248+
// Non constant
5249+
{
5250+
const auto result = test();
5251+
hud_assert_true(std::get<0>(result));
5252+
hud_assert_true(std::get<1>(result));
5253+
hud_assert_true(std::get<2>(result));
5254+
}
5255+
5256+
// Constant
5257+
{
5258+
constexpr auto result = test();
5259+
hud_assert_true(std::get<0>(result));
5260+
hud_assert_true(std::get<1>(result));
5261+
hud_assert_true(std::get<2>(result));
5262+
}
5263+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
11
#include <core/containers/hashmap.h>
2+
3+
GTEST_TEST(hashmap, indexed_operator_trivial_same_type)
4+
{
5+
const auto test = []()
6+
{
7+
hud::hashmap<usize, usize> map;
8+
map[1] = 2;
9+
hud::hashmap<const char *, const char *> map2;
10+
map2["key"] = "value";
11+
12+
return std::tuple {
13+
map.find(1)->value() = 2,
14+
map2.find("key")->value() = "value",
15+
};
16+
};
17+
}

test/pair/pair_hash.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <core/containers/pair.h>
2+
#include <core/hash.h>
3+
4+
GTEST_TEST(pair, hash_pair)
5+
{
6+
const auto test = []()
7+
{
8+
using PairType = hud::pair<i32, hud_test::non_bitwise_type>;
9+
u32 result_hash32 = hud::hash_32<PairType> {}(PairType {1, 2});
10+
hud::hasher_32 hasher32;
11+
hasher32.hash(i32 {1});
12+
hasher32.hash(hud_test::non_bitwise_type {2});
13+
14+
u64 result_hash64 = hud::hash_64<PairType> {}(PairType {1, 2});
15+
hud::hasher_64 hasher64;
16+
hasher64.hash(i32 {1});
17+
hasher64.hash(hud_test::non_bitwise_type {2});
18+
return std::tuple {
19+
result_hash32 == hasher32.result(),
20+
result_hash64 == hasher64.result()
21+
};
22+
};
23+
24+
// Non constant
25+
{
26+
const auto result = test();
27+
hud_assert_true(std::get<0>(result));
28+
hud_assert_true(std::get<1>(result));
29+
}
30+
31+
// Constant
32+
{
33+
constexpr auto result = test();
34+
hud_assert_true(std::get<0>(result));
35+
hud_assert_true(std::get<1>(result));
36+
}
37+
}

0 commit comments

Comments
 (0)