1#ifndef SOURCEMETA_CORE_JSON_HASH_H_
2#define SOURCEMETA_CORE_JSON_HASH_H_
4#include <sourcemeta/core/numeric.h>
12namespace sourcemeta::core {
17 using hash_type = std::uint64_t;
19 inline auto operator()(
const T &value)
const noexcept -> hash_type {
20 if constexpr (
requires { value.get().fast_hash(); }) {
21 return value.get().fast_hash();
23 return value.fast_hash();
29 inline auto is_perfect(
const hash_type)
const noexcept ->
bool {
42 auto operator==(
const hash_type &)
const noexcept ->
bool =
default;
48 const std::size_t size)
const noexcept -> hash_type {
57 static_assert(std::endian::native == std::endian::little);
58 for (std::size_t index = 0; index < size; index += 1) {
59 const auto byte{
static_cast<typename hash_type::type
>(
60 static_cast<unsigned char>(data[index]))};
61 const auto position{index + 1};
63 result.a |= byte << static_cast<int>(8 * position);
65 result.b |= byte << static_cast<int>(8 * (position - 16));
69 std::memcpy(
reinterpret_cast<char *
>(&result) + 1, data, size);
79 constexpr auto operator()(
const T &value)
const noexcept -> hash_type {
80 const auto size{value.size()};
85 return this->
perfect(value.data(), 1);
87 return this->
perfect(value.data(), 2);
89 return this->
perfect(value.data(), 3);
91 return this->
perfect(value.data(), 4);
93 return this->
perfect(value.data(), 5);
95 return this->
perfect(value.data(), 6);
97 return this->
perfect(value.data(), 7);
99 return this->
perfect(value.data(), 8);
101 return this->
perfect(value.data(), 9);
103 return this->
perfect(value.data(), 10);
105 return this->
perfect(value.data(), 11);
107 return this->
perfect(value.data(), 12);
109 return this->
perfect(value.data(), 13);
111 return this->
perfect(value.data(), 14);
113 return this->
perfect(value.data(), 15);
115 return this->
perfect(value.data(), 16);
117 return this->
perfect(value.data(), 17);
119 return this->
perfect(value.data(), 18);
121 return this->
perfect(value.data(), 19);
123 return this->
perfect(value.data(), 20);
125 return this->
perfect(value.data(), 21);
127 return this->
perfect(value.data(), 22);
129 return this->
perfect(value.data(), 23);
131 return this->
perfect(value.data(), 24);
133 return this->
perfect(value.data(), 25);
135 return this->
perfect(value.data(), 26);
137 return this->
perfect(value.data(), 27);
139 return this->
perfect(value.data(), 28);
141 return this->
perfect(value.data(), 29);
143 return this->
perfect(value.data(), 30);
145 return this->
perfect(value.data(), 31);
150 auto hash = this->
perfect(value.data(), 31);
151 hash.a |= 1 + (
static_cast<std::uint64_t
>(size) +
152 static_cast<typename hash_type::type
>(value.front()) +
153 static_cast<typename hash_type::type
>(value.back())) %
160 constexpr auto operator()(
const char *data,
161 const std::size_t size)
const noexcept
185 return this->
perfect(data, 10);
187 return this->
perfect(data, 11);
189 return this->
perfect(data, 12);
191 return this->
perfect(data, 13);
193 return this->
perfect(data, 14);
195 return this->
perfect(data, 15);
197 return this->
perfect(data, 16);
199 return this->
perfect(data, 17);
201 return this->
perfect(data, 18);
203 return this->
perfect(data, 19);
205 return this->
perfect(data, 20);
207 return this->
perfect(data, 21);
209 return this->
perfect(data, 22);
211 return this->
perfect(data, 23);
213 return this->
perfect(data, 24);
215 return this->
perfect(data, 25);
217 return this->
perfect(data, 26);
219 return this->
perfect(data, 27);
221 return this->
perfect(data, 28);
223 return this->
perfect(data, 29);
225 return this->
perfect(data, 30);
227 return this->
perfect(data, 31);
232 auto hash = this->
perfect(data, 31);
233 hash.a |= 1 + (
static_cast<std::uint64_t
>(size) +
234 static_cast<typename hash_type::type
>(data[0]) +
235 static_cast<typename hash_type::type
>(data[size - 1])) %
244 constexpr auto is_perfect(
const hash_type &hash)
const noexcept ->
bool {
247 return (hash.a & 255) == 0;
257 inline auto operator()(
const T &left,
const T &right)
const ->
bool {
258 if constexpr (
requires { left.get() == right.get(); }) {
259 return left.get() == right.get();
261 return left == right;
constexpr auto perfect(const char *data, const std::size_t size) const noexcept -> hash_type
Compute a perfect hash from raw data.
Definition json_hash.h:47
auto is_perfect(const hash_type) const noexcept -> bool
Check whether the given hash is a perfect hash.
Definition json_hash.h:29
constexpr auto is_perfect(const hash_type &hash) const noexcept -> bool
Check whether the given hash is a perfect hash.
Definition json_hash.h:244