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()` and 30 // `combine_contiguous()`, which you can use to contribute to an existing 31 // 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` is intended to strongly mix input bits with a target of passing 44 // an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect). 45 // 46 // Example: 47 // 48 // // Suppose we have a class `Circle` for which we want to add hashing: 49 // class Circle { 50 // public: 51 // ... 52 // private: 53 // std::pair<int, int> center_; 54 // int radius_; 55 // }; 56 // 57 // // To add hashing support to `Circle`, we simply need to add a free 58 // // (non-member) function `AbslHashValue()`, and return the combined hash 59 // // state of the existing hash state and the class state. You can add such a 60 // // free function using a friend declaration within the body of the class: 61 // class Circle { 62 // public: 63 // ... 64 // template <typename H> 65 // friend H AbslHashValue(H h, const Circle& c) { 66 // return H::combine(std::move(h), c.center_, c.radius_); 67 // } 68 // ... 69 // }; 70 // 71 // For more information, see Adding Type Support to `absl::Hash` below. 72 // 73 #ifndef ABSL_HASH_HASH_H_ 74 #define ABSL_HASH_HASH_H_ 75 76 #include "absl/hash/internal/hash.h" 77 78 namespace absl { 79 ABSL_NAMESPACE_BEGIN 80 81 // ----------------------------------------------------------------------------- 82 // `absl::Hash` 83 // ----------------------------------------------------------------------------- 84 // 85 // `absl::Hash<T>` is a convenient general-purpose hash functor for any type `T` 86 // satisfying any of the following conditions (in order): 87 // 88 // * T is an arithmetic or pointer type 89 // * T defines an overload for `AbslHashValue(H, const T&)` for an arbitrary 90 // hash state `H`. 91 // - T defines a specialization of `std::hash<T>` 92 // 93 // `absl::Hash` intrinsically supports the following types: 94 // 95 // * All integral types (including bool) 96 // * All enum types 97 // * All floating-point types (although hashing them is discouraged) 98 // * All pointer types, including nullptr_t 99 // * std::pair<T1, T2>, if T1 and T2 are hashable 100 // * std::tuple<Ts...>, if all the Ts... are hashable 101 // * std::unique_ptr and std::shared_ptr 102 // * All string-like types including: 103 // * absl::Cord 104 // * std::string 105 // * std::string_view (as well as any instance of std::basic_string that 106 // uses char and std::char_traits) 107 // * All the standard sequence containers (provided the elements are hashable) 108 // * All the standard ordered associative containers (provided the elements are 109 // hashable) 110 // * absl types such as the following: 111 // * absl::string_view 112 // * absl::InlinedVector 113 // * absl::FixedArray 114 // * absl::uint128 115 // * absl::Time, absl::Duration, and absl::TimeZone 116 // 117 // Note: the list above is not meant to be exhaustive. Additional type support 118 // may be added, in which case the above list will be updated. 119 // 120 // ----------------------------------------------------------------------------- 121 // absl::Hash Invocation Evaluation 122 // ----------------------------------------------------------------------------- 123 // 124 // When invoked, `absl::Hash<T>` searches for supplied hash functions in the 125 // following order: 126 // 127 // * Natively supported types out of the box (see above) 128 // * Types for which an `AbslHashValue()` overload is provided (such as 129 // user-defined types). See "Adding Type Support to `absl::Hash`" below. 130 // * Types which define a `std::hash<T>` specialization 131 // 132 // The fallback to legacy hash functions exists mainly for backwards 133 // compatibility. If you have a choice, prefer defining an `AbslHashValue` 134 // overload instead of specializing any legacy hash functors. 135 // 136 // ----------------------------------------------------------------------------- 137 // The Hash State Concept, and using `HashState` for Type Erasure 138 // ----------------------------------------------------------------------------- 139 // 140 // The `absl::Hash` framework relies on the Concept of a "hash state." Such a 141 // hash state is used in several places: 142 // 143 // * Within existing implementations of `absl::Hash<T>` to store the hashed 144 // state of an object. Note that it is up to the implementation how it stores 145 // such state. A hash table, for example, may mix the state to produce an 146 // integer value; a testing framework may simply hold a vector of that state. 147 // * Within implementations of `AbslHashValue()` used to extend user-defined 148 // types. (See "Adding Type Support to absl::Hash" below.) 149 // * Inside a `HashState`, providing type erasure for the concept of a hash 150 // state, which you can use to extend the `absl::Hash` framework for types 151 // that are otherwise difficult to extend using `AbslHashValue()`. (See the 152 // `HashState` class below.) 153 // 154 // The "hash state" concept contains two member functions for mixing hash state: 155 // 156 // * `H::combine(state, values...)` 157 // 158 // Combines an arbitrary number of values into a hash state, returning the 159 // updated state. Note that the existing hash state is move-only and must be 160 // passed by value. 161 // 162 // Each of the value types T must be hashable by H. 163 // 164 // NOTE: 165 // 166 // state = H::combine(std::move(state), value1, value2, value3); 167 // 168 // must be guaranteed to produce the same hash expansion as 169 // 170 // state = H::combine(std::move(state), value1); 171 // state = H::combine(std::move(state), value2); 172 // state = H::combine(std::move(state), value3); 173 // 174 // * `H::combine_contiguous(state, data, size)` 175 // 176 // Combines a contiguous array of `size` elements into a hash state, 177 // returning the updated state. Note that the existing hash state is 178 // move-only and must be passed by value. 179 // 180 // NOTE: 181 // 182 // state = H::combine_contiguous(std::move(state), data, size); 183 // 184 // need NOT be guaranteed to produce the same hash expansion as a loop 185 // (it may perform internal optimizations). If you need this guarantee, use a 186 // loop instead. 187 // 188 // ----------------------------------------------------------------------------- 189 // Adding Type Support to `absl::Hash` 190 // ----------------------------------------------------------------------------- 191 // 192 // To add support for your user-defined type, add a proper `AbslHashValue()` 193 // overload as a free (non-member) function. The overload will take an 194 // existing hash state and should combine that state with state from the type. 195 // 196 // Example: 197 // 198 // template <typename H> 199 // H AbslHashValue(H state, const MyType& v) { 200 // return H::combine(std::move(state), v.field1, ..., v.fieldN); 201 // } 202 // 203 // where `(field1, ..., fieldN)` are the members you would use on your 204 // `operator==` to define equality. 205 // 206 // Notice that `AbslHashValue` is not a class member, but an ordinary function. 207 // An `AbslHashValue` overload for a type should only be declared in the same 208 // file and namespace as said type. The proper `AbslHashValue` implementation 209 // for a given type will be discovered via ADL. 210 // 211 // Note: unlike `std::hash', `absl::Hash` should never be specialized. It must 212 // only be extended by adding `AbslHashValue()` overloads. 213 // 214 template <typename T> 215 using Hash = absl::hash_internal::Hash<T>; 216 217 // HashState 218 // 219 // A type erased version of the hash state concept, for use in user-defined 220 // `AbslHashValue` implementations that can't use templates (such as PImpl 221 // classes, virtual functions, etc.). The type erasure adds overhead so it 222 // should be avoided unless necessary. 223 // 224 // Note: This wrapper will only erase calls to: 225 // combine_contiguous(H, const unsigned char*, size_t) 226 // 227 // All other calls will be handled internally and will not invoke overloads 228 // provided by the wrapped class. 229 // 230 // Users of this class should still define a template `AbslHashValue` function, 231 // but can use `absl::HashState::Create(&state)` to erase the type of the hash 232 // state and dispatch to their private hashing logic. 233 // 234 // This state can be used like any other hash state. In particular, you can call 235 // `HashState::combine()` and `HashState::combine_contiguous()` on it. 236 // 237 // Example: 238 // 239 // class Interface { 240 // public: 241 // template <typename H> 242 // friend H AbslHashValue(H state, const Interface& value) { 243 // state = H::combine(std::move(state), std::type_index(typeid(*this))); 244 // value.HashValue(absl::HashState::Create(&state)); 245 // return state; 246 // } 247 // private: 248 // virtual void HashValue(absl::HashState state) const = 0; 249 // }; 250 // 251 // class Impl : Interface { 252 // private: 253 // void HashValue(absl::HashState state) const override { 254 // absl::HashState::combine(std::move(state), v1_, v2_); 255 // } 256 // int v1_; 257 // std::string v2_; 258 // }; 259 class HashState : public hash_internal::HashStateBase<HashState> { 260 public: 261 // HashState::Create() 262 // 263 // Create a new `HashState` instance that wraps `state`. All calls to 264 // `combine()` and `combine_contiguous()` on the new instance will be 265 // redirected to the original `state` object. The `state` object must outlive 266 // the `HashState` instance. 267 template <typename T> Create(T * state)268 static HashState Create(T* state) { 269 HashState s; 270 s.Init(state); 271 return s; 272 } 273 274 HashState(const HashState&) = delete; 275 HashState& operator=(const HashState&) = delete; 276 HashState(HashState&&) = default; 277 HashState& operator=(HashState&&) = default; 278 279 // HashState::combine() 280 // 281 // Combines an arbitrary number of values into a hash state, returning the 282 // updated state. 283 using HashState::HashStateBase::combine; 284 285 // HashState::combine_contiguous() 286 // 287 // Combines a contiguous array of `size` elements into a hash state, returning 288 // the updated state. combine_contiguous(HashState hash_state,const unsigned char * first,size_t size)289 static HashState combine_contiguous(HashState hash_state, 290 const unsigned char* first, size_t size) { 291 hash_state.combine_contiguous_(hash_state.state_, first, size); 292 return hash_state; 293 } 294 using HashState::HashStateBase::combine_contiguous; 295 296 private: 297 HashState() = default; 298 299 template <typename T> CombineContiguousImpl(void * p,const unsigned char * first,size_t size)300 static void CombineContiguousImpl(void* p, const unsigned char* first, 301 size_t size) { 302 T& state = *static_cast<T*>(p); 303 state = T::combine_contiguous(std::move(state), first, size); 304 } 305 306 template <typename T> Init(T * state)307 void Init(T* state) { 308 state_ = state; 309 combine_contiguous_ = &CombineContiguousImpl<T>; 310 } 311 312 // Do not erase an already erased state. Init(HashState * state)313 void Init(HashState* state) { 314 state_ = state->state_; 315 combine_contiguous_ = state->combine_contiguous_; 316 } 317 318 void* state_; 319 void (*combine_contiguous_)(void*, const unsigned char*, size_t); 320 }; 321 322 ABSL_NAMESPACE_END 323 } // namespace absl 324 325 #endif // ABSL_HASH_HASH_H_ 326