Skip to content

Commit 7e92eec

Browse files
committed
hash_consteval.hpp added; hardened named_type_wrapper
1 parent 970285a commit 7e92eec

3 files changed

Lines changed: 64 additions & 5 deletions

File tree

cpp-template-utils.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ HEADERS += \
2222
$$files(string/*.hpp, false) \
2323
$$files(tuple/*.hpp, false) \
2424
$$files(utility/*.h*, false) \
25+
hash/hash_consteval.hpp \
2526
hash/mixers.h \
2627
utility/aligned_wrapper.hpp

hash/hash_consteval.hpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#pragma once
2+
3+
#include <string_view>
4+
#include <stdint.h>
5+
6+
[[nodiscard]] consteval uint32_t murmur3_32_consteval(std::string_view s, uint32_t seed = 0) noexcept
7+
{
8+
constexpr uint32_t c1 = 0xcc9e2d51u;
9+
constexpr uint32_t c2 = 0x1b873593u;
10+
11+
uint32_t h = seed;
12+
const size_t nblocks = s.size() / 4;
13+
14+
for (size_t i = 0; i < nblocks; ++i)
15+
{
16+
// A constant expression can't reinterpret 4 bytes as a uint32_t, so build the block by hand.
17+
// Fixed little-endian keeps results identical across platforms and matches the reference vectors.
18+
const size_t j = i * 4;
19+
uint32_t k = static_cast<uint32_t>(static_cast<uint8_t>(s[j]))
20+
| static_cast<uint32_t>(static_cast<uint8_t>(s[j + 1])) << 8
21+
| static_cast<uint32_t>(static_cast<uint8_t>(s[j + 2])) << 16
22+
| static_cast<uint32_t>(static_cast<uint8_t>(s[j + 3])) << 24;
23+
24+
k *= c1;
25+
k = (k << 15) | (k >> 17);
26+
k *= c2;
27+
28+
h ^= k;
29+
h = (h << 13) | (h >> 19);
30+
h = h * 5u + 0xe6546b64u;
31+
}
32+
33+
uint32_t k = 0;
34+
const size_t tail = nblocks * 4;
35+
switch (s.size() % 4)
36+
{
37+
case 3: k ^= static_cast<uint32_t>(static_cast<uint8_t>(s[tail + 2])) << 16; [[fallthrough]];
38+
case 2: k ^= static_cast<uint32_t>(static_cast<uint8_t>(s[tail + 1])) << 8; [[fallthrough]];
39+
case 1: k ^= static_cast<uint32_t>(static_cast<uint8_t>(s[tail]));
40+
k *= c1;
41+
k = (k << 15) | (k >> 17);
42+
k *= c2;
43+
h ^= k;
44+
}
45+
46+
h ^= static_cast<uint32_t>(s.size());
47+
h ^= h >> 16;
48+
h *= 0x85ebca6bu;
49+
h ^= h >> 13;
50+
h *= 0xc2b2ae35u;
51+
h ^= h >> 16;
52+
53+
return h;
54+
}

utility/named_type_wrapper.hpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
#pragma once
2-
#include <utility>
2+
#include "../hash/hash_consteval.hpp"
33

4-
template <typename T, int>
4+
#include <type_traits>
5+
6+
template <typename T, uint64_t>
57
struct NamedType
68
{
7-
explicit constexpr NamedType(T v) noexcept : _value{ std::move(v) } {}
9+
static_assert(std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>); // Not a hard requirement, but right now the wrapper is not suitable for non-trivial types
10+
11+
explicit constexpr NamedType(T v) noexcept : _value{ v } {}
812
constexpr NamedType() noexcept = default;
913

1014
constexpr operator T() const noexcept
@@ -16,5 +20,5 @@ struct NamedType
1620
T _value{}; // default initialization for class types; zero initialization for primitive type: 'false' for bool, '0' for int etc.
1721
};
1822

19-
#define UniqueNamedBoolType NamedType<bool, __LINE__>
20-
#define UniqueNamedType(T) NamedType<T, __LINE__>
23+
#define UniqueNamedBoolType NamedType<bool, __LINE__ + murmur3_32_consteval(__FILE__)>
24+
#define UniqueNamedType(T) NamedType<T, __LINE__ + murmur3_32_consteval(__FILE__)>

0 commit comments

Comments
 (0)