From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Source/WTF/wtf/HashTraits.h | 143 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 122 insertions(+), 21 deletions(-) (limited to 'Source/WTF/wtf/HashTraits.h') diff --git a/Source/WTF/wtf/HashTraits.h b/Source/WTF/wtf/HashTraits.h index f14810021..542e7ad2c 100644 --- a/Source/WTF/wtf/HashTraits.h +++ b/Source/WTF/wtf/HashTraits.h @@ -21,18 +21,16 @@ #ifndef WTF_HashTraits_h #define WTF_HashTraits_h +#include +#include #include +#include #include -#include -#include namespace WTF { class String; -template class OwnPtr; -template class PassOwnPtr; - template struct HashTraits; template struct GenericHashTraitsBase; @@ -48,7 +46,7 @@ template struct GenericHashTraitsBase { // The starting table size. Can be overridden when we know beforehand that // a hash table will have at least N entries. - static const int minimumTableSize = 8; + static const unsigned minimumTableSize = 8; }; // Default integer traits disallow both 0 and -1 as keys (max value instead of -1 for unsigned). @@ -64,10 +62,18 @@ template struct GenericHashTraits : GenericHashTraitsBase + static void assignToEmpty(U& emptyValue, V&& value) + { + emptyValue = std::forward(value); + } + // Type for return value of functions that do not transfer ownership, such as get. typedef T PeekType; - static PeekType peek(const T& value) { return value; } - static T& peek(T& value) { return value; } // Overloaded to avoid copying of non-temporary values. + template static U&& peek(U&& value) { return std::forward(value); } + + typedef T TakeType; + template static TakeType take(U&& value) { return std::forward(value); } }; template struct HashTraits : GenericHashTraits { }; @@ -89,6 +95,22 @@ template struct UnsignedWithZeroKeyHashTraits : GenericHashTraits static bool isDeletedValue(T value) { return value == std::numeric_limits::max() - 1; } }; +template struct SignedWithZeroKeyHashTraits : GenericHashTraits { + static const bool emptyValueIsZero = false; + static T emptyValue() { return std::numeric_limits::min(); } + static void constructDeletedValue(T& slot) { slot = std::numeric_limits::max(); } + static bool isDeletedValue(T value) { return value == std::numeric_limits::max(); } +}; + +// Can be used with strong enums, allows zero as key. +template struct StrongEnumHashTraits : GenericHashTraits { + using UnderlyingType = typename std::underlying_type::type; + static const bool emptyValueIsZero = false; + static T emptyValue() { return static_cast(std::numeric_limits::max()); } + static void constructDeletedValue(T& slot) { slot = static_cast(std::numeric_limits::max() - 1); } + static bool isDeletedValue(T value) { return value == static_cast(std::numeric_limits::max() - 1); } +}; + template struct HashTraits : GenericHashTraits { static const bool emptyValueIsZero = true; static void constructDeletedValue(P*& slot) { slot = reinterpret_cast(-1); } @@ -97,7 +119,7 @@ template struct HashTraits : GenericHashTraits { template struct SimpleClassHashTraits : GenericHashTraits { static const bool emptyValueIsZero = true; - static void constructDeletedValue(T& slot) { new (NotNull, &slot) T(HashTableDeletedValue); } + static void constructDeletedValue(T& slot) { new (NotNull, std::addressof(slot)) T(HashTableDeletedValue); } static bool isDeletedValue(const T& value) { return value.isHashTableDeletedValue(); } }; @@ -105,31 +127,76 @@ template struct HashTraits& slot) { new (NotNull, std::addressof(slot)) std::unique_ptr { reinterpret_cast(-1) }; } + static bool isDeletedValue(const std::unique_ptr& value) { return value.get() == reinterpret_cast(-1); } + typedef T* PeekType; static T* peek(const std::unique_ptr& value) { return value.get(); } static T* peek(std::nullptr_t) { return nullptr; } -}; - -template struct HashTraits> : SimpleClassHashTraits> { - typedef std::nullptr_t EmptyValueType; - static EmptyValueType emptyValue() { return nullptr; } - typedef T* PeekType; - static T* peek(const OwnPtr& value) { return value.get(); } - static T* peek(std::nullptr_t) { return nullptr; } + static void customDeleteBucket(std::unique_ptr& value) + { + // The custom delete function exists to avoid a dead store before the value is destructed. + // The normal destruction sequence of a bucket would be: + // 1) Call the destructor of unique_ptr. + // 2) unique_ptr store a zero for its internal pointer. + // 3) unique_ptr destroys its value. + // 4) Call constructDeletedValue() to set the bucket as destructed. + // + // The problem is the call in (3) prevents the compile from eliminating the dead store in (2) + // becase a side effect of free() could be observing the value. + // + // This version of deleteBucket() ensures the dead 2 stores changing "value" + // are on the same side of the function call. + ASSERT(!isDeletedValue(value)); + T* pointer = value.release(); + constructDeletedValue(value); + + // The null case happens if a caller uses std::move() to remove the pointer before calling remove() + // with an iterator. This is very uncommon. + if (LIKELY(pointer)) + Deleter()(pointer); + } }; template struct HashTraits> : SimpleClassHashTraits> { - static P* emptyValue() { return 0; } + static P* emptyValue() { return nullptr; } typedef P* PeekType; static PeekType peek(const RefPtr

& value) { return value.get(); } static PeekType peek(P* value) { return value; } + + static void customDeleteBucket(RefPtr

& value) + { + // See unique_ptr's customDeleteBucket() for an explanation. + ASSERT(!SimpleClassHashTraits>::isDeletedValue(value)); + auto valueToBeDestroyed = WTFMove(value); + SimpleClassHashTraits>::constructDeletedValue(value); + } +}; + +template struct HashTraits> : SimpleClassHashTraits> { + static const bool emptyValueIsZero = true; + static Ref

emptyValue() { return HashTableEmptyValue; } + + static const bool hasIsEmptyValueFunction = true; + static bool isEmptyValue(const Ref

& value) { return value.isHashTableEmptyValue(); } + + static void assignToEmpty(Ref

& emptyValue, Ref

&& newValue) { ASSERT(isEmptyValue(emptyValue)); emptyValue.assignToHashTableEmptyValue(WTFMove(newValue)); } + + typedef P* PeekType; + static PeekType peek(const Ref

& value) { return const_cast(value.ptrAllowingHashTableEmptyValue()); } + static PeekType peek(P* value) { return value; } + + typedef std::optional> TakeType; + static TakeType take(Ref

&& value) { return isEmptyValue(value) ? std::nullopt : std::optional>(WTFMove(value)); } }; template<> struct HashTraits : SimpleClassHashTraits { static const bool hasIsEmptyValueFunction = true; static bool isEmptyValue(const String&); + + static void customDeleteBucket(String&); }; // This struct template is an implementation detail of the isHashTraitsEmptyValue function, @@ -146,6 +213,30 @@ template inline bool isHashTraitsEmptyValue(const T return HashTraitsEmptyValueChecker::isEmptyValue(value); } +template +struct HashTraitHasCustomDelete { + static T& bucketArg; + template static std::true_type TestHasCustomDelete(X*, decltype(X::customDeleteBucket(bucketArg))* = nullptr); + static std::false_type TestHasCustomDelete(...); + typedef decltype(TestHasCustomDelete(static_cast(nullptr))) ResultType; + static const bool value = ResultType::value; +}; + +template +typename std::enable_if::value>::type +hashTraitsDeleteBucket(T& value) +{ + Traits::customDeleteBucket(value); +} + +template +typename std::enable_if::value>::type +hashTraitsDeleteBucket(T& value) +{ + value.~T(); + Traits::constructDeletedValue(value); +} + template struct PairHashTraits : GenericHashTraits> { typedef FirstTraitsArg FirstTraits; @@ -156,7 +247,7 @@ struct PairHashTraits : GenericHashTraits TraitType; typedef KeyValuePair EmptyValueType; + typedef typename ValueTraitsArg::TraitType ValueType; static const bool emptyValueIsZero = KeyTraits::emptyValueIsZero && ValueTraits::emptyValueIsZero; static EmptyValueType emptyValue() { return KeyValuePair(KeyTraits::emptyValue(), ValueTraits::emptyValue()); } - static const int minimumTableSize = KeyTraits::minimumTableSize; + static const unsigned minimumTableSize = KeyTraits::minimumTableSize; static void constructDeletedValue(TraitType& slot) { KeyTraits::constructDeletedValue(slot.key); } static bool isDeletedValue(const TraitType& value) { return KeyTraits::isDeletedValue(value.key); } + + static void customDeleteBucket(TraitType& value) + { + static_assert(std::is_trivially_destructible>::value, + "The wrapper itself has to be trivially destructible for customDeleteBucket() to make sense, since we do not destruct the wrapper itself."); + + hashTraitsDeleteBucket(value.key); + value.value.~ValueType(); + } }; template @@ -225,7 +326,7 @@ struct CustomHashTraits : public GenericHashTraits { static void constructDeletedValue(T& slot) { - new (NotNull, &slot) T(T::DeletedValue); + new (NotNull, std::addressof(slot)) T(T::DeletedValue); } static bool isDeletedValue(const T& value) -- cgit v1.2.1