GEGELATI
hash.h
1
40#ifndef HASH_H
41#define HASH_H
42
43#include <cstddef>
44#include <type_traits>
45
46namespace Data {
47
48#ifndef DOXYGEN_SHOULD_SKIP_THIS
49
50#ifndef _NODISCARD
51#define _NODISCARD [[nodiscard]]
52#endif
53
54#if defined(_WIN64) || defined(__x86_64__) || defined(__aarch64__)
55 inline constexpr size_t _FNV_offset_basis = 14695981039346656037ULL;
56 inline constexpr size_t _FNV_prime = 1099511628211ULL;
57#else // defined(_WIN64)
58 inline constexpr size_t _FNV_offset_basis = 2166136261U;
59 inline constexpr size_t _FNV_prime = 16777619U;
60#endif // defined(_WIN64)
61
62 _NODISCARD inline size_t _Fnv1a_append_bytes(
63 size_t _Val, const unsigned char* const _First,
64 const size_t _Count) noexcept
65 { // accumulate range [_First, _First + _Count) into partial FNV-1a hash
66 // _Val
67 for (size_t _Idx = 0; _Idx < _Count; ++_Idx) {
68 _Val ^= static_cast<size_t>(_First[_Idx]);
69 _Val *= _FNV_prime;
70 }
71
72 return _Val;
73 }
74
75 template <class _Kty>
76 _NODISCARD size_t _Fnv1a_append_value(const size_t _Val,
77 const _Kty& _Keyval) noexcept
78 { // accumulate _Keyval into partial FNV-1a hash _Val
79 static_assert(std::is_trivial_v<_Kty>,
80 "Only trivial types can be directly hashed.");
81 return _Fnv1a_append_bytes(
82 _Val, &reinterpret_cast<const unsigned char&>(_Keyval),
83 sizeof(_Kty));
84 }
85
86 // FUNCTION TEMPLATE _Hash_representation
87 template <class _Kty>
88 _NODISCARD size_t _Hash_representation(const _Kty& _Keyval) noexcept
89 { // bitwise hashes the representation of a key
90 return _Fnv1a_append_value(_FNV_offset_basis, _Keyval);
91 }
92
93 // STRUCT TEMPLATE _Conditionally_enabled_hash
94 template <class _Kty> struct Hash;
95
96 template <class _Kty, bool _Enabled> struct _Conditionally_enabled_hash
97 { // conditionally enabled hash base
98 using argument_type = _Kty;
99 using result_type = size_t;
100
101 _NODISCARD size_t
102
103 operator()(const _Kty& _Keyval) const
104 noexcept(noexcept(Hash<_Kty>::_Do_hash(_Keyval))) /* strengthened */
105 {
106 return Hash<_Kty>::_Do_hash(_Keyval);
107 }
108 };
109
110 // STRUCT TEMPLATE hash
111 template <class _Kty>
112 struct Hash
113 : _Conditionally_enabled_hash<
114 _Kty, !std::is_const_v<_Kty> && !std::is_volatile_v<_Kty> &&
115 (std::is_enum_v<_Kty> || std::is_integral_v<_Kty> ||
116 std::is_pointer_v<_Kty>)>
117 {
118 // hash functor primary template (handles enums, integrals, and
119 // pointers)
120 static size_t _Do_hash(const _Kty& _Keyval) noexcept
121 {
122 return _Hash_representation(_Keyval);
123 }
124 };
125
126 template <> struct Hash<float>
127 {
128 using argument_type = float;
129 using result_type = size_t;
130 _NODISCARD size_t
131
132 operator()(const float _Keyval) const noexcept
133 {
134 return _Hash_representation(
135 _Keyval == 0.0F ? 0.0F : _Keyval); // map -0 to 0
136 }
137 };
138
139 template <> struct Hash<double>
140 {
141 using argument_type = double;
142 using result_type = size_t;
143 _NODISCARD size_t
144
145 operator()(const double _Keyval) const noexcept
146 {
147 return _Hash_representation(
148 _Keyval == 0.0 ? 0.0 : _Keyval); // map -0 to 0
149 }
150 };
151
152 template <> struct Hash<std::nullptr_t>
153 {
154 using argument_type = std::nullptr_t;
155 using result_type = size_t;
156 _NODISCARD size_t
157
158 operator()(std::nullptr_t) const noexcept
159 {
160 void* _Null{};
161 return _Hash_representation(_Null);
162 }
163 };
164#endif // DOXYGEN_SHOULD_SKIP_THIS
165} // namespace Data
166
167#endif
Definition: array2DWrapper.h:44