Coverage Report

Created: 2025-07-11 06:37

/src/abseil-cpp/absl/hash/hash.h
Line
Count
Source (jump to first uncovered line)
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
// boundaries 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 <cstddef>
82
#include <cstdint>
83
#include <tuple>
84
#include <type_traits>
85
#include <utility>
86
87
#include "absl/base/config.h"
88
#include "absl/functional/function_ref.h"
89
#include "absl/hash/internal/hash.h"
90
#include "absl/hash/internal/weakly_mixed_integer.h"
91
#include "absl/meta/type_traits.h"
92
93
namespace absl {
94
ABSL_NAMESPACE_BEGIN
95
96
// -----------------------------------------------------------------------------
97
// `absl::Hash`
98
// -----------------------------------------------------------------------------
99
//
100
// `absl::Hash<T>` is a convenient general-purpose hash functor for any type `T`
101
// satisfying any of the following conditions (in order):
102
//
103
//  * T is an arithmetic or pointer type
104
//  * T defines an overload for `AbslHashValue(H, const T&)` for an arbitrary
105
//    hash state `H`.
106
//  - T defines a specialization of `std::hash<T>`
107
//
108
// `absl::Hash` intrinsically supports the following types:
109
//
110
//   * All integral types (including bool)
111
//   * All enum types
112
//   * All floating-point types (although hashing them is discouraged)
113
//   * All pointer types, including nullptr_t
114
//   * std::pair<T1, T2>, if T1 and T2 are hashable
115
//   * std::tuple<Ts...>, if all the Ts... are hashable
116
//   * std::unique_ptr and std::shared_ptr
117
//   * All string-like types including:
118
//     * absl::Cord
119
//     * std::string (as well as any instance of std::basic_string that
120
//       uses one of {char, wchar_t, char16_t, char32_t} and its associated
121
//       std::char_traits)
122
//     * std::string_view (as well as any instance of std::basic_string_view
123
//       that uses one of {char, wchar_t, char16_t, char32_t} and its associated
124
//       std::char_traits)
125
//  * All the standard sequence containers (provided the elements are hashable)
126
//  * All the standard associative containers (provided the elements are
127
//    hashable)
128
//  * absl types such as the following:
129
//    * absl::string_view
130
//    * absl::uint128
131
//    * absl::Time, absl::Duration, and absl::TimeZone
132
//  * absl containers (provided the elements are hashable) such as the
133
//    following:
134
//    * absl::flat_hash_set, absl::node_hash_set, absl::btree_set
135
//    * absl::flat_hash_map, absl::node_hash_map, absl::btree_map
136
//    * absl::btree_multiset, absl::btree_multimap
137
//    * absl::InlinedVector
138
//    * absl::FixedArray
139
//
140
// When absl::Hash is used to hash an unordered container with a custom hash
141
// functor, the elements are hashed using default absl::Hash semantics, not
142
// the custom hash functor.  This is consistent with the behavior of
143
// operator==() on unordered containers, which compares elements pairwise with
144
// operator==() rather than the custom equality functor.  It is usually a
145
// mistake to use either operator==() or absl::Hash on unordered collections
146
// that use functors incompatible with operator==() equality.
147
//
148
// Note: the list above is not meant to be exhaustive. Additional type support
149
// may be added, in which case the above list will be updated.
150
//
151
// -----------------------------------------------------------------------------
152
// absl::Hash Invocation Evaluation
153
// -----------------------------------------------------------------------------
154
//
155
// When invoked, `absl::Hash<T>` searches for supplied hash functions in the
156
// following order:
157
//
158
//   * Natively supported types out of the box (see above)
159
//   * Types for which an `AbslHashValue()` overload is provided (such as
160
//     user-defined types). See "Adding Type Support to `absl::Hash`" below.
161
//   * Types which define a `std::hash<T>` specialization
162
//
163
// The fallback to legacy hash functions exists mainly for backwards
164
// compatibility. If you have a choice, prefer defining an `AbslHashValue`
165
// overload instead of specializing any legacy hash functors.
166
//
167
// -----------------------------------------------------------------------------
168
// The Hash State Concept, and using `HashState` for Type Erasure
169
// -----------------------------------------------------------------------------
170
//
171
// The `absl::Hash` framework relies on the Concept of a "hash state." Such a
172
// hash state is used in several places:
173
//
174
// * Within existing implementations of `absl::Hash<T>` to store the hashed
175
//   state of an object. Note that it is up to the implementation how it stores
176
//   such state. A hash table, for example, may mix the state to produce an
177
//   integer value; a testing framework may simply hold a vector of that state.
178
// * Within implementations of `AbslHashValue()` used to extend user-defined
179
//   types. (See "Adding Type Support to absl::Hash" below.)
180
// * Inside a `HashState`, providing type erasure for the concept of a hash
181
//   state, which you can use to extend the `absl::Hash` framework for types
182
//   that are otherwise difficult to extend using `AbslHashValue()`. (See the
183
//   `HashState` class below.)
184
//
185
// The "hash state" concept contains three member functions for mixing hash
186
// state:
187
//
188
// * `H::combine(state, values...)`
189
//
190
//   Combines an arbitrary number of values into a hash state, returning the
191
//   updated state. Note that the existing hash state is move-only and must be
192
//   passed by value.
193
//
194
//   Each of the value types T must be hashable by H.
195
//
196
//   NOTE:
197
//
198
//     state = H::combine(std::move(state), value1, value2, value3);
199
//
200
//   must be guaranteed to produce the same hash expansion as
201
//
202
//     state = H::combine(std::move(state), value1);
203
//     state = H::combine(std::move(state), value2);
204
//     state = H::combine(std::move(state), value3);
205
//
206
// * `H::combine_contiguous(state, data, size)`
207
//
208
//    Combines a contiguous array of `size` elements into a hash state,
209
//    returning the updated state. Note that the existing hash state is
210
//    move-only and must be passed by value.
211
//
212
//    NOTE:
213
//
214
//      state = H::combine_contiguous(std::move(state), data, size);
215
//
216
//    need NOT be guaranteed to produce the same hash expansion as a loop
217
//    (it may perform internal optimizations). If you need this guarantee, use a
218
//    loop instead.
219
//
220
// * `H::combine_unordered(state, begin, end)`
221
//
222
//    Combines a set of elements denoted by an iterator pair into a hash
223
//    state, returning the updated state.  Note that the existing hash
224
//    state is move-only and must be passed by value.
225
//
226
//    Unlike the other two methods, the hashing is order-independent.
227
//    This can be used to hash unordered collections.
228
//
229
// -----------------------------------------------------------------------------
230
// Adding Type Support to `absl::Hash`
231
// -----------------------------------------------------------------------------
232
//
233
// To add support for your user-defined type, add a proper `AbslHashValue()`
234
// overload as a free (non-member) function. The overload will take an
235
// existing hash state and should combine that state with state from the type.
236
//
237
// Example:
238
//
239
//   template <typename H>
240
//   H AbslHashValue(H state, const MyType& v) {
241
//     return H::combine(std::move(state), v.field1, ..., v.fieldN);
242
//   }
243
//
244
// where `(field1, ..., fieldN)` are the members you would use on your
245
// `operator==` to define equality.
246
//
247
// Notice that `AbslHashValue` is not a class member, but an ordinary function.
248
// An `AbslHashValue` overload for a type should only be declared in the same
249
// file and namespace as said type. The proper `AbslHashValue` implementation
250
// for a given type will be discovered via ADL.
251
//
252
// Note: unlike `std::hash', `absl::Hash` should never be specialized. It must
253
// only be extended by adding `AbslHashValue()` overloads.
254
//
255
template <typename T>
256
using Hash = absl::hash_internal::Hash<T>;
257
258
// HashOf
259
//
260
// absl::HashOf() is a helper that generates a hash from the values of its
261
// arguments.  It dispatches to absl::Hash directly, as follows:
262
//  * HashOf(t) == absl::Hash<T>{}(t)
263
//  * HashOf(a, b, c) == HashOf(std::make_tuple(a, b, c))
264
//
265
// HashOf(a1, a2, ...) == HashOf(b1, b2, ...) is guaranteed when
266
//  * The argument lists have pairwise identical C++ types
267
//  * a1 == b1 && a2 == b2 && ...
268
//
269
// The requirement that the arguments match in both type and value is critical.
270
// It means that `a == b` does not necessarily imply `HashOf(a) == HashOf(b)` if
271
// `a` and `b` have different types. For example, `HashOf(2) != HashOf(2.0)`.
272
template <int&... ExplicitArgumentBarrier, typename... Types>
273
0
size_t HashOf(const Types&... values) {
274
0
  auto tuple = std::tie(values...);
275
0
  return absl::Hash<decltype(tuple)>{}(tuple);
276
0
}
Unexecuted instantiation: _ZN4absl6HashOfITpTnRiJEJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEiEEEmDpRKT0_
Unexecuted instantiation: _ZN4absl6HashOfITpTnRiJEJmEEEmDpRKT0_
277
278
// HashState
279
//
280
// A type erased version of the hash state concept, for use in user-defined
281
// `AbslHashValue` implementations that can't use templates (such as PImpl
282
// classes, virtual functions, etc.). The type erasure adds overhead so it
283
// should be avoided unless necessary.
284
//
285
// Note: This wrapper will only erase calls to
286
//     combine_contiguous(H, const unsigned char*, size_t)
287
//     RunCombineUnordered(H, CombinerF)
288
//
289
// All other calls will be handled internally and will not invoke overloads
290
// provided by the wrapped class.
291
//
292
// Users of this class should still define a template `AbslHashValue` function,
293
// but can use `absl::HashState::Create(&state)` to erase the type of the hash
294
// state and dispatch to their private hashing logic.
295
//
296
// This state can be used like any other hash state. In particular, you can call
297
// `HashState::combine()` and `HashState::combine_contiguous()` on it.
298
//
299
// Example:
300
//
301
//   class Interface {
302
//    public:
303
//     template <typename H>
304
//     friend H AbslHashValue(H state, const Interface& value) {
305
//       state = H::combine(std::move(state), std::type_index(typeid(*this)));
306
//       value.HashValue(absl::HashState::Create(&state));
307
//       return state;
308
//     }
309
//    private:
310
//     virtual void HashValue(absl::HashState state) const = 0;
311
//   };
312
//
313
//   class Impl : Interface {
314
//    private:
315
//     void HashValue(absl::HashState state) const override {
316
//       absl::HashState::combine(std::move(state), v1_, v2_);
317
//     }
318
//     int v1_;
319
//     std::string v2_;
320
//   };
321
class HashState : public hash_internal::HashStateBase<HashState> {
322
 public:
323
  // HashState::Create()
324
  //
325
  // Create a new `HashState` instance that wraps `state`. All calls to
326
  // `combine()` and `combine_contiguous()` on the new instance will be
327
  // redirected to the original `state` object. The `state` object must outlive
328
  // the `HashState` instance. `T` must be a subclass of `HashStateBase<T>` -
329
  // users should not define their own HashState types.
330
  template <
331
      typename T,
332
      absl::enable_if_t<
333
          std::is_base_of<hash_internal::HashStateBase<T>, T>::value, int> = 0>
334
  static HashState Create(T* state) {
335
    HashState s;
336
    s.Init(state);
337
    return s;
338
  }
339
340
  HashState(const HashState&) = delete;
341
  HashState& operator=(const HashState&) = delete;
342
  HashState(HashState&&) = default;
343
  HashState& operator=(HashState&&) = default;
344
345
  // HashState::combine()
346
  //
347
  // Combines an arbitrary number of values into a hash state, returning the
348
  // updated state.
349
  using HashState::HashStateBase::combine;
350
351
  // HashState::combine_contiguous()
352
  //
353
  // Combines a contiguous array of `size` elements into a hash state, returning
354
  // the updated state.
355
  static HashState combine_contiguous(HashState hash_state,
356
0
                                      const unsigned char* first, size_t size) {
357
0
    hash_state.combine_contiguous_(hash_state.state_, first, size);
358
0
    return hash_state;
359
0
  }
360
361
  static HashState combine_weakly_mixed_integer(
362
0
      HashState hash_state, hash_internal::WeaklyMixedInteger value) {
363
0
    hash_state.combine_weakly_mixed_integer_(hash_state.state_, value);
364
0
    return hash_state;
365
0
  }
366
  using HashState::HashStateBase::combine_contiguous;
367
368
 private:
369
  HashState() = default;
370
371
  friend class HashState::HashStateBase;
372
  friend struct hash_internal::CombineRaw;
373
374
  template <typename T>
375
  static void CombineContiguousImpl(void* p, const unsigned char* first,
376
                                    size_t size) {
377
    T& state = *static_cast<T*>(p);
378
    state = T::combine_contiguous(std::move(state), first, size);
379
  }
380
381
  template <typename T>
382
  static void CombineWeaklyMixedIntegerImpl(
383
      void* p, hash_internal::WeaklyMixedInteger value) {
384
    T& state = *static_cast<T*>(p);
385
    state = T::combine_weakly_mixed_integer(std::move(state), value);
386
  }
387
388
0
  static HashState combine_raw(HashState hash_state, uint64_t value) {
389
0
    hash_state.combine_raw_(hash_state.state_, value);
390
0
    return hash_state;
391
0
  }
392
393
  template <typename T>
394
  static void CombineRawImpl(void* p, uint64_t value) {
395
    T& state = *static_cast<T*>(p);
396
    state = hash_internal::CombineRaw()(std::move(state), value);
397
  }
398
399
  template <typename T>
400
  void Init(T* state) {
401
    state_ = state;
402
    combine_weakly_mixed_integer_ = &CombineWeaklyMixedIntegerImpl<T>;
403
    combine_contiguous_ = &CombineContiguousImpl<T>;
404
    combine_raw_ = &CombineRawImpl<T>;
405
    run_combine_unordered_ = &RunCombineUnorderedImpl<T>;
406
  }
407
408
  template <typename HS>
409
  struct CombineUnorderedInvoker {
410
    template <typename T, typename ConsumerT>
411
    void operator()(T inner_state, ConsumerT inner_cb) {
412
      f(HashState::Create(&inner_state),
413
        [&](HashState& inner_erased) { inner_cb(inner_erased.Real<T>()); });
414
    }
415
416
    absl::FunctionRef<void(HS, absl::FunctionRef<void(HS&)>)> f;
417
  };
418
419
  template <typename T>
420
  static HashState RunCombineUnorderedImpl(
421
      HashState state,
422
      absl::FunctionRef<void(HashState, absl::FunctionRef<void(HashState&)>)>
423
          f) {
424
    // Note that this implementation assumes that inner_state and outer_state
425
    // are the same type.  This isn't true in the SpyHash case, but SpyHash
426
    // types are move-convertible to each other, so this still works.
427
    T& real_state = state.Real<T>();
428
    real_state = T::RunCombineUnordered(
429
        std::move(real_state), CombineUnorderedInvoker<HashState>{f});
430
    return state;
431
  }
432
433
  template <typename CombinerT>
434
  static HashState RunCombineUnordered(HashState state, CombinerT combiner) {
435
    auto* run = state.run_combine_unordered_;
436
    return run(std::move(state), std::ref(combiner));
437
  }
438
439
  // Do not erase an already erased state.
440
0
  void Init(HashState* state) {
441
0
    state_ = state->state_;
442
0
    combine_weakly_mixed_integer_ = state->combine_weakly_mixed_integer_;
443
0
    combine_contiguous_ = state->combine_contiguous_;
444
0
    combine_raw_ = state->combine_raw_;
445
0
    run_combine_unordered_ = state->run_combine_unordered_;
446
0
  }
447
448
  template <typename T>
449
  T& Real() {
450
    return *static_cast<T*>(state_);
451
  }
452
453
  void* state_;
454
  void (*combine_weakly_mixed_integer_)(
455
      void*, absl::hash_internal::WeaklyMixedInteger);
456
  void (*combine_contiguous_)(void*, const unsigned char*, size_t);
457
  void (*combine_raw_)(void*, uint64_t);
458
  HashState (*run_combine_unordered_)(
459
      HashState state,
460
      absl::FunctionRef<void(HashState, absl::FunctionRef<void(HashState&)>)>);
461
};
462
463
ABSL_NAMESPACE_END
464
}  // namespace absl
465
466
#endif  // ABSL_HASH_HASH_H_