Skip to content

Commit 95e3ebd

Browse files
author
Julian LALU
committed
Add hasher_32 and hasher_64
1 parent c29bd46 commit 95e3ebd

File tree

15 files changed

+170
-43
lines changed

15 files changed

+170
-43
lines changed

interface/core/containers/hashmap.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ namespace hud
1313
{
1414
template<typename key_t>
1515
struct default_hasher
16+
: hud::hasher_64
1617
{
1718
using key_type = key_t;
1819

19-
[[nodiscard]] u64 operator()(const key_type &key) const noexcept
20-
{
21-
return hud::hash_64(key);
22-
}
20+
// [[nodiscard]] u64 operator()(const key_type &key) const noexcept
21+
// {
22+
// return hud::hash_64(key);
23+
// }
2324
};
2425

2526
template<typename key_t> struct default_equal

interface/core/containers/shared_pointer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,15 +1418,15 @@ namespace hud
14181418
HD_FORCEINLINE u32 hash_32(const shared_pointer<type_t, thread_safety> &ptr) noexcept
14191419
{
14201420
// Simply hash the pointer
1421-
return hash_32(ptr.pointer());
1421+
return hash_32(static_cast<const void *>(ptr.pointer()));
14221422
}
14231423

14241424
/** Specialization of the hash function for shared_pointer */
14251425
template<typename type_t, thread_safety_e thread_safety>
14261426
HD_FORCEINLINE u64 hash_64(const shared_pointer<type_t, thread_safety> &ptr) noexcept
14271427
{
14281428
// Simply hash the pointer
1429-
return hash_64(ptr.pointer());
1429+
return hash_64(static_cast<const void *>(ptr.pointer()));
14301430
}
14311431

14321432
} // namespace hud

interface/core/containers/unique_pointer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,14 +1058,14 @@ namespace hud
10581058
template<typename type_t>
10591059
constexpr u32 hash_32(const unique_pointer<type_t> &ptr) noexcept
10601060
{
1061-
return hud::hash_32(ptr.pointer());
1061+
return hud::hash_32(static_cast<const void *>(ptr.pointer()));
10621062
}
10631063

10641064
/** Specialization of the hash function for unique_pointer */
10651065
template<typename type_t>
10661066
constexpr u64 hash_64(const unique_pointer<type_t> &ptr) noexcept
10671067
{
1068-
return hud::hash_64(ptr.pointer());
1068+
return hud::hash_64(static_cast<const void *>(ptr.pointer()));
10691069
}
10701070

10711071
} // namespace hud

interface/core/hash.h

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "traits/is_integral.h"
77
#include "hash/city_hash.h"
88
#include "templates/bit_cast.h"
9+
#include <core/cstring.h>
910

1011
namespace hud
1112
{
@@ -80,15 +81,43 @@ namespace hud
8081
}
8182

8283
/** Retrieves the 32 bits hash of a ansichar null-terminated string. */
83-
[[nodiscard]] static inline u32 hash_32(const ansichar *value, usize length) noexcept
84+
[[nodiscard]] static constexpr u32 hash_32(const ansichar *value, usize length) noexcept
8485
{
8586
return hud::hash_algorithm::city_hash::hash_32(value, length);
8687
}
8788

89+
/** Retrieves the 32 bits hash of a ansichar null-terminated string. */
90+
[[nodiscard]] static constexpr u32 hash_32(const ansichar *const value) noexcept
91+
{
92+
return hash_32(value, hud::cstring::length(value));
93+
}
94+
8895
/** Retrieves the 32 bits hash of a wchar null-terminated string. */
89-
[[nodiscard]] static inline u32 hash_32(const wchar *value, usize length) noexcept
96+
[[nodiscard]] static constexpr u32 hash_32(const wchar *value, usize length) noexcept
9097
{
91-
return hud::hash_algorithm::city_hash::hash_32(reinterpret_cast<const ansichar *>(value), length * sizeof(wchar));
98+
struct A
99+
{
100+
union
101+
{
102+
const ansichar *a_;
103+
const wchar *w_;
104+
};
105+
106+
constexpr A(const wchar *w)
107+
: w_(w)
108+
{
109+
}
110+
};
111+
112+
A a(value);
113+
a.w_;
114+
return hud::hash_algorithm::city_hash::hash_32(a.a_, length * sizeof(wchar));
115+
}
116+
117+
/** Retrieves the 32 bits hash of a ansichar null-terminated string. */
118+
[[nodiscard]] static constexpr u32 hash_32(const wchar *const value) noexcept
119+
{
120+
return hash_32(value, hud::cstring::length(value));
92121
}
93122

94123
/** Retrieves the 32 bits hash of an enumeration. */
@@ -100,8 +129,7 @@ namespace hud
100129
}
101130

102131
/** Retrieves the 32 bits hash of a pointer of a type type_t. */
103-
template<typename type_t>
104-
[[nodiscard]] static u32 hash_32(type_t *const pointer) noexcept
132+
[[nodiscard]] static inline u32 hash_32(const void *const pointer) noexcept
105133
{
106134
const uptr ptr = reinterpret_cast<uptr>(pointer);
107135
if constexpr (sizeof(uptr) == 4)
@@ -184,17 +212,29 @@ namespace hud
184212
}
185213

186214
/** Retrieves the 64 bits hash of a ansichar null-terminated string. */
187-
[[nodiscard]] static inline u64 hash_64(const ansichar *value, usize length) noexcept
215+
[[nodiscard]] static constexpr u64 hash_64(const ansichar *value, usize length) noexcept
188216
{
189217
return hud::hash_algorithm::city_hash::hash_64(value, length);
190218
}
191219

220+
/** Retrieves the 32 bits hash of a ansichar null-terminated string. */
221+
[[nodiscard]] static constexpr u32 hash_64(const ansichar *const value) noexcept
222+
{
223+
return hash_64(value, hud::cstring::length(value));
224+
}
225+
192226
/** Retrieves the 64 bits hash of a wchar null-terminated string. */
193227
[[nodiscard]] static inline u64 hash_64(const wchar *value, usize length) noexcept
194228
{
195229
return hud::hash_algorithm::city_hash::hash_64(reinterpret_cast<const ansichar *>(value), length * sizeof(wchar));
196230
}
197231

232+
/** Retrieves the 32 bits hash of a ansichar null-terminated string. */
233+
[[nodiscard]] static inline u64 hash_64(const wchar *const value) noexcept
234+
{
235+
return hash_64(value, hud::cstring::length(value));
236+
}
237+
198238
/** Retrieves the 64 bits hash of an enumeration. */
199239
template<typename type_t>
200240
requires(is_enum_v<type_t>)
@@ -204,8 +244,7 @@ namespace hud
204244
}
205245

206246
/** Retrieves the 64 bits hash of a pointer of a type type_t. */
207-
template<typename type_t>
208-
[[nodiscard]] static u64 hash_64(type_t *const pointer) noexcept
247+
[[nodiscard]] static inline u64 hash_64(const void *const pointer) noexcept
209248
{
210249
const uptr ptr = reinterpret_cast<uptr>(pointer);
211250
if constexpr (sizeof(uptr) == 4)
@@ -224,18 +263,30 @@ namespace hud
224263
return hud::hash_algorithm::city_hash::combine_64(a, b);
225264
}
226265

227-
struct Hasher32
266+
struct hasher_32
228267
{
229-
template<typename T>
230-
[[nodiscard]] constexpr u32 operator()(const T &value) noexcept
268+
template<typename... type_t>
269+
[[nodiscard]] constexpr u32 operator()(type_t &&...values) noexcept
231270
{
232-
state_ = hud::combine_32(state_, hud::hash_32(value));
271+
state_ = hud::combine_32(state_, hud::hash_32(hud::forward<type_t>(values)...));
233272
return state_;
234273
}
235274

236275
u32 state_ {0}; // Default is 0, but can be a seed
237276
};
238277

278+
struct hasher_64
279+
{
280+
template<typename... type_t>
281+
[[nodiscard]] constexpr u64 operator()(type_t &&...values) noexcept
282+
{
283+
state_ = hud::combine_64(state_, hud::hash_64(hud::forward<type_t>(values)...));
284+
return state_;
285+
}
286+
287+
u64 state_ {0}; // Default is 0, but can be a seed
288+
};
289+
239290
} // namespace hud
240291

241292
#endif // HD_INC_CORE_HASH_H

interface/core/os_common/cstring.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ namespace hud::os::common
1313

1414
struct cstring
1515
{
16-
static constexpr u32 RSIZE_MAX_STR {4UL << 10}; // 4KB
17-
static constexpr usize RSIZE_MAX {hud::usize_max >> 1}; // Largest acceptable size for bounds-checked functions
16+
static constexpr u32 RSIZE_MAX_STR {4UL << 10}; // 4KB
17+
18+
// static constexpr u64 RSIZE_MAX {hud::usize_max >> 1}; // Largest acceptable size for bounds-checked functions
1819

1920
/**
2021
* Test whether null-terminated string contains only pure ansi characters.
@@ -492,9 +493,24 @@ namespace hud::os::common
492493
* @param string Null-terminated string
493494
* @return Length of the string
494495
*/
495-
static HD_FORCEINLINE usize length(const wchar *string) noexcept
496+
[[nodiscard]] static constexpr usize length(const wchar *string) noexcept
496497
{
497-
return wcslen(string);
498+
if (hud::is_constant_evaluated())
499+
{
500+
// LCOV_EXCL_START
501+
usize string_length = 0;
502+
while (*string != '\0')
503+
{
504+
string_length++;
505+
string++;
506+
}
507+
return string_length;
508+
// LCOV_EXCL_STOP
509+
}
510+
else
511+
{
512+
return wcslen(string);
513+
}
498514
}
499515

500516
/**

test/hash/city_hash.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ GTEST_TEST(cityhash, hash32)
3939
// Test with the lipsum
4040
const u32 hash = hud::hash_algorithm::city_hash::hash_32(lipsum, hud::cstring::length(lipsum));
4141
hud_assert_eq(hash, CityHash32(lipsum, hud::cstring::length(lipsum)));
42+
43+
// Test with "key"
44+
constexpr const usize len = hud::cstring::length("key");
45+
hud_assert_eq(hud::hash_algorithm::city_hash::hash_32("key", len), 0x1096A99Du);
4246
}
4347

4448
GTEST_TEST(cityhash, hash32_is_usable_in_constexpr)
@@ -67,9 +71,13 @@ GTEST_TEST(cityhash, hash64)
6771
hud_assert_eq(hud_test::city_hash_64_result[i], out);
6872
}
6973

74+
// Test with the lipsum
75+
const u64 hash = hud::hash_algorithm::city_hash::hash_64(lipsum, hud::cstring::length(lipsum));
76+
hud_assert_eq(hash, CityHash64(lipsum, hud::cstring::length(lipsum)));
77+
78+
// Test with "key"
7079
constexpr const usize len = hud::cstring::length("key");
7180
hud_assert_eq(hud::hash_algorithm::city_hash::hash_64("key", len), 0x0BB7560E11262CDB);
72-
hud_assert_eq(hud::hash_algorithm::city_hash::hash_64((const ansichar *)&len, sizeof(len)), 0x64C856FF72C54198u);
7381
}
7482

7583
GTEST_TEST(cityhash, hash64_is_usable_in_constexpr)
@@ -79,6 +87,7 @@ GTEST_TEST(cityhash, hash64_is_usable_in_constexpr)
7987
hud_assert_eq(CityHash64(nullptr, 0), hash_nullptr);
8088

8189
constexpr u64 hash_lipsum = hud::hash_algorithm::city_hash::hash_64(lipsum, hud::cstring::length(lipsum));
90+
8291
// Test with the lipsum
8392
hud_assert_eq(hash_lipsum, CityHash64(lipsum, hud::cstring::length(lipsum)));
8493
}
@@ -102,7 +111,19 @@ GTEST_TEST(cityhash, hash128)
102111
}
103112
}
104113

105-
GTEST_TEST(cityhash, combine)
114+
GTEST_TEST(cityhash, combine_32)
115+
{
116+
// This result come from abseil with modification of the hash combine to use the Hash128to64 to combine 2 32 bits hash
117+
constexpr const usize len = hud::cstring::length("key");
118+
u32 hash = hud::hash_algorithm::city_hash::hash_32("key", len);
119+
u32 combined = hud::hash_algorithm::city_hash::combine_32(0, hash);
120+
hud_assert_eq(combined, 0x105695BEu);
121+
122+
u32 hash_2 = hud::hash_algorithm::city_hash::hash_32((const ansichar *)&len, sizeof(len));
123+
hud_assert_eq(hud::hash_algorithm::city_hash::combine_32(combined, hash_2), 0xE638A9DBu);
124+
}
125+
126+
GTEST_TEST(cityhash, combine_64)
106127
{
107128
// This result come from abseil with modification of the hash combine to use the Hash128to64 to combine 2 64 bits hash
108129
constexpr const usize len = hud::cstring::length("key");

test/hash/hash_32.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,13 @@ GTEST_TEST(hash_32, hash_enumeration_are_usable_in_constexpr)
128128
GTEST_TEST(hash_32, hash_can_hash_pointers)
129129
{
130130
const u32 *ptr = nullptr;
131-
hud_assert_eq(hud::hash_32(ptr), reinterpret_cast<uptr>(ptr));
131+
hud_assert_eq(hud::hash_32(static_cast<const void *>(ptr)), reinterpret_cast<uptr>(ptr));
132132
}
133+
134+
GTEST_TEST(hash_32, hasher32)
135+
{
136+
constexpr const usize len = hud::cstring::length("key");
137+
hud::hasher_32 hasher;
138+
hud_assert_eq(hasher("key", len), 0x105695BEu);
139+
hud_assert_eq(hasher((const ansichar *)&len, sizeof(len)), 0xE638A9DBu);
140+
}

test/hash/hash_64.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,31 @@ GTEST_TEST(hash_64, hash_can_hash_c_string)
8282
}
8383
}
8484

85+
GTEST_TEST(hash_64, hash_can_hash_c_string_are_usable_in_constexpr)
86+
{
87+
static constexpr const ansichar txt[] = "abcdefghijklmnopqrstuvwxyz";
88+
constexpr u64 hash_a = hud::hash_64(txt, hud::cstring::length(txt));
89+
hud_assert_eq(hash_a, 0x5EAD741CE7AC31BDu);
90+
91+
// Not Possible, wchar* cannot be cast to ansichar at compile time
92+
//
93+
// static constexpr const wchar *wtxt = L"abcdefghijklmnopqrstuvwxyz";
94+
// if constexpr (sizeof(wchar) == 2)
95+
// {
96+
// constexpr u64 hash_w = hud::hash_64(wtxt, hud::cstring::length(wtxt));
97+
// hud_assert_eq(hash_w, 0xE66EDE359E692EBBu);
98+
// }
99+
// else if constexpr (sizeof(wchar) == 4)
100+
// {
101+
// constexpr u64 hash_w = hud::hash_64(wtxt, hud::cstring::length(wtxt));
102+
// hud_assert_eq(hash_w, 0xF09AD8D8223EE63Bu);
103+
// }
104+
// else
105+
// {
106+
// FAIL();
107+
// }
108+
}
109+
85110
GTEST_TEST(hash_64, hash_can_hash_enumeration)
86111
{
87112
enum class E : u32
@@ -127,5 +152,13 @@ GTEST_TEST(hash_64, hash_enumeration_are_usable_in_constexpr)
127152
GTEST_TEST(hash_64, hash_can_hash_pointers)
128153
{
129154
const u64 *ptr = nullptr;
130-
hud_assert_eq(hud::hash_64(ptr), reinterpret_cast<uptr>(ptr));
155+
hud_assert_eq(hud::hash_64(static_cast<const void *>(ptr)), reinterpret_cast<uptr>(ptr));
131156
}
157+
158+
GTEST_TEST(hash_64, hasher64)
159+
{
160+
constexpr const usize len = hud::cstring::length("key");
161+
hud::hasher_64 hasher;
162+
hud_assert_eq(hasher("key", len), 0xCEAAB8E77B74C2E7u);
163+
hud_assert_eq(hasher((const ansichar *)&len, sizeof(len)), 0x746D68F6EB969EB7u);
164+
}

test/hashmap/hashmap_insert.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,5 @@
44
GTEST_TEST(hashmap, insert)
55
{
66
hud::hashmap<const char *, i64> map;
7-
constexpr const usize len = hud::cstring::length("key");
8-
9-
u64 hash = hud::combine_64(hud::combine_64(0, hud::hash_64("key", len)), hud::hash_64((const char *)&len, sizeof(usize)));
107
auto res = map.insert("key", 1);
118
}

test/shared_pointer/multi_thread/shared_pointer_multi_thread_misc.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ GTEST_TEST(shared_pointer_safe, hash_32)
564564
const auto test = []()
565565
{
566566
hud::shared_pointer<i32, hud::thread_safety_e::safe> ptr(new i32(123));
567-
return hud::hash_32(ptr) == hud::hash_32(ptr.pointer());
567+
return hud::hash_32(ptr) == hud::hash_32(static_cast<const void *>(ptr.pointer()));
568568
};
569569

570570
hud_assert_true(test());
@@ -576,7 +576,7 @@ GTEST_TEST(shared_pointer_safe, hash_64)
576576
const auto test = []()
577577
{
578578
hud::shared_pointer<i32, hud::thread_safety_e::safe> ptr(new i32(123));
579-
return hud::hash_64(ptr) == hud::hash_64(ptr.pointer());
579+
return hud::hash_64(ptr) == hud::hash_64(static_cast<const void *>(ptr.pointer()));
580580
};
581581

582582
hud_assert_true(test());

0 commit comments

Comments
 (0)