|
||||
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_
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |