| OLD | NEW |
| 1 /* | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 * reserved. | 3 // found in the LICENSE file. |
| 4 * | |
| 5 * This library is free software; you can redistribute it and/or | |
| 6 * modify it under the terms of the GNU Library General Public | |
| 7 * License as published by the Free Software Foundation; either | |
| 8 * version 2 of the License, or (at your option) any later version. | |
| 9 * | |
| 10 * This library is distributed in the hope that it will be useful, | |
| 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 * Library General Public License for more details. | |
| 14 * | |
| 15 * You should have received a copy of the GNU Library General Public License | |
| 16 * along with this library; see the file COPYING.LIB. If not, write to | |
| 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 18 * Boston, MA 02110-1301, USA. | |
| 19 * | |
| 20 */ | |
| 21 | 4 |
| 22 #ifndef WTF_HashTraits_h | 5 #include "platform/wtf/HashTraits.h" |
| 23 #define WTF_HashTraits_h | |
| 24 | 6 |
| 25 #include "wtf/Forward.h" | 7 // The contents of this header was moved to platform/wtf as part of |
| 26 #include "wtf/HashFunctions.h" | 8 // WTF migration project. See the following post for details: |
| 27 #include "wtf/HashTableDeletedValueType.h" | 9 // https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gY
CAAJ |
| 28 #include "wtf/StdLibExtras.h" | |
| 29 #include "wtf/TypeTraits.h" | |
| 30 #include <limits> | |
| 31 #include <memory> | |
| 32 #include <string.h> // For memset. | |
| 33 #include <type_traits> | |
| 34 #include <utility> | |
| 35 | |
| 36 namespace WTF { | |
| 37 | |
| 38 template <bool isInteger, typename T> | |
| 39 struct GenericHashTraitsBase; | |
| 40 template <typename T> | |
| 41 struct HashTraits; | |
| 42 | |
| 43 enum ShouldWeakPointersBeMarkedStrongly { | |
| 44 WeakPointersActStrong, | |
| 45 WeakPointersActWeak | |
| 46 }; | |
| 47 | |
| 48 template <typename T> | |
| 49 struct GenericHashTraitsBase<false, T> { | |
| 50 // The emptyValueIsZero flag is used to optimize allocation of empty hash | |
| 51 // tables with zeroed memory. | |
| 52 static const bool emptyValueIsZero = false; | |
| 53 | |
| 54 // The hasIsEmptyValueFunction flag allows the hash table to automatically | |
| 55 // generate code to check for the empty value when it can be done with the | |
| 56 // equality operator, but allows custom functions for cases like String that | |
| 57 // need them. | |
| 58 static const bool hasIsEmptyValueFunction = false; | |
| 59 | |
| 60 // The starting table size. Can be overridden when we know beforehand that a | |
| 61 // hash table will have at least N entries. | |
| 62 #if defined(MEMORY_SANITIZER_INITIAL_SIZE) | |
| 63 static const unsigned minimumTableSize = 1; | |
| 64 #else | |
| 65 static const unsigned minimumTableSize = 8; | |
| 66 #endif | |
| 67 | |
| 68 // When a hash table backing store is traced, its elements will be | |
| 69 // traced if their class type has a trace method. However, weak-referenced | |
| 70 // elements should not be traced then, but handled by the weak processing | |
| 71 // phase that follows. | |
| 72 template <typename U = void> | |
| 73 struct IsTraceableInCollection { | |
| 74 static const bool value = IsTraceable<T>::value && !IsWeak<T>::value; | |
| 75 }; | |
| 76 | |
| 77 // The NeedsToForbidGCOnMove flag is used to make the hash table move | |
| 78 // operations safe when GC is enabled: if a move constructor invokes | |
| 79 // an allocation triggering the GC then it should be invoked within GC | |
| 80 // forbidden scope. | |
| 81 template <typename U = void> | |
| 82 struct NeedsToForbidGCOnMove { | |
| 83 // TODO(yutak): Consider using of std:::is_trivially_move_constructible | |
| 84 // when it is accessible. | |
| 85 static const bool value = !std::is_pod<T>::value; | |
| 86 }; | |
| 87 | |
| 88 static const WeakHandlingFlag weakHandlingFlag = | |
| 89 IsWeak<T>::value ? WeakHandlingInCollections | |
| 90 : NoWeakHandlingInCollections; | |
| 91 }; | |
| 92 | |
| 93 // Default integer traits disallow both 0 and -1 as keys (max value instead of | |
| 94 // -1 for unsigned). | |
| 95 template <typename T> | |
| 96 struct GenericHashTraitsBase<true, T> : GenericHashTraitsBase<false, T> { | |
| 97 static const bool emptyValueIsZero = true; | |
| 98 static void constructDeletedValue(T& slot, bool) { | |
| 99 slot = static_cast<T>(-1); | |
| 100 } | |
| 101 static bool isDeletedValue(T value) { return value == static_cast<T>(-1); } | |
| 102 }; | |
| 103 | |
| 104 template <typename T> | |
| 105 struct GenericHashTraits | |
| 106 : GenericHashTraitsBase<std::is_integral<T>::value, T> { | |
| 107 typedef T TraitType; | |
| 108 typedef T EmptyValueType; | |
| 109 | |
| 110 static T emptyValue() { return T(); } | |
| 111 | |
| 112 // Type for functions that do not take ownership, such as contains. | |
| 113 typedef const T& PeekInType; | |
| 114 typedef T* IteratorGetType; | |
| 115 typedef const T* IteratorConstGetType; | |
| 116 typedef T& IteratorReferenceType; | |
| 117 typedef const T& IteratorConstReferenceType; | |
| 118 static IteratorReferenceType getToReferenceConversion(IteratorGetType x) { | |
| 119 return *x; | |
| 120 } | |
| 121 static IteratorConstReferenceType getToReferenceConstConversion( | |
| 122 IteratorConstGetType x) { | |
| 123 return *x; | |
| 124 } | |
| 125 | |
| 126 template <typename IncomingValueType> | |
| 127 static void store(IncomingValueType&& value, T& storage) { | |
| 128 storage = std::forward<IncomingValueType>(value); | |
| 129 } | |
| 130 | |
| 131 // Type for return value of functions that do not transfer ownership, such | |
| 132 // as get. | |
| 133 // FIXME: We could change this type to const T& for better performance if we | |
| 134 // figured out a way to handle the return value from emptyValue, which is a | |
| 135 // temporary. | |
| 136 typedef T PeekOutType; | |
| 137 static const T& peek(const T& value) { return value; } | |
| 138 }; | |
| 139 | |
| 140 template <typename T> | |
| 141 struct HashTraits : GenericHashTraits<T> {}; | |
| 142 | |
| 143 template <typename T> | |
| 144 struct FloatHashTraits : GenericHashTraits<T> { | |
| 145 static T emptyValue() { return std::numeric_limits<T>::infinity(); } | |
| 146 static void constructDeletedValue(T& slot, bool) { | |
| 147 slot = -std::numeric_limits<T>::infinity(); | |
| 148 } | |
| 149 static bool isDeletedValue(T value) { | |
| 150 return value == -std::numeric_limits<T>::infinity(); | |
| 151 } | |
| 152 }; | |
| 153 | |
| 154 template <> | |
| 155 struct HashTraits<float> : FloatHashTraits<float> {}; | |
| 156 template <> | |
| 157 struct HashTraits<double> : FloatHashTraits<double> {}; | |
| 158 | |
| 159 // Default unsigned traits disallow both 0 and max as keys -- use these traits | |
| 160 // to allow zero and disallow max - 1. | |
| 161 template <typename T> | |
| 162 struct UnsignedWithZeroKeyHashTraits : GenericHashTraits<T> { | |
| 163 static const bool emptyValueIsZero = false; | |
| 164 static T emptyValue() { return std::numeric_limits<T>::max(); } | |
| 165 static void constructDeletedValue(T& slot, bool) { | |
| 166 slot = std::numeric_limits<T>::max() - 1; | |
| 167 } | |
| 168 static bool isDeletedValue(T value) { | |
| 169 return value == std::numeric_limits<T>::max() - 1; | |
| 170 } | |
| 171 }; | |
| 172 | |
| 173 template <typename P> | |
| 174 struct HashTraits<P*> : GenericHashTraits<P*> { | |
| 175 static const bool emptyValueIsZero = true; | |
| 176 static void constructDeletedValue(P*& slot, bool) { | |
| 177 slot = reinterpret_cast<P*>(-1); | |
| 178 } | |
| 179 static bool isDeletedValue(P* value) { | |
| 180 return value == reinterpret_cast<P*>(-1); | |
| 181 } | |
| 182 }; | |
| 183 | |
| 184 template <typename T> | |
| 185 struct SimpleClassHashTraits : GenericHashTraits<T> { | |
| 186 static const bool emptyValueIsZero = true; | |
| 187 template <typename U = void> | |
| 188 struct NeedsToForbidGCOnMove { | |
| 189 static const bool value = false; | |
| 190 }; | |
| 191 static void constructDeletedValue(T& slot, bool) { | |
| 192 new (NotNull, &slot) T(HashTableDeletedValue); | |
| 193 } | |
| 194 static bool isDeletedValue(const T& value) { | |
| 195 return value.isHashTableDeletedValue(); | |
| 196 } | |
| 197 }; | |
| 198 | |
| 199 template <typename P> | |
| 200 struct HashTraits<RefPtr<P>> : SimpleClassHashTraits<RefPtr<P>> { | |
| 201 typedef std::nullptr_t EmptyValueType; | |
| 202 static EmptyValueType emptyValue() { return nullptr; } | |
| 203 | |
| 204 static const bool hasIsEmptyValueFunction = true; | |
| 205 static bool isEmptyValue(const RefPtr<P>& value) { return !value; } | |
| 206 | |
| 207 typedef RefPtrValuePeeker<P> PeekInType; | |
| 208 typedef RefPtr<P>* IteratorGetType; | |
| 209 typedef const RefPtr<P>* IteratorConstGetType; | |
| 210 typedef RefPtr<P>& IteratorReferenceType; | |
| 211 typedef const RefPtr<P>& IteratorConstReferenceType; | |
| 212 static IteratorReferenceType getToReferenceConversion(IteratorGetType x) { | |
| 213 return *x; | |
| 214 } | |
| 215 static IteratorConstReferenceType getToReferenceConstConversion( | |
| 216 IteratorConstGetType x) { | |
| 217 return *x; | |
| 218 } | |
| 219 | |
| 220 static void store(PassRefPtr<P> value, RefPtr<P>& storage) { | |
| 221 storage = std::move(value); | |
| 222 } | |
| 223 | |
| 224 typedef P* PeekOutType; | |
| 225 static PeekOutType peek(const RefPtr<P>& value) { return value.get(); } | |
| 226 static PeekOutType peek(std::nullptr_t) { return 0; } | |
| 227 }; | |
| 228 | |
| 229 template <typename T> | |
| 230 struct HashTraits<std::unique_ptr<T>> | |
| 231 : SimpleClassHashTraits<std::unique_ptr<T>> { | |
| 232 using EmptyValueType = std::nullptr_t; | |
| 233 static EmptyValueType emptyValue() { return nullptr; } | |
| 234 | |
| 235 static const bool hasIsEmptyValueFunction = true; | |
| 236 static bool isEmptyValue(const std::unique_ptr<T>& value) { return !value; } | |
| 237 | |
| 238 using PeekInType = T*; | |
| 239 | |
| 240 static void store(std::unique_ptr<T>&& value, std::unique_ptr<T>& storage) { | |
| 241 storage = std::move(value); | |
| 242 } | |
| 243 | |
| 244 using PeekOutType = T*; | |
| 245 static PeekOutType peek(const std::unique_ptr<T>& value) { | |
| 246 return value.get(); | |
| 247 } | |
| 248 static PeekOutType peek(std::nullptr_t) { return nullptr; } | |
| 249 | |
| 250 static void constructDeletedValue(std::unique_ptr<T>& slot, bool) { | |
| 251 // Dirty trick: implant an invalid pointer to unique_ptr. Destructor isn't | |
| 252 // called for deleted buckets, so this is okay. | |
| 253 new (NotNull, &slot) std::unique_ptr<T>(reinterpret_cast<T*>(1u)); | |
| 254 } | |
| 255 static bool isDeletedValue(const std::unique_ptr<T>& value) { | |
| 256 return value.get() == reinterpret_cast<T*>(1u); | |
| 257 } | |
| 258 }; | |
| 259 | |
| 260 template <> | |
| 261 struct HashTraits<String> : SimpleClassHashTraits<String> { | |
| 262 static const bool hasIsEmptyValueFunction = true; | |
| 263 static bool isEmptyValue(const String&); | |
| 264 }; | |
| 265 | |
| 266 // This struct template is an implementation detail of the | |
| 267 // isHashTraitsEmptyValue function, which selects either the emptyValue function | |
| 268 // or the isEmptyValue function to check for empty values. | |
| 269 template <typename Traits, bool hasEmptyValueFunction> | |
| 270 struct HashTraitsEmptyValueChecker; | |
| 271 template <typename Traits> | |
| 272 struct HashTraitsEmptyValueChecker<Traits, true> { | |
| 273 template <typename T> | |
| 274 static bool isEmptyValue(const T& value) { | |
| 275 return Traits::isEmptyValue(value); | |
| 276 } | |
| 277 }; | |
| 278 template <typename Traits> | |
| 279 struct HashTraitsEmptyValueChecker<Traits, false> { | |
| 280 template <typename T> | |
| 281 static bool isEmptyValue(const T& value) { | |
| 282 return value == Traits::emptyValue(); | |
| 283 } | |
| 284 }; | |
| 285 template <typename Traits, typename T> | |
| 286 inline bool isHashTraitsEmptyValue(const T& value) { | |
| 287 return HashTraitsEmptyValueChecker< | |
| 288 Traits, Traits::hasIsEmptyValueFunction>::isEmptyValue(value); | |
| 289 } | |
| 290 | |
| 291 template <typename FirstTraitsArg, typename SecondTraitsArg> | |
| 292 struct PairHashTraits | |
| 293 : GenericHashTraits<std::pair<typename FirstTraitsArg::TraitType, | |
| 294 typename SecondTraitsArg::TraitType>> { | |
| 295 typedef FirstTraitsArg FirstTraits; | |
| 296 typedef SecondTraitsArg SecondTraits; | |
| 297 typedef std::pair<typename FirstTraits::TraitType, | |
| 298 typename SecondTraits::TraitType> | |
| 299 TraitType; | |
| 300 typedef std::pair<typename FirstTraits::EmptyValueType, | |
| 301 typename SecondTraits::EmptyValueType> | |
| 302 EmptyValueType; | |
| 303 | |
| 304 static const bool emptyValueIsZero = | |
| 305 FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero; | |
| 306 static EmptyValueType emptyValue() { | |
| 307 return std::make_pair(FirstTraits::emptyValue(), | |
| 308 SecondTraits::emptyValue()); | |
| 309 } | |
| 310 | |
| 311 static const bool hasIsEmptyValueFunction = | |
| 312 FirstTraits::hasIsEmptyValueFunction || | |
| 313 SecondTraits::hasIsEmptyValueFunction; | |
| 314 static bool isEmptyValue(const TraitType& value) { | |
| 315 return isHashTraitsEmptyValue<FirstTraits>(value.first) && | |
| 316 isHashTraitsEmptyValue<SecondTraits>(value.second); | |
| 317 } | |
| 318 | |
| 319 static const unsigned minimumTableSize = FirstTraits::minimumTableSize; | |
| 320 | |
| 321 static void constructDeletedValue(TraitType& slot, bool zeroValue) { | |
| 322 FirstTraits::constructDeletedValue(slot.first, zeroValue); | |
| 323 // For GC collections the memory for the backing is zeroed when it is | |
| 324 // allocated, and the constructors may take advantage of that, | |
| 325 // especially if a GC occurs during insertion of an entry into the | |
| 326 // table. This slot is being marked deleted, but If the slot is reused | |
| 327 // at a later point, the same assumptions around memory zeroing must | |
| 328 // hold as they did at the initial allocation. Therefore we zero the | |
| 329 // value part of the slot here for GC collections. | |
| 330 if (zeroValue) | |
| 331 memset(reinterpret_cast<void*>(&slot.second), 0, sizeof(slot.second)); | |
| 332 } | |
| 333 static bool isDeletedValue(const TraitType& value) { | |
| 334 return FirstTraits::isDeletedValue(value.first); | |
| 335 } | |
| 336 }; | |
| 337 | |
| 338 template <typename First, typename Second> | |
| 339 struct HashTraits<std::pair<First, Second>> | |
| 340 : public PairHashTraits<HashTraits<First>, HashTraits<Second>> {}; | |
| 341 | |
| 342 template <typename KeyTypeArg, typename ValueTypeArg> | |
| 343 struct KeyValuePair { | |
| 344 typedef KeyTypeArg KeyType; | |
| 345 | |
| 346 template <typename IncomingKeyType, typename IncomingValueType> | |
| 347 KeyValuePair(IncomingKeyType&& key, IncomingValueType&& value) | |
| 348 : key(std::forward<IncomingKeyType>(key)), | |
| 349 value(std::forward<IncomingValueType>(value)) {} | |
| 350 | |
| 351 template <typename OtherKeyType, typename OtherValueType> | |
| 352 KeyValuePair(KeyValuePair<OtherKeyType, OtherValueType>&& other) | |
| 353 : key(std::move(other.key)), value(std::move(other.value)) {} | |
| 354 | |
| 355 KeyTypeArg key; | |
| 356 ValueTypeArg value; | |
| 357 }; | |
| 358 | |
| 359 template <typename KeyTraitsArg, typename ValueTraitsArg> | |
| 360 struct KeyValuePairHashTraits | |
| 361 : GenericHashTraits<KeyValuePair<typename KeyTraitsArg::TraitType, | |
| 362 typename ValueTraitsArg::TraitType>> { | |
| 363 typedef KeyTraitsArg KeyTraits; | |
| 364 typedef ValueTraitsArg ValueTraits; | |
| 365 typedef KeyValuePair<typename KeyTraits::TraitType, | |
| 366 typename ValueTraits::TraitType> | |
| 367 TraitType; | |
| 368 typedef KeyValuePair<typename KeyTraits::EmptyValueType, | |
| 369 typename ValueTraits::EmptyValueType> | |
| 370 EmptyValueType; | |
| 371 | |
| 372 static const bool emptyValueIsZero = | |
| 373 KeyTraits::emptyValueIsZero && ValueTraits::emptyValueIsZero; | |
| 374 static EmptyValueType emptyValue() { | |
| 375 return KeyValuePair<typename KeyTraits::EmptyValueType, | |
| 376 typename ValueTraits::EmptyValueType>( | |
| 377 KeyTraits::emptyValue(), ValueTraits::emptyValue()); | |
| 378 } | |
| 379 | |
| 380 template <typename U = void> | |
| 381 struct IsTraceableInCollection { | |
| 382 static const bool value = IsTraceableInCollectionTrait<KeyTraits>::value || | |
| 383 IsTraceableInCollectionTrait<ValueTraits>::value; | |
| 384 }; | |
| 385 | |
| 386 template <typename U = void> | |
| 387 struct NeedsToForbidGCOnMove { | |
| 388 static const bool value = | |
| 389 KeyTraits::template NeedsToForbidGCOnMove<>::value || | |
| 390 ValueTraits::template NeedsToForbidGCOnMove<>::value; | |
| 391 }; | |
| 392 | |
| 393 static const WeakHandlingFlag weakHandlingFlag = | |
| 394 (KeyTraits::weakHandlingFlag == WeakHandlingInCollections || | |
| 395 ValueTraits::weakHandlingFlag == WeakHandlingInCollections) | |
| 396 ? WeakHandlingInCollections | |
| 397 : NoWeakHandlingInCollections; | |
| 398 | |
| 399 static const unsigned minimumTableSize = KeyTraits::minimumTableSize; | |
| 400 | |
| 401 static void constructDeletedValue(TraitType& slot, bool zeroValue) { | |
| 402 KeyTraits::constructDeletedValue(slot.key, zeroValue); | |
| 403 // See similar code in this file for why we need to do this. | |
| 404 if (zeroValue) | |
| 405 memset(reinterpret_cast<void*>(&slot.value), 0, sizeof(slot.value)); | |
| 406 } | |
| 407 static bool isDeletedValue(const TraitType& value) { | |
| 408 return KeyTraits::isDeletedValue(value.key); | |
| 409 } | |
| 410 }; | |
| 411 | |
| 412 template <typename Key, typename Value> | |
| 413 struct HashTraits<KeyValuePair<Key, Value>> | |
| 414 : public KeyValuePairHashTraits<HashTraits<Key>, HashTraits<Value>> {}; | |
| 415 | |
| 416 template <typename T> | |
| 417 struct NullableHashTraits : public HashTraits<T> { | |
| 418 static const bool emptyValueIsZero = false; | |
| 419 static T emptyValue() { return reinterpret_cast<T>(1); } | |
| 420 }; | |
| 421 | |
| 422 } // namespace WTF | |
| 423 | |
| 424 using WTF::HashTraits; | |
| 425 using WTF::PairHashTraits; | |
| 426 using WTF::NullableHashTraits; | |
| 427 using WTF::SimpleClassHashTraits; | |
| 428 | |
| 429 #endif // WTF_HashTraits_h | |
| OLD | NEW |