C/C++ API Reference
Loading...
Searching...
No Matches
functional.h
1// Copyright 2026 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstddef>
17#include <cstdint>
18#include <functional>
19#include <type_traits>
20#include <utility>
21#include <variant>
22
23namespace pw {
24
25class HashState;
26
35template <typename H, typename T>
36H PwHashValue(H h, const T& val) = delete;
37
38namespace hash_impl {
39
40template <typename H, typename T, typename = void>
41struct HasPwHashValue : std::false_type {};
42
43template <typename H, typename T>
45 T,
46 std::void_t<decltype(PwHashValue(
47 std::declval<H>(), std::declval<const T&>()))>>
48 : std::is_same<decltype(PwHashValue(std::declval<H>(),
49 std::declval<const T&>())),
50 H> {};
51
52template <typename H, typename T>
53inline constexpr bool kHasPwHashValue = HasPwHashValue<H, T>::value;
54
55template <typename T, typename = void>
56struct HasStdHash : std::false_type {};
57
58template <typename T>
59struct HasStdHash<T,
60 std::void_t<decltype(std::declval<std::hash<T>>()(
61 std::declval<const T&>()))>>
62 : std::is_same<decltype(std::declval<std::hash<T>>()(
63 std::declval<const T&>())),
64 size_t> {};
65
66template <typename T>
67inline constexpr bool kHasStdHash = HasStdHash<T>::value;
68
69template <typename T>
70struct IsStdVariant : std::false_type {};
71
72template <typename... Ts>
73struct IsStdVariant<std::variant<Ts...>> : std::true_type {};
74
75template <typename T>
76inline constexpr bool kIsStdVariant = IsStdVariant<std::decay_t<T>>::value;
77
78// Dispatches the hashing logic based on the type traits detected above.
79// Priority:
80// 1. Custom `PwHashValue` (User-defined extension)
81// 2. Pointers (Hashed by address)
82// 3. Enums (Hashed by underlying integer value)
83// 4. Variants (Hashed by index and alternative)
84// 5. Standard `std::hash` (Fallback for int, float, etc.)
85template <typename H, typename T>
86H hash_value_dispatcher(H h, const T& val) {
87 if constexpr (kHasPwHashValue<H, T>) {
88 return PwHashValue(std::move(h), val);
89 } else if constexpr (std::is_pointer_v<T> || std::is_null_pointer_v<T>) {
90 return H::mix(std::move(h), reinterpret_cast<uintptr_t>(val));
91 } else if constexpr (std::is_enum_v<T>) {
92 return H::mix(
93 std::move(h),
94 static_cast<size_t>(static_cast<std::underlying_type_t<T>>(val)));
95 } else if constexpr (kIsStdVariant<T>) {
96 h = H::mix(std::move(h), val.index());
97 return std::visit(
98 [&](const auto& alternative) {
99 return hash_value_dispatcher(std::move(h), alternative);
100 },
101 val);
102 } else {
103 static_assert(kHasStdHash<T>,
104 "The type must be hashable by either PwHashValue, std::hash, "
105 "or a pointer/enum/variant.");
106 return H::mix(std::move(h), std::hash<T>()(val));
107 }
108}
109
110} // namespace hash_impl
111
119 public:
122 explicit HashState(size_t seed = 17) : state_(seed) {}
123
124 HashState(const HashState&) = delete;
125 HashState& operator=(const HashState&) = delete;
126 HashState(HashState&&) = default;
127 HashState& operator=(HashState&&) = default;
128
136 static HashState mix(HashState&& h, size_t val) {
137 h.state_ ^= val + 0x9e3779b9 + (h.state_ << 6) + (h.state_ >> 2);
138 return std::move(h);
139 }
140
146 template <typename T>
147 static HashState combine(HashState&& h, const T& val) {
148 h = hash_impl::hash_value_dispatcher(std::move(h), val);
149 return std::move(h);
150 }
151
170 template <typename T, typename... Ts>
171 static HashState combine(HashState&& h, const T& first, const Ts&... rest) {
172 h = combine(std::move(h), first);
173 if constexpr (sizeof...(rest) > 0) {
174 return combine(std::move(h), rest...);
175 }
176 return std::move(h);
177 }
178
193 template <typename T>
195 const T* data,
196 size_t size) {
197 for (size_t i = 0; i < size; i++) {
198 h = combine(std::move(h), data[i]);
199 }
200 return std::move(h);
201 }
202
214 template <typename InputIt>
216 InputIt first,
217 InputIt last) {
218 size_t total = 0;
219 size_t count = 0;
220 for (auto it = first; it != last; ++it) {
221 // High-entropy seed (Golden Ratio) prevents zero-swallowing
222 total += combine(HashState(0x9E3779B9), *it).finalize();
223 ++count;
224 }
225 return HashState::combine(std::move(h), total, count);
226 }
227
229 size_t finalize() { return state_; }
230
231 private:
232 size_t state_;
233};
234
235struct Hash {
236 size_t seed_;
237 constexpr explicit Hash(size_t seed = 17) : seed_(seed) {}
238
239 template <typename T>
240 constexpr size_t operator()(const T& value) const {
241 return hash_impl::hash_value_dispatcher(HashState(seed_), value).finalize();
242 }
243};
244
245// Performs comparisons with operator==, similar to C++14's `std::equal_to<>`.
246struct EqualTo {
247 template <typename T, typename U>
248 constexpr bool operator()(const T& lhs, const U& rhs) const {
249 return lhs == rhs;
250 }
251};
252
253} // namespace pw
Definition: functional.h:118
static HashState combine_contiguous(HashState &&h, const T *data, size_t size)
Definition: functional.h:194
static HashState mix(HashState &&h, size_t val)
Definition: functional.h:136
HashState(size_t seed=17)
Definition: functional.h:122
static HashState combine(HashState &&h, const T &first, const Ts &... rest)
Definition: functional.h:171
static HashState combine(HashState &&h, const T &val)
Definition: functional.h:147
static HashState combine_unordered(HashState &&h, InputIt first, InputIt last)
Definition: functional.h:215
size_t finalize()
Finalizes the hash calculation and returns the result.
Definition: functional.h:229
The Pigweed namespace.
Definition: alignment.h:27
H PwHashValue(H h, const T &val)=delete
Definition: functional.h:246
Definition: functional.h:235
Definition: functional.h:41
Definition: functional.h:56
Definition: functional.h:70