xref: /aosp_15_r20/external/webrtc/third_party/abseil-cpp/absl/hash/hash.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 //   * `AbslHashValue`, an extension point that allows you to extend types to
26 //     support Abseil hashing without requiring you to define a hashing
27 //     algorithm.
28 //   * `HashState`, a type-erased class which implements the manipulation of the
29 //     hash state (H) itself; contains member functions `combine()`,
30 //     `combine_contiguous()`, and `combine_unordered()`; and which you can use
31 //     to contribute to an existing hash state when hashing your types.
32 //
33 // Unlike `std::hash` or other hashing frameworks, the Abseil hashing framework
34 // provides most of its utility by abstracting away the hash algorithm (and its
35 // implementation) entirely. Instead, a type invokes the Abseil hashing
36 // framework by simply combining its state with the state of known, hashable
37 // types. Hashing of that combined state is separately done by `absl::Hash`.
38 //
39 // One should assume that a hash algorithm is chosen randomly at the start of
40 // each process.  E.g., `absl::Hash<int>{}(9)` in one process and
41 // `absl::Hash<int>{}(9)` in another process are likely to differ.
42 //
43 // `absl::Hash` may also produce different values from different dynamically
44 // loaded libraries. For this reason, `absl::Hash` values must never cross
45 // boundries in dynamically loaded libraries (including when used in types like
46 // hash containers.)
47 //
48 // `absl::Hash` is intended to strongly mix input bits with a target of passing
49 // an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect).
50 //
51 // Example:
52 //
53 //   // Suppose we have a class `Circle` for which we want to add hashing:
54 //   class Circle {
55 //    public:
56 //     ...
57 //    private:
58 //     std::pair<int, int> center_;
59 //     int radius_;
60 //   };
61 //
62 //   // To add hashing support to `Circle`, we simply need to add a free
63 //   // (non-member) function `AbslHashValue()`, and return the combined hash
64 //   // state of the existing hash state and the class state. You can add such a
65 //   // free function using a friend declaration within the body of the class:
66 //   class Circle {
67 //    public:
68 //     ...
69 //     template <typename H>
70 //     friend H AbslHashValue(H h, const Circle& c) {
71 //       return H::combine(std::move(h), c.center_, c.radius_);
72 //     }
73 //     ...
74 //   };
75 //
76 // For more information, see Adding Type Support to `absl::Hash` below.
77 //
78 #ifndef ABSL_HASH_HASH_H_
79 #define ABSL_HASH_HASH_H_
80 
81 #include <tuple>
82 #include <utility>
83 
84 #include "absl/functional/function_ref.h"
85 #include "absl/hash/internal/hash.h"
86 
87 namespace absl {
88 ABSL_NAMESPACE_BEGIN
89 
90 // -----------------------------------------------------------------------------
91 // `absl::Hash`
92 // -----------------------------------------------------------------------------
93 //
94 // `absl::Hash<T>` is a convenient general-purpose hash functor for any type `T`
95 // satisfying any of the following conditions (in order):
96 //
97 //  * T is an arithmetic or pointer type
98 //  * T defines an overload for `AbslHashValue(H, const T&)` for an arbitrary
99 //    hash state `H`.
100 //  - T defines a specialization of `std::hash<T>`
101 //
102 // `absl::Hash` intrinsically supports the following types:
103 //
104 //   * All integral types (including bool)
105 //   * All enum types
106 //   * All floating-point types (although hashing them is discouraged)
107 //   * All pointer types, including nullptr_t
108 //   * std::pair<T1, T2>, if T1 and T2 are hashable
109 //   * std::tuple<Ts...>, if all the Ts... are hashable
110 //   * std::unique_ptr and std::shared_ptr
111 //   * All string-like types including:
112 //     * absl::Cord
113 //     * std::string
114 //     * std::string_view (as well as any instance of std::basic_string that
115 //       uses char and std::char_traits)
116 //  * All the standard sequence containers (provided the elements are hashable)
117 //  * All the standard associative containers (provided the elements are
118 //    hashable)
119 //  * absl types such as the following:
120 //    * absl::string_view
121 //    * absl::uint128
122 //    * absl::Time, absl::Duration, and absl::TimeZone
123 //  * absl containers (provided the elements are hashable) such as the
124 //    following:
125 //    * absl::flat_hash_set, absl::node_hash_set, absl::btree_set
126 //    * absl::flat_hash_map, absl::node_hash_map, absl::btree_map
127 //    * absl::btree_multiset, absl::btree_multimap
128 //    * absl::InlinedVector
129 //    * absl::FixedArray
130 //
131 // When absl::Hash is used to hash an unordered container with a custom hash
132 // functor, the elements are hashed using default absl::Hash semantics, not
133 // the custom hash functor.  This is consistent with the behavior of
134 // operator==() on unordered containers, which compares elements pairwise with
135 // operator==() rather than the custom equality functor.  It is usually a
136 // mistake to use either operator==() or absl::Hash on unordered collections
137 // that use functors incompatible with operator==() equality.
138 //
139 // Note: the list above is not meant to be exhaustive. Additional type support
140 // may be added, in which case the above list will be updated.
141 //
142 // -----------------------------------------------------------------------------
143 // absl::Hash Invocation Evaluation
144 // -----------------------------------------------------------------------------
145 //
146 // When invoked, `absl::Hash<T>` searches for supplied hash functions in the
147 // following order:
148 //
149 //   * Natively supported types out of the box (see above)
150 //   * Types for which an `AbslHashValue()` overload is provided (such as
151 //     user-defined types). See "Adding Type Support to `absl::Hash`" below.
152 //   * Types which define a `std::hash<T>` specialization
153 //
154 // The fallback to legacy hash functions exists mainly for backwards
155 // compatibility. If you have a choice, prefer defining an `AbslHashValue`
156 // overload instead of specializing any legacy hash functors.
157 //
158 // -----------------------------------------------------------------------------
159 // The Hash State Concept, and using `HashState` for Type Erasure
160 // -----------------------------------------------------------------------------
161 //
162 // The `absl::Hash` framework relies on the Concept of a "hash state." Such a
163 // hash state is used in several places:
164 //
165 // * Within existing implementations of `absl::Hash<T>` to store the hashed
166 //   state of an object. Note that it is up to the implementation how it stores
167 //   such state. A hash table, for example, may mix the state to produce an
168 //   integer value; a testing framework may simply hold a vector of that state.
169 // * Within implementations of `AbslHashValue()` used to extend user-defined
170 //   types. (See "Adding Type Support to absl::Hash" below.)
171 // * Inside a `HashState`, providing type erasure for the concept of a hash
172 //   state, which you can use to extend the `absl::Hash` framework for types
173 //   that are otherwise difficult to extend using `AbslHashValue()`. (See the
174 //   `HashState` class below.)
175 //
176 // The "hash state" concept contains three member functions for mixing hash
177 // state:
178 //
179 // * `H::combine(state, values...)`
180 //
181 //   Combines an arbitrary number of values into a hash state, returning the
182 //   updated state. Note that the existing hash state is move-only and must be
183 //   passed by value.
184 //
185 //   Each of the value types T must be hashable by H.
186 //
187 //   NOTE:
188 //
189 //     state = H::combine(std::move(state), value1, value2, value3);
190 //
191 //   must be guaranteed to produce the same hash expansion as
192 //
193 //     state = H::combine(std::move(state), value1);
194 //     state = H::combine(std::move(state), value2);
195 //     state = H::combine(std::move(state), value3);
196 //
197 // * `H::combine_contiguous(state, data, size)`
198 //
199 //    Combines a contiguous array of `size` elements into a hash state,
200 //    returning the updated state. Note that the existing hash state is
201 //    move-only and must be passed by value.
202 //
203 //    NOTE:
204 //
205 //      state = H::combine_contiguous(std::move(state), data, size);
206 //
207 //    need NOT be guaranteed to produce the same hash expansion as a loop
208 //    (it may perform internal optimizations). If you need this guarantee, use a
209 //    loop instead.
210 //
211 // * `H::combine_unordered(state, begin, end)`
212 //
213 //    Combines a set of elements denoted by an iterator pair into a hash
214 //    state, returning the updated state.  Note that the existing hash
215 //    state is move-only and must be passed by value.
216 //
217 //    Unlike the other two methods, the hashing is order-independent.
218 //    This can be used to hash unordered collections.
219 //
220 // -----------------------------------------------------------------------------
221 // Adding Type Support to `absl::Hash`
222 // -----------------------------------------------------------------------------
223 //
224 // To add support for your user-defined type, add a proper `AbslHashValue()`
225 // overload as a free (non-member) function. The overload will take an
226 // existing hash state and should combine that state with state from the type.
227 //
228 // Example:
229 //
230 //   template <typename H>
231 //   H AbslHashValue(H state, const MyType& v) {
232 //     return H::combine(std::move(state), v.field1, ..., v.fieldN);
233 //   }
234 //
235 // where `(field1, ..., fieldN)` are the members you would use on your
236 // `operator==` to define equality.
237 //
238 // Notice that `AbslHashValue` is not a class member, but an ordinary function.
239 // An `AbslHashValue` overload for a type should only be declared in the same
240 // file and namespace as said type. The proper `AbslHashValue` implementation
241 // for a given type will be discovered via ADL.
242 //
243 // Note: unlike `std::hash', `absl::Hash` should never be specialized. It must
244 // only be extended by adding `AbslHashValue()` overloads.
245 //
246 template <typename T>
247 using Hash = absl::hash_internal::Hash<T>;
248 
249 // HashOf
250 //
251 // absl::HashOf() is a helper that generates a hash from the values of its
252 // arguments.  It dispatches to absl::Hash directly, as follows:
253 //  * HashOf(t) == absl::Hash<T>{}(t)
254 //  * HashOf(a, b, c) == HashOf(std::make_tuple(a, b, c))
255 //
256 // HashOf(a1, a2, ...) == HashOf(b1, b2, ...) is guaranteed when
257 //  * The argument lists have pairwise identical C++ types
258 //  * a1 == b1 && a2 == b2 && ...
259 //
260 // The requirement that the arguments match in both type and value is critical.
261 // It means that `a == b` does not necessarily imply `HashOf(a) == HashOf(b)` if
262 // `a` and `b` have different types. For example, `HashOf(2) != HashOf(2.0)`.
263 template <int&... ExplicitArgumentBarrier, typename... Types>
HashOf(const Types &...values)264 size_t HashOf(const Types&... values) {
265   auto tuple = std::tie(values...);
266   return absl::Hash<decltype(tuple)>{}(tuple);
267 }
268 
269 // HashState
270 //
271 // A type erased version of the hash state concept, for use in user-defined
272 // `AbslHashValue` implementations that can't use templates (such as PImpl
273 // classes, virtual functions, etc.). The type erasure adds overhead so it
274 // should be avoided unless necessary.
275 //
276 // Note: This wrapper will only erase calls to
277 //     combine_contiguous(H, const unsigned char*, size_t)
278 //     RunCombineUnordered(H, CombinerF)
279 //
280 // All other calls will be handled internally and will not invoke overloads
281 // provided by the wrapped class.
282 //
283 // Users of this class should still define a template `AbslHashValue` function,
284 // but can use `absl::HashState::Create(&state)` to erase the type of the hash
285 // state and dispatch to their private hashing logic.
286 //
287 // This state can be used like any other hash state. In particular, you can call
288 // `HashState::combine()` and `HashState::combine_contiguous()` on it.
289 //
290 // Example:
291 //
292 //   class Interface {
293 //    public:
294 //     template <typename H>
295 //     friend H AbslHashValue(H state, const Interface& value) {
296 //       state = H::combine(std::move(state), std::type_index(typeid(*this)));
297 //       value.HashValue(absl::HashState::Create(&state));
298 //       return state;
299 //     }
300 //    private:
301 //     virtual void HashValue(absl::HashState state) const = 0;
302 //   };
303 //
304 //   class Impl : Interface {
305 //    private:
306 //     void HashValue(absl::HashState state) const override {
307 //       absl::HashState::combine(std::move(state), v1_, v2_);
308 //     }
309 //     int v1_;
310 //     std::string v2_;
311 //   };
312 class HashState : public hash_internal::HashStateBase<HashState> {
313  public:
314   // HashState::Create()
315   //
316   // Create a new `HashState` instance that wraps `state`. All calls to
317   // `combine()` and `combine_contiguous()` on the new instance will be
318   // redirected to the original `state` object. The `state` object must outlive
319   // the `HashState` instance.
320   template <typename T>
Create(T * state)321   static HashState Create(T* state) {
322     HashState s;
323     s.Init(state);
324     return s;
325   }
326 
327   HashState(const HashState&) = delete;
328   HashState& operator=(const HashState&) = delete;
329   HashState(HashState&&) = default;
330   HashState& operator=(HashState&&) = default;
331 
332   // HashState::combine()
333   //
334   // Combines an arbitrary number of values into a hash state, returning the
335   // updated state.
336   using HashState::HashStateBase::combine;
337 
338   // HashState::combine_contiguous()
339   //
340   // Combines a contiguous array of `size` elements into a hash state, returning
341   // the updated state.
combine_contiguous(HashState hash_state,const unsigned char * first,size_t size)342   static HashState combine_contiguous(HashState hash_state,
343                                       const unsigned char* first, size_t size) {
344     hash_state.combine_contiguous_(hash_state.state_, first, size);
345     return hash_state;
346   }
347   using HashState::HashStateBase::combine_contiguous;
348 
349  private:
350   HashState() = default;
351 
352   friend class HashState::HashStateBase;
353 
354   template <typename T>
CombineContiguousImpl(void * p,const unsigned char * first,size_t size)355   static void CombineContiguousImpl(void* p, const unsigned char* first,
356                                     size_t size) {
357     T& state = *static_cast<T*>(p);
358     state = T::combine_contiguous(std::move(state), first, size);
359   }
360 
361   template <typename T>
Init(T * state)362   void Init(T* state) {
363     state_ = state;
364     combine_contiguous_ = &CombineContiguousImpl<T>;
365     run_combine_unordered_ = &RunCombineUnorderedImpl<T>;
366   }
367 
368   template <typename HS>
369   struct CombineUnorderedInvoker {
370     template <typename T, typename ConsumerT>
operatorCombineUnorderedInvoker371     void operator()(T inner_state, ConsumerT inner_cb) {
372       f(HashState::Create(&inner_state),
373         [&](HashState& inner_erased) { inner_cb(inner_erased.Real<T>()); });
374     }
375 
376     absl::FunctionRef<void(HS, absl::FunctionRef<void(HS&)>)> f;
377   };
378 
379   template <typename T>
RunCombineUnorderedImpl(HashState state,absl::FunctionRef<void (HashState,absl::FunctionRef<void (HashState &)>)> f)380   static HashState RunCombineUnorderedImpl(
381       HashState state,
382       absl::FunctionRef<void(HashState, absl::FunctionRef<void(HashState&)>)>
383           f) {
384     // Note that this implementation assumes that inner_state and outer_state
385     // are the same type.  This isn't true in the SpyHash case, but SpyHash
386     // types are move-convertible to each other, so this still works.
387     T& real_state = state.Real<T>();
388     real_state = T::RunCombineUnordered(
389         std::move(real_state), CombineUnorderedInvoker<HashState>{f});
390     return state;
391   }
392 
393   template <typename CombinerT>
RunCombineUnordered(HashState state,CombinerT combiner)394   static HashState RunCombineUnordered(HashState state, CombinerT combiner) {
395     auto* run = state.run_combine_unordered_;
396     return run(std::move(state), std::ref(combiner));
397   }
398 
399   // Do not erase an already erased state.
Init(HashState * state)400   void Init(HashState* state) {
401     state_ = state->state_;
402     combine_contiguous_ = state->combine_contiguous_;
403     run_combine_unordered_ = state->run_combine_unordered_;
404   }
405 
406   template <typename T>
Real()407   T& Real() {
408     return *static_cast<T*>(state_);
409   }
410 
411   void* state_;
412   void (*combine_contiguous_)(void*, const unsigned char*, size_t);
413   HashState (*run_combine_unordered_)(
414       HashState state,
415       absl::FunctionRef<void(HashState, absl::FunctionRef<void(HashState&)>)>);
416 };
417 
418 ABSL_NAMESPACE_END
419 }  // namespace absl
420 
421 #endif  // ABSL_HASH_HASH_H_
422