Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:18

0001 // Copyright 2018 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 //
0015 // -----------------------------------------------------------------------------
0016 // File: hash.h
0017 // -----------------------------------------------------------------------------
0018 //
0019 // This header file defines the Abseil `hash` library and the Abseil hashing
0020 // framework. This framework consists of the following:
0021 //
0022 //   * The `absl::Hash` functor, which is used to invoke the hasher within the
0023 //     Abseil hashing framework. `absl::Hash<T>` supports most basic types and
0024 //     a number of Abseil types out of the box.
0025 //   * `AbslHashValue`, an extension point that allows you to extend types to
0026 //     support Abseil hashing without requiring you to define a hashing
0027 //     algorithm.
0028 //   * `HashState`, a type-erased class which implements the manipulation of the
0029 //     hash state (H) itself; contains member functions `combine()`,
0030 //     `combine_contiguous()`, and `combine_unordered()`; and which you can use
0031 //     to contribute to an existing hash state when hashing your types.
0032 //
0033 // Unlike `std::hash` or other hashing frameworks, the Abseil hashing framework
0034 // provides most of its utility by abstracting away the hash algorithm (and its
0035 // implementation) entirely. Instead, a type invokes the Abseil hashing
0036 // framework by simply combining its state with the state of known, hashable
0037 // types. Hashing of that combined state is separately done by `absl::Hash`.
0038 //
0039 // One should assume that a hash algorithm is chosen randomly at the start of
0040 // each process.  E.g., `absl::Hash<int>{}(9)` in one process and
0041 // `absl::Hash<int>{}(9)` in another process are likely to differ.
0042 //
0043 // `absl::Hash` may also produce different values from different dynamically
0044 // loaded libraries. For this reason, `absl::Hash` values must never cross
0045 // boundaries in dynamically loaded libraries (including when used in types like
0046 // hash containers.)
0047 //
0048 // `absl::Hash` is intended to strongly mix input bits with a target of passing
0049 // an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect).
0050 //
0051 // Example:
0052 //
0053 //   // Suppose we have a class `Circle` for which we want to add hashing:
0054 //   class Circle {
0055 //    public:
0056 //     ...
0057 //    private:
0058 //     std::pair<int, int> center_;
0059 //     int radius_;
0060 //   };
0061 //
0062 //   // To add hashing support to `Circle`, we simply need to add a free
0063 //   // (non-member) function `AbslHashValue()`, and return the combined hash
0064 //   // state of the existing hash state and the class state. You can add such a
0065 //   // free function using a friend declaration within the body of the class:
0066 //   class Circle {
0067 //    public:
0068 //     ...
0069 //     template <typename H>
0070 //     friend H AbslHashValue(H h, const Circle& c) {
0071 //       return H::combine(std::move(h), c.center_, c.radius_);
0072 //     }
0073 //     ...
0074 //   };
0075 //
0076 // For more information, see Adding Type Support to `absl::Hash` below.
0077 //
0078 #ifndef ABSL_HASH_HASH_H_
0079 #define ABSL_HASH_HASH_H_
0080 
0081 #include <tuple>
0082 #include <utility>
0083 
0084 #include "absl/functional/function_ref.h"
0085 #include "absl/hash/internal/hash.h"
0086 
0087 namespace absl {
0088 ABSL_NAMESPACE_BEGIN
0089 
0090 // -----------------------------------------------------------------------------
0091 // `absl::Hash`
0092 // -----------------------------------------------------------------------------
0093 //
0094 // `absl::Hash<T>` is a convenient general-purpose hash functor for any type `T`
0095 // satisfying any of the following conditions (in order):
0096 //
0097 //  * T is an arithmetic or pointer type
0098 //  * T defines an overload for `AbslHashValue(H, const T&)` for an arbitrary
0099 //    hash state `H`.
0100 //  - T defines a specialization of `std::hash<T>`
0101 //
0102 // `absl::Hash` intrinsically supports the following types:
0103 //
0104 //   * All integral types (including bool)
0105 //   * All enum types
0106 //   * All floating-point types (although hashing them is discouraged)
0107 //   * All pointer types, including nullptr_t
0108 //   * std::pair<T1, T2>, if T1 and T2 are hashable
0109 //   * std::tuple<Ts...>, if all the Ts... are hashable
0110 //   * std::unique_ptr and std::shared_ptr
0111 //   * All string-like types including:
0112 //     * absl::Cord
0113 //     * std::string (as well as any instance of std::basic_string that
0114 //       uses one of {char, wchar_t, char16_t, char32_t} and its associated
0115 //       std::char_traits)
0116 //     * std::string_view (as well as any instance of std::basic_string_view
0117 //       that uses one of {char, wchar_t, char16_t, char32_t} and its associated
0118 //       std::char_traits)
0119 //  * All the standard sequence containers (provided the elements are hashable)
0120 //  * All the standard associative containers (provided the elements are
0121 //    hashable)
0122 //  * absl types such as the following:
0123 //    * absl::string_view
0124 //    * absl::uint128
0125 //    * absl::Time, absl::Duration, and absl::TimeZone
0126 //  * absl containers (provided the elements are hashable) such as the
0127 //    following:
0128 //    * absl::flat_hash_set, absl::node_hash_set, absl::btree_set
0129 //    * absl::flat_hash_map, absl::node_hash_map, absl::btree_map
0130 //    * absl::btree_multiset, absl::btree_multimap
0131 //    * absl::InlinedVector
0132 //    * absl::FixedArray
0133 //
0134 // When absl::Hash is used to hash an unordered container with a custom hash
0135 // functor, the elements are hashed using default absl::Hash semantics, not
0136 // the custom hash functor.  This is consistent with the behavior of
0137 // operator==() on unordered containers, which compares elements pairwise with
0138 // operator==() rather than the custom equality functor.  It is usually a
0139 // mistake to use either operator==() or absl::Hash on unordered collections
0140 // that use functors incompatible with operator==() equality.
0141 //
0142 // Note: the list above is not meant to be exhaustive. Additional type support
0143 // may be added, in which case the above list will be updated.
0144 //
0145 // -----------------------------------------------------------------------------
0146 // absl::Hash Invocation Evaluation
0147 // -----------------------------------------------------------------------------
0148 //
0149 // When invoked, `absl::Hash<T>` searches for supplied hash functions in the
0150 // following order:
0151 //
0152 //   * Natively supported types out of the box (see above)
0153 //   * Types for which an `AbslHashValue()` overload is provided (such as
0154 //     user-defined types). See "Adding Type Support to `absl::Hash`" below.
0155 //   * Types which define a `std::hash<T>` specialization
0156 //
0157 // The fallback to legacy hash functions exists mainly for backwards
0158 // compatibility. If you have a choice, prefer defining an `AbslHashValue`
0159 // overload instead of specializing any legacy hash functors.
0160 //
0161 // -----------------------------------------------------------------------------
0162 // The Hash State Concept, and using `HashState` for Type Erasure
0163 // -----------------------------------------------------------------------------
0164 //
0165 // The `absl::Hash` framework relies on the Concept of a "hash state." Such a
0166 // hash state is used in several places:
0167 //
0168 // * Within existing implementations of `absl::Hash<T>` to store the hashed
0169 //   state of an object. Note that it is up to the implementation how it stores
0170 //   such state. A hash table, for example, may mix the state to produce an
0171 //   integer value; a testing framework may simply hold a vector of that state.
0172 // * Within implementations of `AbslHashValue()` used to extend user-defined
0173 //   types. (See "Adding Type Support to absl::Hash" below.)
0174 // * Inside a `HashState`, providing type erasure for the concept of a hash
0175 //   state, which you can use to extend the `absl::Hash` framework for types
0176 //   that are otherwise difficult to extend using `AbslHashValue()`. (See the
0177 //   `HashState` class below.)
0178 //
0179 // The "hash state" concept contains three member functions for mixing hash
0180 // state:
0181 //
0182 // * `H::combine(state, values...)`
0183 //
0184 //   Combines an arbitrary number of values into a hash state, returning the
0185 //   updated state. Note that the existing hash state is move-only and must be
0186 //   passed by value.
0187 //
0188 //   Each of the value types T must be hashable by H.
0189 //
0190 //   NOTE:
0191 //
0192 //     state = H::combine(std::move(state), value1, value2, value3);
0193 //
0194 //   must be guaranteed to produce the same hash expansion as
0195 //
0196 //     state = H::combine(std::move(state), value1);
0197 //     state = H::combine(std::move(state), value2);
0198 //     state = H::combine(std::move(state), value3);
0199 //
0200 // * `H::combine_contiguous(state, data, size)`
0201 //
0202 //    Combines a contiguous array of `size` elements into a hash state,
0203 //    returning the updated state. Note that the existing hash state is
0204 //    move-only and must be passed by value.
0205 //
0206 //    NOTE:
0207 //
0208 //      state = H::combine_contiguous(std::move(state), data, size);
0209 //
0210 //    need NOT be guaranteed to produce the same hash expansion as a loop
0211 //    (it may perform internal optimizations). If you need this guarantee, use a
0212 //    loop instead.
0213 //
0214 // * `H::combine_unordered(state, begin, end)`
0215 //
0216 //    Combines a set of elements denoted by an iterator pair into a hash
0217 //    state, returning the updated state.  Note that the existing hash
0218 //    state is move-only and must be passed by value.
0219 //
0220 //    Unlike the other two methods, the hashing is order-independent.
0221 //    This can be used to hash unordered collections.
0222 //
0223 // -----------------------------------------------------------------------------
0224 // Adding Type Support to `absl::Hash`
0225 // -----------------------------------------------------------------------------
0226 //
0227 // To add support for your user-defined type, add a proper `AbslHashValue()`
0228 // overload as a free (non-member) function. The overload will take an
0229 // existing hash state and should combine that state with state from the type.
0230 //
0231 // Example:
0232 //
0233 //   template <typename H>
0234 //   H AbslHashValue(H state, const MyType& v) {
0235 //     return H::combine(std::move(state), v.field1, ..., v.fieldN);
0236 //   }
0237 //
0238 // where `(field1, ..., fieldN)` are the members you would use on your
0239 // `operator==` to define equality.
0240 //
0241 // Notice that `AbslHashValue` is not a class member, but an ordinary function.
0242 // An `AbslHashValue` overload for a type should only be declared in the same
0243 // file and namespace as said type. The proper `AbslHashValue` implementation
0244 // for a given type will be discovered via ADL.
0245 //
0246 // Note: unlike `std::hash', `absl::Hash` should never be specialized. It must
0247 // only be extended by adding `AbslHashValue()` overloads.
0248 //
0249 template <typename T>
0250 using Hash = absl::hash_internal::Hash<T>;
0251 
0252 // HashOf
0253 //
0254 // absl::HashOf() is a helper that generates a hash from the values of its
0255 // arguments.  It dispatches to absl::Hash directly, as follows:
0256 //  * HashOf(t) == absl::Hash<T>{}(t)
0257 //  * HashOf(a, b, c) == HashOf(std::make_tuple(a, b, c))
0258 //
0259 // HashOf(a1, a2, ...) == HashOf(b1, b2, ...) is guaranteed when
0260 //  * The argument lists have pairwise identical C++ types
0261 //  * a1 == b1 && a2 == b2 && ...
0262 //
0263 // The requirement that the arguments match in both type and value is critical.
0264 // It means that `a == b` does not necessarily imply `HashOf(a) == HashOf(b)` if
0265 // `a` and `b` have different types. For example, `HashOf(2) != HashOf(2.0)`.
0266 template <int&... ExplicitArgumentBarrier, typename... Types>
0267 size_t HashOf(const Types&... values) {
0268   auto tuple = std::tie(values...);
0269   return absl::Hash<decltype(tuple)>{}(tuple);
0270 }
0271 
0272 // HashState
0273 //
0274 // A type erased version of the hash state concept, for use in user-defined
0275 // `AbslHashValue` implementations that can't use templates (such as PImpl
0276 // classes, virtual functions, etc.). The type erasure adds overhead so it
0277 // should be avoided unless necessary.
0278 //
0279 // Note: This wrapper will only erase calls to
0280 //     combine_contiguous(H, const unsigned char*, size_t)
0281 //     RunCombineUnordered(H, CombinerF)
0282 //
0283 // All other calls will be handled internally and will not invoke overloads
0284 // provided by the wrapped class.
0285 //
0286 // Users of this class should still define a template `AbslHashValue` function,
0287 // but can use `absl::HashState::Create(&state)` to erase the type of the hash
0288 // state and dispatch to their private hashing logic.
0289 //
0290 // This state can be used like any other hash state. In particular, you can call
0291 // `HashState::combine()` and `HashState::combine_contiguous()` on it.
0292 //
0293 // Example:
0294 //
0295 //   class Interface {
0296 //    public:
0297 //     template <typename H>
0298 //     friend H AbslHashValue(H state, const Interface& value) {
0299 //       state = H::combine(std::move(state), std::type_index(typeid(*this)));
0300 //       value.HashValue(absl::HashState::Create(&state));
0301 //       return state;
0302 //     }
0303 //    private:
0304 //     virtual void HashValue(absl::HashState state) const = 0;
0305 //   };
0306 //
0307 //   class Impl : Interface {
0308 //    private:
0309 //     void HashValue(absl::HashState state) const override {
0310 //       absl::HashState::combine(std::move(state), v1_, v2_);
0311 //     }
0312 //     int v1_;
0313 //     std::string v2_;
0314 //   };
0315 class HashState : public hash_internal::HashStateBase<HashState> {
0316  public:
0317   // HashState::Create()
0318   //
0319   // Create a new `HashState` instance that wraps `state`. All calls to
0320   // `combine()` and `combine_contiguous()` on the new instance will be
0321   // redirected to the original `state` object. The `state` object must outlive
0322   // the `HashState` instance.
0323   template <typename T>
0324   static HashState Create(T* state) {
0325     HashState s;
0326     s.Init(state);
0327     return s;
0328   }
0329 
0330   HashState(const HashState&) = delete;
0331   HashState& operator=(const HashState&) = delete;
0332   HashState(HashState&&) = default;
0333   HashState& operator=(HashState&&) = default;
0334 
0335   // HashState::combine()
0336   //
0337   // Combines an arbitrary number of values into a hash state, returning the
0338   // updated state.
0339   using HashState::HashStateBase::combine;
0340 
0341   // HashState::combine_contiguous()
0342   //
0343   // Combines a contiguous array of `size` elements into a hash state, returning
0344   // the updated state.
0345   static HashState combine_contiguous(HashState hash_state,
0346                                       const unsigned char* first, size_t size) {
0347     hash_state.combine_contiguous_(hash_state.state_, first, size);
0348     return hash_state;
0349   }
0350   using HashState::HashStateBase::combine_contiguous;
0351 
0352  private:
0353   HashState() = default;
0354 
0355   friend class HashState::HashStateBase;
0356 
0357   template <typename T>
0358   static void CombineContiguousImpl(void* p, const unsigned char* first,
0359                                     size_t size) {
0360     T& state = *static_cast<T*>(p);
0361     state = T::combine_contiguous(std::move(state), first, size);
0362   }
0363 
0364   template <typename T>
0365   void Init(T* state) {
0366     state_ = state;
0367     combine_contiguous_ = &CombineContiguousImpl<T>;
0368     run_combine_unordered_ = &RunCombineUnorderedImpl<T>;
0369   }
0370 
0371   template <typename HS>
0372   struct CombineUnorderedInvoker {
0373     template <typename T, typename ConsumerT>
0374     void operator()(T inner_state, ConsumerT inner_cb) {
0375       f(HashState::Create(&inner_state),
0376         [&](HashState& inner_erased) { inner_cb(inner_erased.Real<T>()); });
0377     }
0378 
0379     absl::FunctionRef<void(HS, absl::FunctionRef<void(HS&)>)> f;
0380   };
0381 
0382   template <typename T>
0383   static HashState RunCombineUnorderedImpl(
0384       HashState state,
0385       absl::FunctionRef<void(HashState, absl::FunctionRef<void(HashState&)>)>
0386           f) {
0387     // Note that this implementation assumes that inner_state and outer_state
0388     // are the same type.  This isn't true in the SpyHash case, but SpyHash
0389     // types are move-convertible to each other, so this still works.
0390     T& real_state = state.Real<T>();
0391     real_state = T::RunCombineUnordered(
0392         std::move(real_state), CombineUnorderedInvoker<HashState>{f});
0393     return state;
0394   }
0395 
0396   template <typename CombinerT>
0397   static HashState RunCombineUnordered(HashState state, CombinerT combiner) {
0398     auto* run = state.run_combine_unordered_;
0399     return run(std::move(state), std::ref(combiner));
0400   }
0401 
0402   // Do not erase an already erased state.
0403   void Init(HashState* state) {
0404     state_ = state->state_;
0405     combine_contiguous_ = state->combine_contiguous_;
0406     run_combine_unordered_ = state->run_combine_unordered_;
0407   }
0408 
0409   template <typename T>
0410   T& Real() {
0411     return *static_cast<T*>(state_);
0412   }
0413 
0414   void* state_;
0415   void (*combine_contiguous_)(void*, const unsigned char*, size_t);
0416   HashState (*run_combine_unordered_)(
0417       HashState state,
0418       absl::FunctionRef<void(HashState, absl::FunctionRef<void(HashState&)>)>);
0419 };
0420 
0421 ABSL_NAMESPACE_END
0422 }  // namespace absl
0423 
0424 #endif  // ABSL_HASH_HASH_H_