Skip to content

Commit 9afcf34

Browse files
author
Julian LALU
committed
Add cityhash combine_64
1 parent 2f005d1 commit 9afcf34

File tree

3 files changed

+45
-38
lines changed

3 files changed

+45
-38
lines changed

interface/core/hash.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ namespace hud
115115
}
116116

117117
/** Combine two 32 bits value. */
118-
static u64 combine_32(u64 a, u64 b)
118+
[[nodiscard]] static constexpr u64 combine_32(u64 a, u64 b) noexcept
119119
{
120120
return hud::hash_algorithm::city_hash::combine_32(a, b);
121121
}
@@ -219,7 +219,7 @@ namespace hud
219219
}
220220

221221
/** Combine two 64 bits value. */
222-
static u64 combine_64(u64 a, u64 b)
222+
[[nodiscard]] static constexpr u64 combine_64(u64 a, u64 b) noexcept
223223
{
224224
return hud::hash_algorithm::city_hash::combine_64(a, b);
225225
}

interface/core/hash/city_hash.h

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,15 @@ namespace hud::hash_algorithm
8787
};
8888

8989
/** Performs a load of 32 bits into an aligned memory from a unaligned memory */
90-
static constexpr u32 unaligned_load32(const ansichar *buffer)
90+
[[nodiscard]] static constexpr u32 unaligned_load32(const ansichar *buffer)
9191
{
9292
ansichar result[sizeof(u32)];
9393
hud::memory::copy(result, buffer, sizeof(u32));
9494
return hud::bit_cast<u32>(result);
9595
}
9696

9797
/** Performs a load of 32 bits into an aligned memory from a unaligned memory */
98-
static constexpr u64 unaligned_load64(const ansichar *buffer)
98+
[[nodiscard]] static constexpr u64 unaligned_load64(const ansichar *buffer)
9999
{
100100
ansichar result[sizeof(u64)];
101101
hud::memory::copy(result, buffer, sizeof(u64));
@@ -107,7 +107,7 @@ namespace hud::hash_algorithm
107107
* @param value The value
108108
* @param The shift and mixed value
109109
*/
110-
static constexpr u64 shift_mix(u64 value) noexcept
110+
[[nodiscard]] static constexpr u64 shift_mix(u64 value) noexcept
111111
{
112112
return value ^ (value >> 47);
113113
}
@@ -117,7 +117,7 @@ namespace hud::hash_algorithm
117117
* @param key The key to mix
118118
* @return The resulting value
119119
*/
120-
static constexpr u32 avalanche_mixer(u32 key) noexcept
120+
[[nodiscard]] static constexpr u32 avalanche_mixer(u32 key) noexcept
121121
{
122122
key ^= key >> 16;
123123
key *= 0x85ebca6b;
@@ -133,7 +133,7 @@ namespace hud::hash_algorithm
133133
* @param b The second value to combine
134134
* @return The combined value
135135
*/
136-
constexpr u32 combine_32(u32 a, u32 b) noexcept
136+
[[nodiscard]] constexpr u32 combine_32(u32 a, u32 b) noexcept
137137
{
138138
a *= C1;
139139
a = hud::memory::rotate_left(a, 15);
@@ -148,7 +148,7 @@ namespace hud::hash_algorithm
148148
* @param buffer The possibly unaligned memory
149149
* @return The 32 bits aligned memory
150150
*/
151-
static constexpr u32 fetch_32(const ansichar *buffer) noexcept
151+
[[nodiscard]] static constexpr u32 fetch_32(const ansichar *buffer) noexcept
152152
{
153153
if constexpr (compilation::is_endianness(endianness_e::big))
154154
{
@@ -165,7 +165,7 @@ namespace hud::hash_algorithm
165165
* @param buffer The possibly unaligned memory
166166
* @return The 32 bits aligned memory
167167
*/
168-
static constexpr u64 fetch_64(const ansichar *buffer) noexcept
168+
[[nodiscard]] static constexpr u64 fetch_64(const ansichar *buffer) noexcept
169169
{
170170
if constexpr (compilation::is_endianness(endianness_e::big))
171171
{
@@ -183,7 +183,7 @@ namespace hud::hash_algorithm
183183
* @param length The length of the key
184184
* @return The hash of the key
185185
*/
186-
static constexpr u32 hash_32_len_0_to_4(const ansichar *key, usize length) noexcept
186+
[[nodiscard]] static constexpr u32 hash_32_len_0_to_4(const ansichar *key, usize length) noexcept
187187
{
188188
u32 b = 0;
189189
u32 c = 9;
@@ -204,7 +204,7 @@ namespace hud::hash_algorithm
204204
* @param length The length of the key
205205
* @return The hash of the key
206206
*/
207-
static constexpr u32 hash_32_len_5_to_12(const ansichar *key, usize length) noexcept
207+
[[nodiscard]] static constexpr u32 hash_32_len_5_to_12(const ansichar *key, usize length) noexcept
208208
{
209209
u32 a = static_cast<u32>(length), b = static_cast<u32>(length) * 5, c = 9, d = b;
210210
a += fetch_32(key);
@@ -221,7 +221,7 @@ namespace hud::hash_algorithm
221221
* @param length The length of the key
222222
* @return The hash of the key
223223
*/
224-
static constexpr u32 hash_32_len_13_to_24(const ansichar *key, usize length) noexcept
224+
[[nodiscard]] static constexpr u32 hash_32_len_13_to_24(const ansichar *key, usize length) noexcept
225225
{
226226
u32 a = fetch_32(key - 4 + (length >> 1));
227227
u32 b = fetch_32(key + 4);
@@ -243,7 +243,7 @@ namespace hud::hash_algorithm
243243
* @param multiplier The multiplier
244244
* @return Value1 combined with Value2
245245
*/
246-
static constexpr u64 hash_64_len_16(u64 value1, u64 value2, u64 multiplier) noexcept
246+
[[nodiscard]] static constexpr u64 hash_64_len_16(u64 value1, u64 value2, u64 multiplier) noexcept
247247
{
248248
// Murmur-inspired hashing.
249249
u64 a = (value1 ^ value2) * multiplier;
@@ -260,7 +260,7 @@ namespace hud::hash_algorithm
260260
* @param length The length of the key
261261
* @return The hash of the key
262262
*/
263-
static constexpr u64 hash_64_len_0_to_16(const ansichar *key, usize length) noexcept
263+
[[nodiscard]] static constexpr u64 hash_64_len_0_to_16(const ansichar *key, usize length) noexcept
264264
{
265265
if (length >= 8)
266266
{
@@ -295,7 +295,7 @@ namespace hud::hash_algorithm
295295
* @param length The length of the key
296296
* @return The hash of the key
297297
*/
298-
static constexpr u64 hash_64_len_17_to_32(const ansichar *key, usize length) noexcept
298+
[[nodiscard]] static constexpr u64 hash_64_len_17_to_32(const ansichar *key, usize length) noexcept
299299
{
300300
u64 mul = K2 + length * 2;
301301
u64 a = fetch_64(key) * K1;
@@ -311,7 +311,7 @@ namespace hud::hash_algorithm
311311
* @param length The length of the key
312312
* @return The hash of the key
313313
*/
314-
static constexpr u64 hash_64_len_33_to_64(const ansichar *key, usize len) noexcept
314+
[[nodiscard]] static constexpr u64 hash_64_len_33_to_64(const ansichar *key, usize len) noexcept
315315
{
316316
u64 mul = K2 + len * 2;
317317
u64 a = fetch_64(key) * K2;
@@ -338,7 +338,7 @@ namespace hud::hash_algorithm
338338
* @param hash The 128bits hash
339339
* @return The 64 bits hash
340340
*/
341-
static constexpr u64 hash_128_to_64(const u128 &hash) noexcept
341+
[[nodiscard]] static constexpr u64 hash_128_to_64(const u128 &hash) noexcept
342342
{
343343
// Murmur-inspired hashing.
344344
const u64 kMul = 0x9ddfea08eb382d69ULL;
@@ -356,7 +356,7 @@ namespace hud::hash_algorithm
356356
* @param high The 64 bits high value
357357
* @return The 64 bits hash
358358
*/
359-
static constexpr u64 hash_64_len_16(u64 low, u64 high) noexcept
359+
[[nodiscard]] static constexpr u64 hash_64_len_16(u64 low, u64 high) noexcept
360360
{
361361
return hash_128_to_64(u128 {low, high});
362362
}
@@ -372,7 +372,7 @@ namespace hud::hash_algorithm
372372
* @param b 8 bytes to hash
373373
* @return 128 bits hash of 48 bytes
374374
*/
375-
static constexpr u128 weak_hash_len_32_with_seeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) noexcept
375+
[[nodiscard]] static constexpr u128 weak_hash_len_32_with_seeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) noexcept
376376
{
377377
a += w;
378378
b = hud::memory::rotate_right(b + a + z, 21);
@@ -391,31 +391,22 @@ namespace hud::hash_algorithm
391391
* @param b 8 bytes
392392
* @return 128 bits hash of 48 bytes
393393
*/
394-
static constexpr u128 weak_hash_len_32_with_seeds(const ansichar *key, u64 a, u64 b) noexcept
394+
[[nodiscard]] static constexpr u128 weak_hash_len_32_with_seeds(const ansichar *key, u64 a, u64 b) noexcept
395395
{
396396
return weak_hash_len_32_with_seeds(fetch_64(key), fetch_64(key + 8), fetch_64(key + 16), fetch_64(key + 24), a, b);
397397
}
398398

399399
/**
400400
* Combine two 64 bits value
401-
* From abseil https://github.com/abseil/abseil-cpp
402401
* @param a The first value to combine
403402
* @param b The second value to combine
404403
* @return The combined value
405404
*/
406-
constexpr u64 combine_64(u64 a, u64 b) noexcept
405+
[[nodiscard]] static constexpr u64 combine_64(u64 a, u64 b) noexcept
407406
{
408-
// From abseil 64 bit hash mix
409-
constexpr const u64 kMul = sizeof(usize) == 4 ? u64 {0xcc9e2d51} : u64 {0x9ddfea08eb382d69};
410-
using MulResultType = hud::conditional_t<sizeof(uptr) == 4, u64, ::u128>;
411-
// We do the addition in 64-bit space to make sure the 128-bit
412-
// multiplication is fast. If we were to do it as MultType the compiler has
413-
// to assume that the high word is non-zero and needs to perform 2
414-
// multiplications instead of one.
415-
MulResultType m = a + b;
416-
m *= kMul;
417-
return static_cast<u64>(m ^ (m >> (sizeof(m) * 8 / 2)));
407+
return hash_128_to_64(u128 {b, a});
418408
}
409+
419410
} // namespace details
420411

421412
struct city_hash

test/hash/city_hash.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ et porttitor lacus tempor.Nulla non libero porta, faucibus ex eleifend, sodales
1515
Mauris molestie, dolor non porttitor lobortis, erat nunc fringilla nulla, a consequat justo odio ut lorem.Cras maximus tristique erat, sit amet facilisis urna euismod in.\
1616
Maecenas sit amet congue magna.Donec nisl mauris, tempus eu mauris eget, iaculis sodales libero.Nulla hendrerit bibendum magna, at egestas leo semper ac.Donec porttitor ut orci id ornare.Praesent id nunc risus.Fusce consequat tortor at enim cursus, sed mattis lorem gravida.Orci varius. ";
1717

18-
GTEST_TEST(hash, cityhash_hash32)
18+
GTEST_TEST(cityhash, hash32)
1919
{
2020
// hash32 of nullptr
2121
u32 hash_nullptr = hud::hash_algorithm::city_hash::hash_32(nullptr, 0);
@@ -41,7 +41,7 @@ GTEST_TEST(hash, cityhash_hash32)
4141
hud_assert_eq(hash, CityHash32(lipsum, hud::cstring::length(lipsum)));
4242
}
4343

44-
GTEST_TEST(hash, cityhash_hash32_is_usable_in_constexpr)
44+
GTEST_TEST(cityhash, hash32_is_usable_in_constexpr)
4545
{
4646
constexpr u32 hash_nullptr = hud::hash_algorithm::city_hash::hash_32(nullptr, 0);
4747
hud_assert_eq(hash_nullptr, 0XDC56D17A);
@@ -52,7 +52,7 @@ GTEST_TEST(hash, cityhash_hash32_is_usable_in_constexpr)
5252
hud_assert_eq(hash_lipsum, CityHash32(lipsum, hud::cstring::length(lipsum)));
5353
}
5454

55-
GTEST_TEST(hash, cityhash_hash64)
55+
GTEST_TEST(cityhash, hash64)
5656
{
5757
// hash64 of nullptr
5858
hud_assert_eq(hud::hash_algorithm::city_hash::hash_64(nullptr, 0), 0X9AE16A3B2F90404Full);
@@ -66,9 +66,13 @@ GTEST_TEST(hash, cityhash_hash64)
6666
u64 out = hud::hash_algorithm::city_hash::hash_64(key, i);
6767
hud_assert_eq(hud_test::city_hash_64_result[i], out);
6868
}
69+
70+
constexpr const usize len = hud::cstring::length("key");
71+
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);
6973
}
7074

71-
GTEST_TEST(hash, cityhash_hash64_is_usable_in_constexpr)
75+
GTEST_TEST(cityhash, hash64_is_usable_in_constexpr)
7276
{
7377
constexpr u64 hash_nullptr = hud::hash_algorithm::city_hash::hash_64(nullptr, 0);
7478
hud_assert_eq(hash_nullptr, 0x9AE16A3B2F90404Full);
@@ -79,7 +83,7 @@ GTEST_TEST(hash, cityhash_hash64_is_usable_in_constexpr)
7983
hud_assert_eq(hash_lipsum, CityHash64(lipsum, hud::cstring::length(lipsum)));
8084
}
8185

82-
GTEST_TEST(hash, cityhash_hash128)
86+
GTEST_TEST(cityhash, hash128)
8387
{
8488
// hash128 of nullptr
8589
uint128 hash = CityHash128(nullptr, 0);
@@ -96,4 +100,16 @@ GTEST_TEST(hash, cityhash_hash128)
96100
u64 out = hud::hash_algorithm::city_hash::hash_64(key, i);
97101
hud_assert_eq(hud_test::city_hash_64_result[i], out);
98102
}
99-
}
103+
}
104+
105+
GTEST_TEST(cityhash, combine)
106+
{
107+
// This result come from abseil with modification of the hash combine to use the Hash128to64 to combine 2 64 bits hash
108+
constexpr const usize len = hud::cstring::length("key");
109+
u64 hash = hud::hash_algorithm::city_hash::hash_64("key", len);
110+
u64 combined = hud::hash_algorithm::city_hash::combine_64(0, hash);
111+
hud_assert_eq(combined, 0xCEAAB8E77B74C2E7u);
112+
113+
u64 hash_2 = hud::hash_algorithm::city_hash::hash_64((const ansichar *)&len, sizeof(len));
114+
hud_assert_eq(hud::hash_algorithm::city_hash::combine_64(combined, hash_2), 0x746D68F6EB969EB7u);
115+
}

0 commit comments

Comments
 (0)