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
22namespace pw {
23
24class HashState;
25
34template <typename H, typename T>
35H PwHashValue(H h, const T& val) = delete;
36
37namespace hash_impl {
38
39template <typename H, typename T, typename = void>
40struct HasPwHashValue : std::false_type {};
41
42template <typename H, typename T>
44 T,
45 std::void_t<decltype(PwHashValue(
46 std::declval<H>(), std::declval<const T&>()))>>
47 : std::is_same<decltype(PwHashValue(std::declval<H>(),
48 std::declval<const T&>())),
49 H> {};
50
51template <typename H, typename T>
52inline constexpr bool kHasPwHashValue = HasPwHashValue<H, T>::value;
53
54template <typename T, typename = void>
55struct HasStdHash : std::false_type {};
56
57template <typename T>
58struct HasStdHash<T,
59 std::void_t<decltype(std::declval<std::hash<T>>()(
60 std::declval<const T&>()))>>
61 : std::is_same<decltype(std::declval<std::hash<T>>()(
62 std::declval<const T&>())),
63 size_t> {};
64
65template <typename T>
66inline constexpr bool kHasStdHash = HasStdHash<T>::value;
67
68// Dispatches the hashing logic based on the type traits detected above.
69// Priority:
70// 1. Custom `PwHashValue` (User-defined extension)
71// 2. Pointers (Hashed by address)
72// 3. Enums (Hashed by underlying integer value)
73// 4. Standard `std::hash` (Fallback for int, float, etc.)
74template <typename H, typename T>
75H hash_value_dispatcher(H h, const T& val) {
76 if constexpr (kHasPwHashValue<H, T>) {
77 return PwHashValue(std::move(h), val);
78 } else if constexpr (std::is_pointer_v<T> || std::is_null_pointer_v<T>) {
79 return H::mix(std::move(h), reinterpret_cast<uintptr_t>(val));
80 } else if constexpr (std::is_enum_v<T>) {
81 return H::mix(
82 std::move(h),
83 static_cast<size_t>(static_cast<std::underlying_type_t<T>>(val)));
84 } else {
85 static_assert(kHasStdHash<T>,
86 "The type must be hashable by either PwHashValue, std::hash, "
87 "or a pointer/enum.");
88 return H::mix(std::move(h), std::hash<T>()(val));
89 }
90}
91
92} // namespace hash_impl
93
101 public:
104 explicit HashState(size_t seed = 17) : state_(seed) {}
105
106 HashState(const HashState&) = delete;
107 HashState& operator=(const HashState&) = delete;
108 HashState(HashState&&) = default;
109 HashState& operator=(HashState&&) = default;
110
118 static HashState mix(HashState&& h, size_t val) {
119 h.state_ ^= val + 0x9e3779b9 + (h.state_ << 6) + (h.state_ >> 2);
120 return std::move(h);
121 }
122
128 template <typename T>
129 static HashState combine(HashState&& h, const T& val) {
130 h = hash_impl::hash_value_dispatcher(std::move(h), val);
131 return std::move(h);
132 }
133
152 template <typename T, typename... Ts>
153 static HashState combine(HashState&& h, const T& first, const Ts&... rest) {
154 h = combine(std::move(h), first);
155 if constexpr (sizeof...(rest) > 0) {
156 return combine(std::move(h), rest...);
157 }
158 return std::move(h);
159 }
160
175 template <typename T>
177 const T* data,
178 size_t size) {
179 for (size_t i = 0; i < size; i++) {
180 h = combine(std::move(h), data[i]);
181 }
182 return std::move(h);
183 }
184
196 template <typename InputIt>
198 InputIt first,
199 InputIt last) {
200 size_t total = 0;
201 size_t count = 0;
202 for (auto it = first; it != last; ++it) {
203 // High-entropy seed (Golden Ratio) prevents zero-swallowing
204 total += combine(HashState(0x9E3779B9), *it).finalize();
205 ++count;
206 }
207 return HashState::combine(std::move(h), total, count);
208 }
209
211 size_t finalize() { return state_; }
212
213 private:
214 size_t state_;
215};
216
217struct Hash {
218 size_t seed_;
219 constexpr explicit Hash(size_t seed = 17) : seed_(seed) {}
220
221 template <typename T>
222 constexpr size_t operator()(const T& value) const {
223 return hash_impl::hash_value_dispatcher(HashState(seed_), value).finalize();
224 }
225};
226
227// Performs comparisons with operator==, similar to C++14's `std::equal_to<>`.
228struct EqualTo {
229 template <typename T, typename U>
230 constexpr bool operator()(const T& lhs, const U& rhs) const {
231 return lhs == rhs;
232 }
233};
234
235} // namespace pw
Definition: functional.h:100
static HashState combine_contiguous(HashState &&h, const T *data, size_t size)
Definition: functional.h:176
static HashState mix(HashState &&h, size_t val)
Definition: functional.h:118
HashState(size_t seed=17)
Definition: functional.h:104
static HashState combine(HashState &&h, const T &first, const Ts &... rest)
Definition: functional.h:153
static HashState combine(HashState &&h, const T &val)
Definition: functional.h:129
static HashState combine_unordered(HashState &&h, InputIt first, InputIt last)
Definition: functional.h:197
size_t finalize()
Finalizes the hash calculation and returns the result.
Definition: functional.h:211
The Pigweed namespace.
Definition: alignment.h:27
H PwHashValue(H h, const T &val)=delete
Definition: functional.h:228
Definition: functional.h:217
Definition: functional.h:40
Definition: functional.h:55