/src/abseil-cpp/absl/hash/hash.h
Line | Count | Source |
1 | | // Copyright 2018 The Abseil Authors. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of 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, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | // ----------------------------------------------------------------------------- |
16 | | // File: hash.h |
17 | | // ----------------------------------------------------------------------------- |
18 | | // |
19 | | // This header file defines the Abseil `hash` library and the Abseil hashing |
20 | | // framework. This framework consists of the following: |
21 | | // |
22 | | // * The `absl::Hash` functor, which is used to invoke the hasher within the |
23 | | // Abseil hashing framework. `absl::Hash<T>` supports most basic types and |
24 | | // a number of Abseil types out of the box. |
25 | | // * The `absl::TransparentHash` functor, which provides transparent hashing |
26 | | // for heterogeneous lookup across multiple types in associative containers. |
27 | | // * `AbslHashValue`, an extension point that allows you to extend types to |
28 | | // support Abseil hashing without requiring you to define a hashing |
29 | | // algorithm. |
30 | | // * `HashState`, a type-erased class which implements the manipulation of the |
31 | | // hash state (H) itself; contains member functions `combine()`, |
32 | | // `combine_contiguous()`, and `combine_unordered()`; and which you can use |
33 | | // to contribute to an existing hash state when hashing your types. |
34 | | // |
35 | | // Unlike `std::hash` or other hashing frameworks, the Abseil hashing framework |
36 | | // provides most of its utility by abstracting away the hash algorithm (and its |
37 | | // implementation) entirely. Instead, a type invokes the Abseil hashing |
38 | | // framework by simply combining its state with the state of known, hashable |
39 | | // types. Hashing of that combined state is separately done by `absl::Hash`. |
40 | | // |
41 | | // One should assume that a hash algorithm is chosen randomly at the start of |
42 | | // each process. E.g., `absl::Hash<int>{}(9)` in one process and |
43 | | // `absl::Hash<int>{}(9)` in another process are likely to differ. |
44 | | // |
45 | | // `absl::Hash` may also produce different values from different dynamically |
46 | | // loaded libraries. For this reason, `absl::Hash` values must never cross |
47 | | // boundaries in dynamically loaded libraries (including when used in types like |
48 | | // hash containers.) |
49 | | // |
50 | | // `absl::Hash` is intended to strongly mix input bits with a target of passing |
51 | | // an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect). |
52 | | // |
53 | | // Example: |
54 | | // |
55 | | // // Suppose we have a class `Circle` for which we want to add hashing: |
56 | | // class Circle { |
57 | | // public: |
58 | | // ... |
59 | | // private: |
60 | | // std::pair<int, int> center_; |
61 | | // int radius_; |
62 | | // }; |
63 | | // |
64 | | // // To add hashing support to `Circle`, we simply need to add a free |
65 | | // // (non-member) function `AbslHashValue()`, and return the combined hash |
66 | | // // state of the existing hash state and the class state. You can add such a |
67 | | // // free function using a friend declaration within the body of the class: |
68 | | // class Circle { |
69 | | // public: |
70 | | // ... |
71 | | // template <typename H> |
72 | | // friend H AbslHashValue(H h, const Circle& c) { |
73 | | // return H::combine(std::move(h), c.center_, c.radius_); |
74 | | // } |
75 | | // ... |
76 | | // }; |
77 | | // |
78 | | // For more information, see Adding Type Support to `absl::Hash` below. |
79 | | // |
80 | | #ifndef ABSL_HASH_HASH_H_ |
81 | | #define ABSL_HASH_HASH_H_ |
82 | | |
83 | | #include <cstddef> |
84 | | #include <cstdint> |
85 | | #include <tuple> |
86 | | #include <type_traits> |
87 | | #include <utility> |
88 | | |
89 | | #include "absl/base/config.h" |
90 | | #include "absl/functional/function_ref.h" |
91 | | #include "absl/hash/internal/hash.h" |
92 | | #include "absl/hash/internal/weakly_mixed_integer.h" |
93 | | #include "absl/meta/type_traits.h" |
94 | | |
95 | | namespace absl { |
96 | | ABSL_NAMESPACE_BEGIN |
97 | | |
98 | | // ----------------------------------------------------------------------------- |
99 | | // `absl::Hash` |
100 | | // ----------------------------------------------------------------------------- |
101 | | // |
102 | | // `absl::Hash<T>` is a convenient general-purpose hash functor for any type `T` |
103 | | // satisfying any of the following conditions (in order): |
104 | | // |
105 | | // * T is an arithmetic or pointer type |
106 | | // * T defines an overload for `AbslHashValue(H, const T&)` for an arbitrary |
107 | | // hash state `H`. |
108 | | // - T defines a specialization of `std::hash<T>` |
109 | | // |
110 | | // `absl::Hash` intrinsically supports the following types: |
111 | | // |
112 | | // * All integral types (including bool) |
113 | | // * All enum types |
114 | | // * All floating-point types (although hashing them is discouraged) |
115 | | // * All pointer types, including nullptr_t |
116 | | // * std::pair<T1, T2>, if T1 and T2 are hashable |
117 | | // * std::tuple<Ts...>, if all the Ts... are hashable |
118 | | // * std::unique_ptr and std::shared_ptr |
119 | | // * All string-like types including: |
120 | | // * absl::Cord |
121 | | // * std::string (as well as any instance of std::basic_string that |
122 | | // uses one of {char, wchar_t, char8_t, char16_t, char32_t} and its |
123 | | // associated std::char_traits) |
124 | | // * std::string_view (as well as any instance of std::basic_string_view |
125 | | // that uses one of {char, wchar_t, char8_t, char16_t, char32_t} and its |
126 | | // associated std::char_traits) |
127 | | // * All the standard sequence containers (provided the elements are hashable) |
128 | | // * All the standard associative containers (provided the elements are |
129 | | // hashable) |
130 | | // * absl types such as the following: |
131 | | // * absl::string_view |
132 | | // * absl::uint128 |
133 | | // * absl::Time, absl::Duration, and absl::TimeZone |
134 | | // * absl containers (provided the elements are hashable) such as the |
135 | | // following: |
136 | | // * absl::flat_hash_set, absl::node_hash_set, absl::btree_set |
137 | | // * absl::flat_hash_map, absl::node_hash_map, absl::btree_map |
138 | | // * absl::btree_multiset, absl::btree_multimap |
139 | | // * absl::InlinedVector |
140 | | // * absl::FixedArray |
141 | | // |
142 | | // When absl::Hash is used to hash an unordered container with a custom hash |
143 | | // functor, the elements are hashed using default absl::Hash semantics, not |
144 | | // the custom hash functor. This is consistent with the behavior of |
145 | | // operator==() on unordered containers, which compares elements pairwise with |
146 | | // operator==() rather than the custom equality functor. It is usually a |
147 | | // mistake to use either operator==() or absl::Hash on unordered collections |
148 | | // that use functors incompatible with operator==() equality. |
149 | | // |
150 | | // Note: the list above is not meant to be exhaustive. Additional type support |
151 | | // may be added, in which case the above list will be updated. |
152 | | // |
153 | | // ----------------------------------------------------------------------------- |
154 | | // absl::Hash Invocation Evaluation |
155 | | // ----------------------------------------------------------------------------- |
156 | | // |
157 | | // When invoked, `absl::Hash<T>` searches for supplied hash functions in the |
158 | | // following order: |
159 | | // |
160 | | // * Natively supported types out of the box (see above) |
161 | | // * Types for which an `AbslHashValue()` overload is provided (such as |
162 | | // user-defined types). See "Adding Type Support to `absl::Hash`" below. |
163 | | // * Types which define a `std::hash<T>` specialization |
164 | | // |
165 | | // The fallback to legacy hash functions exists mainly for backwards |
166 | | // compatibility. If you have a choice, prefer defining an `AbslHashValue` |
167 | | // overload instead of specializing any legacy hash functors. |
168 | | // |
169 | | // ----------------------------------------------------------------------------- |
170 | | // The Hash State Concept, and using `HashState` for Type Erasure |
171 | | // ----------------------------------------------------------------------------- |
172 | | // |
173 | | // The `absl::Hash` framework relies on the Concept of a "hash state." Such a |
174 | | // hash state is used in several places: |
175 | | // |
176 | | // * Within existing implementations of `absl::Hash<T>` to store the hashed |
177 | | // state of an object. Note that it is up to the implementation how it stores |
178 | | // such state. A hash table, for example, may mix the state to produce an |
179 | | // integer value; a testing framework may simply hold a vector of that state. |
180 | | // * Within implementations of `AbslHashValue()` used to extend user-defined |
181 | | // types. (See "Adding Type Support to absl::Hash" below.) |
182 | | // * Inside a `HashState`, providing type erasure for the concept of a hash |
183 | | // state, which you can use to extend the `absl::Hash` framework for types |
184 | | // that are otherwise difficult to extend using `AbslHashValue()`. (See the |
185 | | // `HashState` class below.) |
186 | | // |
187 | | // The "hash state" concept contains three member functions for mixing hash |
188 | | // state: |
189 | | // |
190 | | // * `H::combine(state, values...)` |
191 | | // |
192 | | // Combines an arbitrary number of values into a hash state, returning the |
193 | | // updated state. Note that the existing hash state is move-only and must be |
194 | | // passed by value. |
195 | | // |
196 | | // Each of the value types T must be hashable by H. |
197 | | // |
198 | | // NOTE: |
199 | | // |
200 | | // state = H::combine(std::move(state), value1, value2, value3); |
201 | | // |
202 | | // must be guaranteed to produce the same hash expansion as |
203 | | // |
204 | | // state = H::combine(std::move(state), value1); |
205 | | // state = H::combine(std::move(state), value2); |
206 | | // state = H::combine(std::move(state), value3); |
207 | | // |
208 | | // * `H::combine_contiguous(state, data, size)` |
209 | | // |
210 | | // Combines a contiguous array of `size` elements into a hash state, |
211 | | // returning the updated state. Note that the existing hash state is |
212 | | // move-only and must be passed by value. |
213 | | // |
214 | | // NOTE: |
215 | | // |
216 | | // state = H::combine_contiguous(std::move(state), data, size); |
217 | | // |
218 | | // need NOT be guaranteed to produce the same hash expansion as a loop |
219 | | // (it may perform internal optimizations). If you need this guarantee, use a |
220 | | // loop instead. |
221 | | // |
222 | | // * `H::combine_unordered(state, begin, end)` |
223 | | // |
224 | | // Combines a set of elements denoted by an iterator pair into a hash |
225 | | // state, returning the updated state. Note that the existing hash |
226 | | // state is move-only and must be passed by value. |
227 | | // |
228 | | // Unlike the other two methods, the hashing is order-independent. |
229 | | // This can be used to hash unordered collections. |
230 | | // |
231 | | // ----------------------------------------------------------------------------- |
232 | | // Adding Type Support to `absl::Hash` |
233 | | // ----------------------------------------------------------------------------- |
234 | | // |
235 | | // To add support for your user-defined type, add a proper `AbslHashValue()` |
236 | | // overload as a free (non-member) function. The overload will take an |
237 | | // existing hash state and should combine that state with state from the type. |
238 | | // |
239 | | // Example: |
240 | | // |
241 | | // template <typename H> |
242 | | // H AbslHashValue(H state, const MyType& v) { |
243 | | // return H::combine(std::move(state), v.field1, ..., v.fieldN); |
244 | | // } |
245 | | // |
246 | | // where `(field1, ..., fieldN)` are the members you would use on your |
247 | | // `operator==` to define equality. |
248 | | // |
249 | | // Notice that `AbslHashValue` is not a class member, but an ordinary function. |
250 | | // An `AbslHashValue` overload for a type should only be declared in the same |
251 | | // file and namespace as said type. The proper `AbslHashValue` implementation |
252 | | // for a given type will be discovered via ADL. |
253 | | // |
254 | | // Note: unlike `std::hash', `absl::Hash` should never be specialized. It must |
255 | | // only be extended by adding `AbslHashValue()` overloads. |
256 | | // |
257 | | template <typename T> |
258 | | using Hash = absl::hash_internal::Hash<T>; |
259 | | |
260 | | // TransparentHash |
261 | | // |
262 | | // `absl::TransparentHash<Ts...>` is a transparent hash functor that provides |
263 | | // heterogeneous hashing across multiple types `Ts...` for associative |
264 | | // containers such as `absl::flat_hash_set` and `absl::flat_hash_map`. |
265 | | // |
266 | | // It exposes `operator()(const T&)` overloads for each type `T` in `Ts...`, |
267 | | // delegating each call to `absl::Hash<T>{}(value)`. It also defines the nested |
268 | | // type alias `using is_transparent = void;`, signaling to containers that |
269 | | // heterogeneous lookup is supported. |
270 | | // |
271 | | // If any type in `Ts...` is not hashable within the `absl::Hash` framework, |
272 | | // `absl::TransparentHash` is poisoned (its call operators are disabled) in the |
273 | | // same manner as `absl::Hash`. |
274 | | // |
275 | | // Duplicates types are allowed in `Ts...`. |
276 | | // |
277 | | // Requirements: |
278 | | // |
279 | | // For heterogeneous lookup to be correct, equivalent values across different |
280 | | // types must produce identical hash values. That is, if `a == b`, then |
281 | | // `TransparentHash{}(a) == TransparentHash{}(b)` must hold. This is typically |
282 | | // satisfied when the `AbslHashValue()` implementations for each type combine |
283 | | // identical fields in the same order. |
284 | | // |
285 | | // Usage: |
286 | | // |
287 | | // `absl::TransparentHash` can be used in two ways: |
288 | | // |
289 | | // 1. As an explicit `Hash` template argument to a container: |
290 | | // |
291 | | // absl::flat_hash_set<Name, absl::TransparentHash<Name, NameView>, |
292 | | // NameEq> set; |
293 | | // |
294 | | // 2. As the nested `absl_container_hash` type alias within a user-defined key |
295 | | // type: |
296 | | // |
297 | | // struct Name { |
298 | | // ... |
299 | | // using absl_container_hash = absl::TransparentHash<Name, NameView>; |
300 | | // }; |
301 | | // |
302 | | // When `absl_container_hash` is defined in the key type, Abseil hash |
303 | | // containers will automatically use it and enable heterogeneous lookup by |
304 | | // default (using `std::equal_to<void>` for equality if `absl_container_eq` |
305 | | // is not provided). |
306 | | // |
307 | | // Example: |
308 | | // |
309 | | // struct NameView { |
310 | | // absl::string_view first; |
311 | | // absl::string_view last; |
312 | | // |
313 | | // template <typename H> |
314 | | // friend H AbslHashValue(H h, const NameView& nv) { |
315 | | // return H::combine(std::move(h), nv.first, nv.last); |
316 | | // } |
317 | | // friend bool operator==(const NameView& a, const NameView& b); |
318 | | // }; |
319 | | // |
320 | | // struct Name { |
321 | | // std::string first; |
322 | | // std::string last; |
323 | | // |
324 | | // template <typename H> |
325 | | // friend H AbslHashValue(H h, const Name& n) { |
326 | | // return H::combine(std::move(h), n.first, n.last); |
327 | | // } |
328 | | // friend bool operator==(const Name& a, const Name& b); |
329 | | // friend bool operator==(const Name& a, const NameView& b); |
330 | | // |
331 | | // using absl_container_hash = absl::TransparentHash<Name, NameView>; |
332 | | // }; |
333 | | // |
334 | | // absl::flat_hash_set<Name> names; |
335 | | // names.insert(Name{"John", "Doe"}); |
336 | | // |
337 | | // // Look up using `NameView` without constructing a temporary `Name` or |
338 | | // // allocating memory: |
339 | | // assert(names.contains(NameView{"John", "Doe"})); |
340 | | template <typename... Ts> |
341 | | using TransparentHash = absl::hash_internal::TransparentHash<Ts...>; |
342 | | |
343 | | // HashOf |
344 | | // |
345 | | // absl::HashOf() is a helper that generates a hash from the values of its |
346 | | // arguments. It dispatches to absl::Hash directly, as follows: |
347 | | // * HashOf(t) == absl::Hash<T>{}(t) |
348 | | // * HashOf(a, b, c) == HashOf(std::make_tuple(a, b, c)) |
349 | | // |
350 | | // HashOf(a1, a2, ...) == HashOf(b1, b2, ...) is guaranteed when |
351 | | // * The argument lists have pairwise identical C++ types |
352 | | // * a1 == b1 && a2 == b2 && ... |
353 | | // |
354 | | // The requirement that the arguments match in both type and value is critical. |
355 | | // It means that `a == b` does not necessarily imply `HashOf(a) == HashOf(b)` if |
356 | | // `a` and `b` have different types. For example, `HashOf(2) != HashOf(2.0)`. |
357 | | template <int&... ExplicitArgumentBarrier, typename... Types> |
358 | 0 | size_t HashOf(const Types&... values) { |
359 | 0 | auto tuple = std::tie(values...); |
360 | 0 | return absl::Hash<decltype(tuple)>{}(tuple); |
361 | 0 | } Unexecuted instantiation: _ZN4absl6HashOfITpTnRiJEJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEiEEEmDpRKT0_ Unexecuted instantiation: _ZN4absl6HashOfITpTnRiJEJmEEEmDpRKT0_ |
362 | | |
363 | | // HashState |
364 | | // |
365 | | // A type erased version of the hash state concept, for use in user-defined |
366 | | // `AbslHashValue` implementations that can't use templates (such as PImpl |
367 | | // classes, virtual functions, etc.). The type erasure adds overhead so it |
368 | | // should be avoided unless necessary. |
369 | | // |
370 | | // Note: This wrapper will only erase calls to |
371 | | // combine_contiguous(H, const unsigned char*, size_t) |
372 | | // RunCombineUnordered(H, CombinerF) |
373 | | // |
374 | | // All other calls will be handled internally and will not invoke overloads |
375 | | // provided by the wrapped class. |
376 | | // |
377 | | // Users of this class should still define a template `AbslHashValue` function, |
378 | | // but can use `absl::HashState::Create(&state)` to erase the type of the hash |
379 | | // state and dispatch to their private hashing logic. |
380 | | // |
381 | | // This state can be used like any other hash state. In particular, you can call |
382 | | // `HashState::combine()` and `HashState::combine_contiguous()` on it. |
383 | | // |
384 | | // Example: |
385 | | // |
386 | | // class Interface { |
387 | | // public: |
388 | | // template <typename H> |
389 | | // friend H AbslHashValue(H state, const Interface& value) { |
390 | | // state = H::combine(std::move(state), std::type_index(typeid(*this))); |
391 | | // value.HashValue(absl::HashState::Create(&state)); |
392 | | // return state; |
393 | | // } |
394 | | // private: |
395 | | // virtual void HashValue(absl::HashState state) const = 0; |
396 | | // }; |
397 | | // |
398 | | // class Impl : Interface { |
399 | | // private: |
400 | | // void HashValue(absl::HashState state) const override { |
401 | | // absl::HashState::combine(std::move(state), v1_, v2_); |
402 | | // } |
403 | | // int v1_; |
404 | | // std::string v2_; |
405 | | // }; |
406 | | class HashState : public hash_internal::HashStateBase<HashState> { |
407 | | public: |
408 | | // HashState::Create() |
409 | | // |
410 | | // Create a new `HashState` instance that wraps `state`. All calls to |
411 | | // `combine()` and `combine_contiguous()` on the new instance will be |
412 | | // redirected to the original `state` object. The `state` object must outlive |
413 | | // the `HashState` instance. `T` must be a subclass of `HashStateBase<T>` - |
414 | | // users should not define their own HashState types. |
415 | | template <typename T, |
416 | | std::enable_if_t< |
417 | | std::is_base_of_v<hash_internal::HashStateBase<T>, T>, int> = 0> |
418 | | static HashState Create(T* state) { |
419 | | HashState s; |
420 | | s.Init(state); |
421 | | return s; |
422 | | } |
423 | | |
424 | | HashState(const HashState&) = delete; |
425 | | HashState& operator=(const HashState&) = delete; |
426 | | HashState(HashState&&) = default; |
427 | | HashState& operator=(HashState&&) = default; |
428 | | |
429 | | // HashState::combine() |
430 | | // |
431 | | // Combines an arbitrary number of values into a hash state, returning the |
432 | | // updated state. |
433 | | using HashState::HashStateBase::combine; |
434 | | |
435 | | // HashState::combine_contiguous() |
436 | | // |
437 | | // Combines a contiguous array of `size` elements into a hash state, returning |
438 | | // the updated state. |
439 | | static HashState combine_contiguous(HashState hash_state, |
440 | 0 | const unsigned char* first, size_t size) { |
441 | 0 | hash_state.combine_contiguous_(hash_state.state_, first, size); |
442 | 0 | return hash_state; |
443 | 0 | } |
444 | | |
445 | | static HashState combine_weakly_mixed_integer( |
446 | 0 | HashState hash_state, hash_internal::WeaklyMixedInteger value) { |
447 | 0 | hash_state.combine_weakly_mixed_integer_(hash_state.state_, value); |
448 | 0 | return hash_state; |
449 | 0 | } |
450 | | using HashState::HashStateBase::combine_contiguous; |
451 | | |
452 | | private: |
453 | | HashState() = default; |
454 | | |
455 | | friend class HashState::HashStateBase; |
456 | | friend struct hash_internal::CombineRaw; |
457 | | |
458 | | template <typename T> |
459 | | static void CombineContiguousImpl(void* p, const unsigned char* first, |
460 | | size_t size) { |
461 | | T& state = *static_cast<T*>(p); |
462 | | state = T::combine_contiguous(std::move(state), first, size); |
463 | | } |
464 | | |
465 | | template <typename T> |
466 | | static void CombineWeaklyMixedIntegerImpl( |
467 | | void* p, hash_internal::WeaklyMixedInteger value) { |
468 | | T& state = *static_cast<T*>(p); |
469 | | state = T::combine_weakly_mixed_integer(std::move(state), value); |
470 | | } |
471 | | |
472 | 0 | static HashState combine_raw(HashState hash_state, uint64_t value) { |
473 | 0 | hash_state.combine_raw_(hash_state.state_, value); |
474 | 0 | return hash_state; |
475 | 0 | } |
476 | | |
477 | | template <typename T> |
478 | | static void CombineRawImpl(void* p, uint64_t value) { |
479 | | T& state = *static_cast<T*>(p); |
480 | | state = hash_internal::CombineRaw()(std::move(state), value); |
481 | | } |
482 | | |
483 | | template <typename T> |
484 | | void Init(T* state) { |
485 | | state_ = state; |
486 | | combine_weakly_mixed_integer_ = &CombineWeaklyMixedIntegerImpl<T>; |
487 | | combine_contiguous_ = &CombineContiguousImpl<T>; |
488 | | combine_raw_ = &CombineRawImpl<T>; |
489 | | run_combine_unordered_ = &RunCombineUnorderedImpl<T>; |
490 | | } |
491 | | |
492 | | template <typename HS> |
493 | | struct CombineUnorderedInvoker { |
494 | | template <typename T, typename ConsumerT> |
495 | | void operator()(T inner_state, ConsumerT inner_cb) { |
496 | | f(HashState::Create(&inner_state), |
497 | | [&](HashState& inner_erased) { inner_cb(inner_erased.Real<T>()); }); |
498 | | } |
499 | | |
500 | | absl::FunctionRef<void(HS, absl::FunctionRef<void(HS&)>)> f; |
501 | | }; |
502 | | |
503 | | template <typename T> |
504 | | static HashState RunCombineUnorderedImpl( |
505 | | HashState state, |
506 | | absl::FunctionRef<void(HashState, absl::FunctionRef<void(HashState&)>)> |
507 | | f) { |
508 | | // Note that this implementation assumes that inner_state and outer_state |
509 | | // are the same type. This isn't true in the SpyHash case, but SpyHash |
510 | | // types are move-convertible to each other, so this still works. |
511 | | T& real_state = state.Real<T>(); |
512 | | real_state = T::RunCombineUnordered( |
513 | | std::move(real_state), CombineUnorderedInvoker<HashState>{f}); |
514 | | return state; |
515 | | } |
516 | | |
517 | | template <typename CombinerT> |
518 | | static HashState RunCombineUnordered(HashState state, CombinerT combiner) { |
519 | | auto* run = state.run_combine_unordered_; |
520 | | return run(std::move(state), std::ref(combiner)); |
521 | | } |
522 | | |
523 | | // Do not erase an already erased state. |
524 | 0 | void Init(HashState* state) { |
525 | 0 | state_ = state->state_; |
526 | 0 | combine_weakly_mixed_integer_ = state->combine_weakly_mixed_integer_; |
527 | 0 | combine_contiguous_ = state->combine_contiguous_; |
528 | 0 | combine_raw_ = state->combine_raw_; |
529 | 0 | run_combine_unordered_ = state->run_combine_unordered_; |
530 | 0 | } |
531 | | |
532 | | template <typename T> |
533 | | T& Real() { |
534 | | return *static_cast<T*>(state_); |
535 | | } |
536 | | |
537 | | void* state_; |
538 | | void (*combine_weakly_mixed_integer_)( |
539 | | void*, absl::hash_internal::WeaklyMixedInteger); |
540 | | void (*combine_contiguous_)(void*, const unsigned char*, size_t); |
541 | | void (*combine_raw_)(void*, uint64_t); |
542 | | HashState (*run_combine_unordered_)( |
543 | | HashState state, |
544 | | absl::FunctionRef<void(HashState, absl::FunctionRef<void(HashState&)>)>); |
545 | | }; |
546 | | |
547 | | ABSL_NAMESPACE_END |
548 | | } // namespace absl |
549 | | |
550 | | #endif // ABSL_HASH_HASH_H_ |