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 // Define the default Hash and Eq functions for SwissTable containers. 16 // 17 // std::hash<T> and std::equal_to<T> are not appropriate hash and equal 18 // functions for SwissTable containers. There are two reasons for this. 19 // 20 // SwissTable containers are power of 2 sized containers: 21 // 22 // This means they use the lower bits of the hash value to find the slot for 23 // each entry. The typical hash function for integral types is the identity. 24 // This is a very weak hash function for SwissTable and any power of 2 sized 25 // hashtable implementation which will lead to excessive collisions. For 26 // SwissTable we use murmur3 style mixing to reduce collisions to a minimum. 27 // 28 // SwissTable containers support heterogeneous lookup: 29 // 30 // In order to make heterogeneous lookup work, hash and equal functions must be 31 // polymorphic. At the same time they have to satisfy the same requirements the 32 // C++ standard imposes on hash functions and equality operators. That is: 33 // 34 // if hash_default_eq<T>(a, b) returns true for any a and b of type T, then 35 // hash_default_hash<T>(a) must equal hash_default_hash<T>(b) 36 // 37 // For SwissTable containers this requirement is relaxed to allow a and b of 38 // any and possibly different types. Note that like the standard the hash and 39 // equal functions are still bound to T. This is important because some type U 40 // can be hashed by/tested for equality differently depending on T. A notable 41 // example is `const char*`. `const char*` is treated as a c-style string when 42 // the hash function is hash<std::string> but as a pointer when the hash 43 // function is hash<void*>. 44 // 45 #ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ 46 #define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ 47 48 #include <cstddef> 49 #include <functional> 50 #include <memory> 51 #include <string> 52 #include <type_traits> 53 54 #include "absl/base/config.h" 55 #include "absl/container/internal/common.h" 56 #include "absl/hash/hash.h" 57 #include "absl/meta/type_traits.h" 58 #include "absl/strings/cord.h" 59 #include "absl/strings/string_view.h" 60 61 #ifdef ABSL_HAVE_STD_STRING_VIEW 62 #include <string_view> 63 #endif 64 65 namespace absl { 66 ABSL_NAMESPACE_BEGIN 67 namespace container_internal { 68 69 // The hash of an object of type T is computed by using absl::Hash. 70 template <class T, class E = void> 71 struct HashEq { 72 using Hash = absl::Hash<T>; 73 using Eq = std::equal_to<T>; 74 }; 75 76 struct StringHash { 77 using is_transparent = void; 78 operatorStringHash79 size_t operator()(absl::string_view v) const { 80 return absl::Hash<absl::string_view>{}(v); 81 } operatorStringHash82 size_t operator()(const absl::Cord& v) const { 83 return absl::Hash<absl::Cord>{}(v); 84 } 85 }; 86 87 struct StringEq { 88 using is_transparent = void; operatorStringEq89 bool operator()(absl::string_view lhs, absl::string_view rhs) const { 90 return lhs == rhs; 91 } operatorStringEq92 bool operator()(const absl::Cord& lhs, const absl::Cord& rhs) const { 93 return lhs == rhs; 94 } operatorStringEq95 bool operator()(const absl::Cord& lhs, absl::string_view rhs) const { 96 return lhs == rhs; 97 } operatorStringEq98 bool operator()(absl::string_view lhs, const absl::Cord& rhs) const { 99 return lhs == rhs; 100 } 101 }; 102 103 // Supports heterogeneous lookup for string-like elements. 104 struct StringHashEq { 105 using Hash = StringHash; 106 using Eq = StringEq; 107 }; 108 109 template <> 110 struct HashEq<std::string> : StringHashEq {}; 111 template <> 112 struct HashEq<absl::string_view> : StringHashEq {}; 113 template <> 114 struct HashEq<absl::Cord> : StringHashEq {}; 115 116 #ifdef ABSL_HAVE_STD_STRING_VIEW 117 118 template <typename TChar> 119 struct BasicStringHash { 120 using is_transparent = void; 121 122 size_t operator()(std::basic_string_view<TChar> v) const { 123 return absl::Hash<std::basic_string_view<TChar>>{}(v); 124 } 125 }; 126 127 template <typename TChar> 128 struct BasicStringEq { 129 using is_transparent = void; 130 bool operator()(std::basic_string_view<TChar> lhs, 131 std::basic_string_view<TChar> rhs) const { 132 return lhs == rhs; 133 } 134 }; 135 136 // Supports heterogeneous lookup for w/u16/u32 string + string_view + char*. 137 template <typename TChar> 138 struct BasicStringHashEq { 139 using Hash = BasicStringHash<TChar>; 140 using Eq = BasicStringEq<TChar>; 141 }; 142 143 template <> 144 struct HashEq<std::wstring> : BasicStringHashEq<wchar_t> {}; 145 template <> 146 struct HashEq<std::wstring_view> : BasicStringHashEq<wchar_t> {}; 147 template <> 148 struct HashEq<std::u16string> : BasicStringHashEq<char16_t> {}; 149 template <> 150 struct HashEq<std::u16string_view> : BasicStringHashEq<char16_t> {}; 151 template <> 152 struct HashEq<std::u32string> : BasicStringHashEq<char32_t> {}; 153 template <> 154 struct HashEq<std::u32string_view> : BasicStringHashEq<char32_t> {}; 155 156 #endif // ABSL_HAVE_STD_STRING_VIEW 157 158 // Supports heterogeneous lookup for pointers and smart pointers. 159 template <class T> 160 struct HashEq<T*> { 161 struct Hash { 162 using is_transparent = void; 163 template <class U> 164 size_t operator()(const U& ptr) const { 165 return absl::Hash<const T*>{}(HashEq::ToPtr(ptr)); 166 } 167 }; 168 struct Eq { 169 using is_transparent = void; 170 template <class A, class B> 171 bool operator()(const A& a, const B& b) const { 172 return HashEq::ToPtr(a) == HashEq::ToPtr(b); 173 } 174 }; 175 176 private: 177 static const T* ToPtr(const T* ptr) { return ptr; } 178 template <class U, class D> 179 static const T* ToPtr(const std::unique_ptr<U, D>& ptr) { 180 return ptr.get(); 181 } 182 template <class U> 183 static const T* ToPtr(const std::shared_ptr<U>& ptr) { 184 return ptr.get(); 185 } 186 }; 187 188 template <class T, class D> 189 struct HashEq<std::unique_ptr<T, D>> : HashEq<T*> {}; 190 template <class T> 191 struct HashEq<std::shared_ptr<T>> : HashEq<T*> {}; 192 193 template <typename T, typename E = void> 194 struct HasAbslContainerHash : std::false_type {}; 195 196 template <typename T> 197 struct HasAbslContainerHash<T, absl::void_t<typename T::absl_container_hash>> 198 : std::true_type {}; 199 200 template <typename T, typename E = void> 201 struct HasAbslContainerEq : std::false_type {}; 202 203 template <typename T> 204 struct HasAbslContainerEq<T, absl::void_t<typename T::absl_container_eq>> 205 : std::true_type {}; 206 207 template <typename T, typename E = void> 208 struct AbslContainerEq { 209 using type = std::equal_to<>; 210 }; 211 212 template <typename T> 213 struct AbslContainerEq< 214 T, typename std::enable_if_t<HasAbslContainerEq<T>::value>> { 215 using type = typename T::absl_container_eq; 216 }; 217 218 template <typename T, typename E = void> 219 struct AbslContainerHash { 220 using type = void; 221 }; 222 223 template <typename T> 224 struct AbslContainerHash< 225 T, typename std::enable_if_t<HasAbslContainerHash<T>::value>> { 226 using type = typename T::absl_container_hash; 227 }; 228 229 // HashEq specialization for user types that provide `absl_container_hash` and 230 // (optionally) `absl_container_eq`. This specialization allows user types to 231 // provide heterogeneous lookup without requiring to explicitly specify Hash/Eq 232 // type arguments in unordered Abseil containers. 233 // 234 // Both `absl_container_hash` and `absl_container_eq` should be transparent 235 // (have inner is_transparent type). While there is no technical reason to 236 // restrict to transparent-only types, there is also no feasible use case when 237 // it shouldn't be transparent - it is easier to relax the requirement later if 238 // such a case arises rather than restricting it. 239 // 240 // If type provides only `absl_container_hash` then `eq` part will be 241 // `std::equal_to<void>`. 242 // 243 // User types are not allowed to provide only a `Eq` part as there is no 244 // feasible use case for this behavior - if Hash should be a default one then Eq 245 // should be an equivalent to the `std::equal_to<T>`. 246 template <typename T> 247 struct HashEq<T, typename std::enable_if_t<HasAbslContainerHash<T>::value>> { 248 using Hash = typename AbslContainerHash<T>::type; 249 using Eq = typename AbslContainerEq<T>::type; 250 static_assert(IsTransparent<Hash>::value, 251 "absl_container_hash must be transparent. To achieve it add a " 252 "`using is_transparent = void;` clause to this type."); 253 static_assert(IsTransparent<Eq>::value, 254 "absl_container_eq must be transparent. To achieve it add a " 255 "`using is_transparent = void;` clause to this type."); 256 }; 257 258 // This header's visibility is restricted. If you need to access the default 259 // hasher please use the container's ::hasher alias instead. 260 // 261 // Example: typename Hash = typename absl::flat_hash_map<K, V>::hasher 262 template <class T> 263 using hash_default_hash = typename container_internal::HashEq<T>::Hash; 264 265 // This header's visibility is restricted. If you need to access the default 266 // key equal please use the container's ::key_equal alias instead. 267 // 268 // Example: typename Eq = typename absl::flat_hash_map<K, V, Hash>::key_equal 269 template <class T> 270 using hash_default_eq = typename container_internal::HashEq<T>::Eq; 271 272 } // namespace container_internal 273 ABSL_NAMESPACE_END 274 } // namespace absl 275 276 #endif // ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ 277