Coverage Report

Created: 2026-09-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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_