Title: [225463] trunk
Revision
225463
Author
[email protected]
Date
2017-12-03 14:48:40 -0800 (Sun, 03 Dec 2017)

Log Message

Add WTF::Hasher, an easier to use replacement for WTF::IntegerHasher
https://bugs.webkit.org/show_bug.cgi?id=180318

Reviewed by JF Bastien.

Source/WTF:

* WTF.xcodeproj/project.pbxproj: Added Hasher.h.
* wtf/CMakeLists.txt: Ditto.

* wtf/Forward.h: Added Hasher and TextStream.

* wtf/Hasher.h: Moved StringHasher into a separate header. Added Hasher.
Marked IntegerHasher deprecated.

* wtf/text/CString.cpp: Include StringHasher.h instead of Hasher.h.
* wtf/text/StringHash.h: Ditto.

* wtf/text/StringHasher.h: Added. Moved StringHasher here from Hasher.h.

* wtf/text/StringImpl.h: Include StringHasher.h instead of Hasher.h.

* wtf/text/WTFString.h: Added a hash function. This was useful in some
adoption I was doing in WebCore, not included in this patch.

* wtf/unicode/UTF8.cpp: Include StringHasher.h instead of Hasher.h.

Tools:

* TestWebKitAPI/CMakeLists.txt: Added Hasher.cpp.
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Ditto.

* TestWebKitAPI/Tests/WTF/Hasher.cpp: Added. Contains tests of the new
WTF::Hasher class.

* TestWebKitAPI/Tests/WTF/StringHasher.cpp: Include StringHasher.h instead of
Hasher.h.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (225462 => 225463)


--- trunk/Source/WTF/ChangeLog	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/ChangeLog	2017-12-03 22:48:40 UTC (rev 225463)
@@ -1,3 +1,30 @@
+2017-12-03  Darin Adler  <[email protected]>
+
+        Add WTF::Hasher, an easier to use replacement for WTF::IntegerHasher
+        https://bugs.webkit.org/show_bug.cgi?id=180318
+
+        Reviewed by JF Bastien.
+
+        * WTF.xcodeproj/project.pbxproj: Added Hasher.h.
+        * wtf/CMakeLists.txt: Ditto.
+
+        * wtf/Forward.h: Added Hasher and TextStream.
+
+        * wtf/Hasher.h: Moved StringHasher into a separate header. Added Hasher.
+        Marked IntegerHasher deprecated.
+
+        * wtf/text/CString.cpp: Include StringHasher.h instead of Hasher.h.
+        * wtf/text/StringHash.h: Ditto.
+
+        * wtf/text/StringHasher.h: Added. Moved StringHasher here from Hasher.h.
+
+        * wtf/text/StringImpl.h: Include StringHasher.h instead of Hasher.h.
+
+        * wtf/text/WTFString.h: Added a hash function. This was useful in some
+        adoption I was doing in WebCore, not included in this patch.
+
+        * wtf/unicode/UTF8.cpp: Include StringHasher.h instead of Hasher.h.
+
 2017-12-02  Brady Eidson  <[email protected]>
 
         Factor out the "databaseTaskQueue" parts of IDBServer into something reusable.

Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (225462 => 225463)


--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2017-12-03 22:48:40 UTC (rev 225463)
@@ -378,6 +378,7 @@
 		83F2BADE1CF9524E003E99C3 /* Function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Function.h; sourceTree = "<group>"; };
 		83FBA93119DF459700F30ADB /* TypeCasts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeCasts.h; sourceTree = "<group>"; };
 		86F46F5F1A2840EE00CCBF22 /* RefCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefCounter.h; sourceTree = "<group>"; };
+		933D63191FCB6AB90032ECD6 /* StringHasher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringHasher.h; sourceTree = "<group>"; };
 		93934BD218A1E8C300D0D6A1 /* StringViewObjC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = StringViewObjC.mm; path = mac/StringViewObjC.mm; sourceTree = "<group>"; };
 		93934BD418A1F16900D0D6A1 /* StringViewCF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringViewCF.cpp; path = cf/StringViewCF.cpp; sourceTree = "<group>"; };
 		93AC91A718942FC400244939 /* LChar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LChar.h; sourceTree = "<group>"; };
@@ -1141,6 +1142,7 @@
 				A8A47326151A825B004123FF /* StringConcatenate.h */,
 				7CD4C26F1E2C82B900929470 /* StringConcatenateNumbers.h */,
 				A8A47327151A825B004123FF /* StringHash.h */,
+				933D63191FCB6AB90032ECD6 /* StringHasher.h */,
 				A8A47328151A825B004123FF /* StringImpl.cpp */,
 				A8A47329151A825B004123FF /* StringImpl.h */,
 				0F0F52691F421FF8004A452C /* StringMalloc.cpp */,

Modified: trunk/Source/WTF/wtf/CMakeLists.txt (225462 => 225463)


--- trunk/Source/WTF/wtf/CMakeLists.txt	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/wtf/CMakeLists.txt	2017-12-03 22:48:40 UTC (rev 225463)
@@ -186,6 +186,7 @@
     text/StringBuffer.h
     text/StringCommon.h
     text/StringHash.h
+    text/StringHasher.h
     text/StringImpl.h
     text/StringMalloc.h
     text/StringVector.h

Modified: trunk/Source/WTF/wtf/Forward.h (225462 => 225463)


--- trunk/Source/WTF/wtf/Forward.h	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/wtf/Forward.h	2017-12-03 22:48:40 UTC (rev 225463)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2006, 2009, 2011 Apple Inc. All rights reserved.
+ *  Copyright (C) 2006-2017 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -34,6 +34,7 @@
 class CString;
 class CrashOnOverflow;
 class FunctionDispatcher;
+class Hasher;
 class OrdinalNumber;
 class PrintStream;
 class SHA1;
@@ -42,6 +43,7 @@
 class StringImpl;
 class StringView;
 class TextPosition;
+class TextStream;
 
 struct FastMalloc;
 
@@ -69,8 +71,8 @@
 using WTF::AtomicString;
 using WTF::AtomicStringImpl;
 using WTF::BinarySemaphore;
+using WTF::CString;
 using WTF::CompletionHandler;
-using WTF::CString;
 using WTF::Expected;
 using WTF::Function;
 using WTF::FunctionDispatcher;
@@ -77,6 +79,7 @@
 using WTF::HashCountedSet;
 using WTF::HashMap;
 using WTF::HashSet;
+using WTF::Hasher;
 using WTF::LazyNeverDestroyed;
 using WTF::NeverDestroyed;
 using WTF::OptionSet;
@@ -91,5 +94,6 @@
 using WTF::StringImpl;
 using WTF::StringView;
 using WTF::TextPosition;
+using WTF::TextStream;
 using WTF::Variant;
 using WTF::Vector;

Modified: trunk/Source/WTF/wtf/Hasher.h (225462 => 225463)


--- trunk/Source/WTF/wtf/Hasher.h	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/wtf/Hasher.h	2017-12-03 22:48:40 UTC (rev 225463)
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2005-2006, 2008, 2010, 2013, 2016 Apple Inc. All rights reserved.
- * Copyright (C) 2010 Patrick Gansterer <[email protected]>
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -19,371 +18,147 @@
  *
  */
 
-#ifndef WTF_Hasher_h
-#define WTF_Hasher_h
+#pragma once
 
-#include <unicode/utypes.h>
-#include <wtf/text/LChar.h>
+#include <wtf/Forward.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHasher.h>
 
 namespace WTF {
 
-// Paul Hsieh's SuperFastHash
-// http://www.azillionmonkeys.com/qed/hash.html
-
-// LChar data is interpreted as Latin-1-encoded (zero extended to 16 bits).
-
-// NOTE: The hash computation here must stay in sync with the create_hash_table script in
-// _javascript_Core and the CodeGeneratorJS.pm script in WebCore.
-
-// Golden ratio. Arbitrary start value to avoid mapping all zeros to a hash value of zero.
-static constexpr const unsigned stringHashingStartValue = 0x9E3779B9U;
-
-class StringHasher {
+// Deprecated. Use Hasher instead.
+class IntegerHasher {
 public:
-    static constexpr const unsigned flagCount = 8; // Save 8 bits for StringImpl to use as flags.
-    static constexpr const unsigned maskHash = (1U << (sizeof(unsigned) * 8 - flagCount)) - 1;
-
-    StringHasher()
-        : m_hash(stringHashingStartValue)
-        , m_hasPendingCharacter(false)
-        , m_pendingCharacter(0)
+    void add(uint32_t integer)
     {
+        m_underlyingHasher.addCharactersAssumingAligned(integer, integer >> 16);
     }
 
-    // The hasher hashes two characters at a time, and thus an "aligned" hasher is one
-    // where an even number of characters have been added. Callers that always add
-    // characters two at a time can use the "assuming aligned" functions.
-    void addCharactersAssumingAligned(UChar a, UChar b)
-    {
-        ASSERT(!m_hasPendingCharacter);
-        m_hash += a;
-        m_hash = (m_hash << 16) ^ ((b << 11) ^ m_hash);
-        m_hash += m_hash >> 11;
-    }
-
-    void addCharacter(UChar character)
-    {
-        if (m_hasPendingCharacter) {
-            m_hasPendingCharacter = false;
-            addCharactersAssumingAligned(m_pendingCharacter, character);
-            return;
-        }
-
-        m_pendingCharacter = character;
-        m_hasPendingCharacter = true;
-    }
-
-    void addCharacters(UChar a, UChar b)
-    {
-        if (m_hasPendingCharacter) {
-#if !ASSERT_DISABLED
-            m_hasPendingCharacter = false;
-#endif
-            addCharactersAssumingAligned(m_pendingCharacter, a);
-            m_pendingCharacter = b;
-#if !ASSERT_DISABLED
-            m_hasPendingCharacter = true;
-#endif
-            return;
-        }
-
-        addCharactersAssumingAligned(a, b);
-    }
-
-    template<typename T, UChar Converter(T)> void addCharactersAssumingAligned(const T* data, unsigned length)
-    {
-        ASSERT(!m_hasPendingCharacter);
-
-        bool remainder = length & 1;
-        length >>= 1;
-
-        while (length--) {
-            addCharactersAssumingAligned(Converter(data[0]), Converter(data[1]));
-            data += 2;
-        }
-
-        if (remainder)
-            addCharacter(Converter(*data));
-    }
-
-    template<typename T> void addCharactersAssumingAligned(const T* data, unsigned length)
-    {
-        addCharactersAssumingAligned<T, defaultConverter>(data, length);
-    }
-
-    template<typename T, UChar Converter(T)> void addCharactersAssumingAligned(const T* data)
-    {
-        ASSERT(!m_hasPendingCharacter);
-
-        while (T a = *data++) {
-            T b = *data++;
-            if (!b) {
-                addCharacter(Converter(a));
-                break;
-            }
-            addCharactersAssumingAligned(Converter(a), Converter(b));
-        }
-    }
-
-    template<typename T> void addCharactersAssumingAligned(const T* data)
-    {
-        addCharactersAssumingAligned<T, defaultConverter>(data);
-    }
-
-    template<typename T, UChar Converter(T)> void addCharacters(const T* data, unsigned length)
-    {
-        if (!length)
-            return;
-        if (m_hasPendingCharacter) {
-            m_hasPendingCharacter = false;
-            addCharactersAssumingAligned(m_pendingCharacter, Converter(*data++));
-            --length;
-        }
-        addCharactersAssumingAligned<T, Converter>(data, length);
-    }
-
-    template<typename T> void addCharacters(const T* data, unsigned length)
-    {
-        addCharacters<T, defaultConverter>(data, length);
-    }
-
-    template<typename T, UChar Converter(T)> void addCharacters(const T* data)
-    {
-        if (m_hasPendingCharacter && *data) {
-            m_hasPendingCharacter = false;
-            addCharactersAssumingAligned(m_pendingCharacter, Converter(*data++));
-        }
-        addCharactersAssumingAligned<T, Converter>(data);
-    }
-
-    template<typename T> void addCharacters(const T* data)
-    {
-        addCharacters<T, defaultConverter>(data);
-    }
-
-    unsigned hashWithTop8BitsMasked() const
-    {
-        return finalizeAndMaskTop8Bits(processPendingCharacter());
-    }
-
     unsigned hash() const
     {
-        return finalize(processPendingCharacter());
+        return m_underlyingHasher.hash();
     }
 
-    template<typename T, UChar Converter(T)> static unsigned computeHashAndMaskTop8Bits(const T* data, unsigned length)
-    {
-        StringHasher hasher;
-        hasher.addCharactersAssumingAligned<T, Converter>(data, length);
-        return hasher.hashWithTop8BitsMasked();
-    }
+private:
+    StringHasher m_underlyingHasher;
+};
 
-    template<typename T, UChar Converter(T)> static unsigned computeHashAndMaskTop8Bits(const T* data)
-    {
-        StringHasher hasher;
-        hasher.addCharactersAssumingAligned<T, Converter>(data);
-        return hasher.hashWithTop8BitsMasked();
-    }
+template<typename... Types> uint32_t computeHash(const Types&...);
+template<typename T, typename... OtherTypes> uint32_t computeHash(std::initializer_list<T>, std::initializer_list<OtherTypes>...);
 
-    template<typename T> static unsigned computeHashAndMaskTop8Bits(const T* data, unsigned length)
+class Hasher {
+public:
+    template<typename... Types> friend uint32_t computeHash(const Types&... values)
     {
-        return computeHashAndMaskTop8Bits<T, defaultConverter>(data, length);
+        Hasher hasher;
+        add(hasher, std::forward_as_tuple(values...));
+        return hasher.m_underlyingHasher.hash();
     }
 
-    template<typename T> static unsigned computeHashAndMaskTop8Bits(const T* data)
+    template<typename T, typename... OtherTypes> friend uint32_t computeHash(std::initializer_list<T> list, std::initializer_list<OtherTypes>... otherLists)
     {
-        return computeHashAndMaskTop8Bits<T, defaultConverter>(data);
+        Hasher hasher;
+        add(hasher, list);
+        add(hasher, std::forward_as_tuple(otherLists...));
+        return hasher.m_underlyingHasher.hash();
     }
 
-    template<typename T, UChar Converter(T)> static unsigned computeHash(const T* data, unsigned length)
+    template<typename UnsignedInteger> friend std::enable_if_t<std::is_unsigned<UnsignedInteger>::value && sizeof(UnsignedInteger) <= sizeof(uint32_t), void> add(Hasher& hasher, UnsignedInteger integer)
     {
-        StringHasher hasher;
-        hasher.addCharactersAssumingAligned<T, Converter>(data, length);
-        return hasher.hash();
+        // We can consider adding a more efficient code path for hashing booleans or individual bytes if needed.
+        // We can consider adding a more efficient code path for hashing 16-bit values if needed, perhaps using addCharacter,
+        // but getting rid of "assuming aligned" would make hashing values 32-bit or larger slower.
+        uint32_t sizedInteger = integer;
+        hasher.m_underlyingHasher.addCharactersAssumingAligned(sizedInteger, sizedInteger >> 16);
     }
 
-    template<typename T, UChar Converter(T)> static unsigned computeHash(const T* data)
-    {
-        StringHasher hasher;
-        hasher.addCharactersAssumingAligned<T, Converter>(data);
-        return hasher.hash();
-    }
-
-    template<typename T> static unsigned computeHash(const T* data, unsigned length)
-    {
-        return computeHash<T, defaultConverter>(data, length);
-    }
-
-    template<typename T> static unsigned computeHash(const T* data)
-    {
-        return computeHash<T, defaultConverter>(data);
-    }
-
-    static unsigned hashMemory(const void* data, unsigned length)
-    {
-        size_t lengthInUChar = length / sizeof(UChar);
-        StringHasher hasher;
-        hasher.addCharactersAssumingAligned(static_cast<const UChar*>(data), lengthInUChar);
-
-        for (size_t i = 0; i < length % sizeof(UChar); ++i)
-            hasher.addCharacter(static_cast<const char*>(data)[lengthInUChar * sizeof(UChar) + i]);
-
-        return hasher.hash();
-    }
-
-    template<size_t length> static unsigned hashMemory(const void* data)
-    {
-        return hashMemory(data, length);
-    }
-
-    static constexpr unsigned finalize(unsigned hash)
-    {
-        return avoidZero(avalancheBits(hash));
-    }
-
-    static constexpr unsigned finalizeAndMaskTop8Bits(unsigned hash)
-    {
-        // Reserving space from the high bits for flags preserves most of the hash's
-        // value, since hash lookup typically masks out the high bits anyway.
-        return avoidZero(avalancheBits(hash) & StringHasher::maskHash);
-    }
-
-    template<typename T, unsigned characterCount>
-    static constexpr unsigned computeLiteralHash(const T (&characters)[characterCount])
-    {
-        return StringHasher::finalize(computeLiteralHashImpl(stringHashingStartValue, 0, characters, characterCount - 1));
-    }
-
-    template<typename T, unsigned characterCount>
-    static constexpr unsigned computeLiteralHashAndMaskTop8Bits(const T (&characters)[characterCount])
-    {
-        return StringHasher::finalizeAndMaskTop8Bits(computeLiteralHashImpl(stringHashingStartValue, 0, characters, characterCount - 1));
-    }
-
 private:
-    static UChar defaultConverter(UChar character)
-    {
-        return character;
-    }
+    StringHasher m_underlyingHasher;
+};
 
-    static UChar defaultConverter(LChar character)
-    {
-        return character;
-    }
+template<typename UnsignedInteger> std::enable_if_t<std::is_unsigned<UnsignedInteger>::value && sizeof(UnsignedInteger) == sizeof(uint64_t), void> add(Hasher& hasher, UnsignedInteger integer)
+{
+    add(hasher, static_cast<uint32_t>(integer));
+    add(hasher, static_cast<uint32_t>(integer >> 32));
+}
 
-    ALWAYS_INLINE static constexpr unsigned avalancheBits3(unsigned hash)
-    {
-        return hash ^ (hash << 10);
-    }
+template<typename SignedArithmetic> std::enable_if_t<std::is_signed<SignedArithmetic>::value, void> add(Hasher& hasher, SignedArithmetic number)
+{
+    // We overloaded for double and float below, just deal with integers here.
+    add(hasher, static_cast<std::make_unsigned_t<SignedArithmetic>>(number));
+}
 
-    ALWAYS_INLINE static constexpr unsigned avalancheBits2(unsigned hash)
-    {
-        return avalancheBits3(hash + (hash >> 15));
-    }
+inline void add(Hasher& hasher, double number)
+{
+    add(hasher, bitwise_cast<uint64_t>(number));
+}
 
-    ALWAYS_INLINE static constexpr unsigned avalancheBits1(unsigned hash)
-    {
-        return avalancheBits2(hash ^ (hash << 2));
-    }
+inline void add(Hasher& hasher, float number)
+{
+    add(hasher, bitwise_cast<uint32_t>(number));
+}
 
-    ALWAYS_INLINE static constexpr unsigned avalancheBits0(unsigned hash)
-    {
-        return avalancheBits1(hash + (hash >> 5));
-    }
+template<typename Enumeration> std::enable_if_t<std::is_enum<Enumeration>::value, void> add(Hasher& hasher, Enumeration value)
+{
+    add(hasher, static_cast<std::underlying_type_t<Enumeration>>(value));
+}
 
-    ALWAYS_INLINE static constexpr unsigned avalancheBits(unsigned hash)
-    {
-        return avalancheBits0(hash ^ (hash << 3));
-    }
+template<typename> struct TypeCheckHelper { };
+template<typename, typename = void> struct HasBeginFunctionMember : std::false_type { };
+template<typename Container> struct HasBeginFunctionMember<Container, std::conditional_t<false, TypeCheckHelper<decltype(std::declval<Container>().begin())>, void>> : std::true_type { };
 
-    // This avoids ever returning a hash code of 0, since that is used to
-    // signal "hash not computed yet". Setting the high bit maintains
-    // reasonable fidelity to a hash code of 0 because it is likely to yield
-    // exactly 0 when hash lookup masks out the high bits.
-    ALWAYS_INLINE static constexpr unsigned avoidZero(unsigned hash)
-    {
-        return hash ? hash : (0x80000000 >> StringHasher::flagCount);
-    }
+template<typename Container> std::enable_if_t<HasBeginFunctionMember<Container>::value, void> add(Hasher& hasher, const Container& container)
+{
+    for (const auto& value : container)
+        add(hasher, value);
+}
 
-    unsigned processPendingCharacter() const
-    {
-        unsigned result = m_hash;
+template<typename Tuple, std::size_t ...i> void addTupleHelper(Hasher& hasher, const Tuple& values, std::index_sequence<i...>)
+{
+    [] (...) { }((add(hasher, std::get<i>(values)), 0)...);
+}
 
-        // Handle end case.
-        if (m_hasPendingCharacter) {
-            result += m_pendingCharacter;
-            result ^= result << 11;
-            result += result >> 17;
-        }
-        return result;
-    }
+template<typename... Types> void add(Hasher& hasher, const std::tuple<Types...>& tuple)
+{
+    addTupleHelper(hasher, tuple, std::make_index_sequence<std::tuple_size<std::tuple<Types...>>::value> { });
+}
 
+template<typename T1, typename T2> void add(Hasher& hasher, const std::pair<T1, T2>& pair)
+{
+    add(hasher, pair.first);
+    add(hasher, pair.second);
+}
 
-    // FIXME: This code limits itself to the older, more limited C++11 constexpr capabilities, using
-    // recursion instead of looping, for example. Would be nice to rewrite this in a simpler way
-    // once we no longer need to support compilers like GCC 4.9 that do not yet support it.
-    static constexpr unsigned calculateWithRemainingLastCharacter1(unsigned hash)
-    {
-        return hash + (hash >> 17);
-    }
+template<typename T> void add(Hasher& hasher, const std::optional<T>& optional)
+{
+    add(hasher, optional.has_value());
+    if (optional.has_value())
+        add(hasher, optional.value());
+}
 
-    static constexpr unsigned calculateWithRemainingLastCharacter0(unsigned hash)
-    {
-        return calculateWithRemainingLastCharacter1((hash << 11) ^ hash);
-    }
+template<typename... Types> void add(Hasher& hasher, const Variant<Types...>& variant)
+{
+    add(hasher, variant.index());
+    visit([&hasher] (auto& value) {
+        add(hasher, value);
+    }, variant);
+}
 
-    static constexpr unsigned calculateWithRemainingLastCharacter(unsigned hash, unsigned character)
-    {
-        return calculateWithRemainingLastCharacter0(hash + character);
-    }
+template<typename T1, typename T2, typename... OtherTypes> void add(Hasher& hasher, const T1& value1, const T2& value2, const OtherTypes&... otherValues)
+{
+    add(hasher, value1);
+    add(hasher, value2);
+    add(hasher, std::forward_as_tuple(otherValues...));
+}
 
-    static constexpr unsigned calculate1(unsigned hash)
-    {
-        return hash + (hash >> 11);
-    }
+template<typename T> void add(Hasher& hasher, std::initializer_list<T> values)
+{
+    for (auto& value : values)
+        add(hasher, value);
+}
 
-    static constexpr unsigned calculate0(unsigned hash, unsigned secondCharacter)
-    {
-        return calculate1((hash << 16) ^ ((secondCharacter << 11) ^ hash));
-    }
-
-    static constexpr unsigned calculate(unsigned hash, unsigned firstCharacter, unsigned secondCharacter)
-    {
-        return calculate0(hash + firstCharacter, secondCharacter);
-    }
-
-    static constexpr unsigned computeLiteralHashImpl(unsigned hash, unsigned index, const char* characters, unsigned length)
-    {
-        return (index == length)
-            ? hash : ((index + 1) == length)
-            ? calculateWithRemainingLastCharacter(hash, characters[index])
-            : computeLiteralHashImpl(calculate(hash, characters[index], characters[index + 1]), index + 2, characters, length);
-    }
-
-    unsigned m_hash;
-    bool m_hasPendingCharacter;
-    UChar m_pendingCharacter;
-};
-
-class IntegerHasher {
-public:
-    void add(unsigned integer)
-    {
-        m_underlyingHasher.addCharactersAssumingAligned(integer, integer >> 16);
-    }
-
-    unsigned hash() const
-    {
-        return m_underlyingHasher.hash();
-    }
-
-private:
-    StringHasher m_underlyingHasher;
-};
-
 } // namespace WTF
 
+using WTF::computeHash;
+using WTF::Hasher;
 using WTF::IntegerHasher;
-using WTF::StringHasher;
-
-#endif // WTF_Hasher_h

Modified: trunk/Source/WTF/wtf/text/CString.cpp (225462 => 225463)


--- trunk/Source/WTF/wtf/text/CString.cpp	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/wtf/text/CString.cpp	2017-12-03 22:48:40 UTC (rev 225463)
@@ -28,7 +28,7 @@
 #include "CString.h"
 
 #include <string.h>
-#include <wtf/Hasher.h>
+#include <wtf/text/StringHasher.h>
 #include <wtf/text/StringMalloc.h>
 
 namespace WTF {

Modified: trunk/Source/WTF/wtf/text/StringHash.h (225462 => 225463)


--- trunk/Source/WTF/wtf/text/StringHash.h	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/wtf/text/StringHash.h	2017-12-03 22:48:40 UTC (rev 225463)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2008, 2012-2013, 2016 Apple Inc. All rights reserved
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved
  * Copyright (C) Research In Motion Limited 2009. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
@@ -22,9 +22,9 @@
 #ifndef StringHash_h
 #define StringHash_h
 
+#include <wtf/HashTraits.h>
 #include <wtf/text/AtomicString.h>
-#include <wtf/HashTraits.h>
-#include <wtf/Hasher.h>
+#include <wtf/text/StringHasher.h>
 
 namespace WTF {
 

Copied: trunk/Source/WTF/wtf/text/StringHasher.h (from rev 225462, trunk/Source/WTF/wtf/Hasher.h) (0 => 225463)


--- trunk/Source/WTF/wtf/text/StringHasher.h	                        (rev 0)
+++ trunk/Source/WTF/wtf/text/StringHasher.h	2017-12-03 22:48:40 UTC (rev 225463)
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Patrick Gansterer <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#pragma once
+
+#include <unicode/utypes.h>
+#include <wtf/text/LChar.h>
+
+namespace WTF {
+
+// Paul Hsieh's SuperFastHash
+// http://www.azillionmonkeys.com/qed/hash.html
+
+// LChar data is interpreted as Latin-1-encoded (zero-extended to 16 bits).
+
+// NOTE: The hash computation here must stay in sync with the create_hash_table script in
+// _javascript_Core and the CodeGeneratorJS.pm script in WebCore.
+
+// Golden ratio. Arbitrary start value to avoid mapping all zeros to a hash value of zero.
+static constexpr const unsigned stringHashingStartValue = 0x9E3779B9U;
+
+class StringHasher {
+public:
+    static constexpr const unsigned flagCount = 8; // Save 8 bits for StringImpl to use as flags.
+    static constexpr const unsigned maskHash = (1U << (sizeof(unsigned) * 8 - flagCount)) - 1;
+
+    StringHasher()
+        : m_hash(stringHashingStartValue)
+        , m_hasPendingCharacter(false)
+        , m_pendingCharacter(0)
+    {
+    }
+
+    // The hasher hashes two characters at a time, and thus an "aligned" hasher is one
+    // where an even number of characters have been added. Callers that always add
+    // characters two at a time can use the "assuming aligned" functions.
+    void addCharactersAssumingAligned(UChar a, UChar b)
+    {
+        ASSERT(!m_hasPendingCharacter);
+        m_hash += a;
+        m_hash = (m_hash << 16) ^ ((b << 11) ^ m_hash);
+        m_hash += m_hash >> 11;
+    }
+
+    void addCharacter(UChar character)
+    {
+        if (m_hasPendingCharacter) {
+            m_hasPendingCharacter = false;
+            addCharactersAssumingAligned(m_pendingCharacter, character);
+            return;
+        }
+
+        m_pendingCharacter = character;
+        m_hasPendingCharacter = true;
+    }
+
+    void addCharacters(UChar a, UChar b)
+    {
+        if (m_hasPendingCharacter) {
+#if !ASSERT_DISABLED
+            m_hasPendingCharacter = false;
+#endif
+            addCharactersAssumingAligned(m_pendingCharacter, a);
+            m_pendingCharacter = b;
+#if !ASSERT_DISABLED
+            m_hasPendingCharacter = true;
+#endif
+            return;
+        }
+
+        addCharactersAssumingAligned(a, b);
+    }
+
+    template<typename T, UChar Converter(T)> void addCharactersAssumingAligned(const T* data, unsigned length)
+    {
+        ASSERT(!m_hasPendingCharacter);
+
+        bool remainder = length & 1;
+        length >>= 1;
+
+        while (length--) {
+            addCharactersAssumingAligned(Converter(data[0]), Converter(data[1]));
+            data += 2;
+        }
+
+        if (remainder)
+            addCharacter(Converter(*data));
+    }
+
+    template<typename T> void addCharactersAssumingAligned(const T* data, unsigned length)
+    {
+        addCharactersAssumingAligned<T, defaultConverter>(data, length);
+    }
+
+    template<typename T, UChar Converter(T)> void addCharactersAssumingAligned(const T* data)
+    {
+        ASSERT(!m_hasPendingCharacter);
+
+        while (T a = *data++) {
+            T b = *data++;
+            if (!b) {
+                addCharacter(Converter(a));
+                break;
+            }
+            addCharactersAssumingAligned(Converter(a), Converter(b));
+        }
+    }
+
+    template<typename T> void addCharactersAssumingAligned(const T* data)
+    {
+        addCharactersAssumingAligned<T, defaultConverter>(data);
+    }
+
+    template<typename T, UChar Converter(T)> void addCharacters(const T* data, unsigned length)
+    {
+        if (!length)
+            return;
+        if (m_hasPendingCharacter) {
+            m_hasPendingCharacter = false;
+            addCharactersAssumingAligned(m_pendingCharacter, Converter(*data++));
+            --length;
+        }
+        addCharactersAssumingAligned<T, Converter>(data, length);
+    }
+
+    template<typename T> void addCharacters(const T* data, unsigned length)
+    {
+        addCharacters<T, defaultConverter>(data, length);
+    }
+
+    template<typename T, UChar Converter(T)> void addCharacters(const T* data)
+    {
+        if (m_hasPendingCharacter && *data) {
+            m_hasPendingCharacter = false;
+            addCharactersAssumingAligned(m_pendingCharacter, Converter(*data++));
+        }
+        addCharactersAssumingAligned<T, Converter>(data);
+    }
+
+    template<typename T> void addCharacters(const T* data)
+    {
+        addCharacters<T, defaultConverter>(data);
+    }
+
+    unsigned hashWithTop8BitsMasked() const
+    {
+        return finalizeAndMaskTop8Bits(processPendingCharacter());
+    }
+
+    unsigned hash() const
+    {
+        return finalize(processPendingCharacter());
+    }
+
+    template<typename T, UChar Converter(T)> static unsigned computeHashAndMaskTop8Bits(const T* data, unsigned length)
+    {
+        StringHasher hasher;
+        hasher.addCharactersAssumingAligned<T, Converter>(data, length);
+        return hasher.hashWithTop8BitsMasked();
+    }
+
+    template<typename T, UChar Converter(T)> static unsigned computeHashAndMaskTop8Bits(const T* data)
+    {
+        StringHasher hasher;
+        hasher.addCharactersAssumingAligned<T, Converter>(data);
+        return hasher.hashWithTop8BitsMasked();
+    }
+
+    template<typename T> static unsigned computeHashAndMaskTop8Bits(const T* data, unsigned length)
+    {
+        return computeHashAndMaskTop8Bits<T, defaultConverter>(data, length);
+    }
+
+    template<typename T> static unsigned computeHashAndMaskTop8Bits(const T* data)
+    {
+        return computeHashAndMaskTop8Bits<T, defaultConverter>(data);
+    }
+
+    template<typename T, UChar Converter(T)> static unsigned computeHash(const T* data, unsigned length)
+    {
+        StringHasher hasher;
+        hasher.addCharactersAssumingAligned<T, Converter>(data, length);
+        return hasher.hash();
+    }
+
+    template<typename T, UChar Converter(T)> static unsigned computeHash(const T* data)
+    {
+        StringHasher hasher;
+        hasher.addCharactersAssumingAligned<T, Converter>(data);
+        return hasher.hash();
+    }
+
+    template<typename T> static unsigned computeHash(const T* data, unsigned length)
+    {
+        return computeHash<T, defaultConverter>(data, length);
+    }
+
+    template<typename T> static unsigned computeHash(const T* data)
+    {
+        return computeHash<T, defaultConverter>(data);
+    }
+
+    static unsigned hashMemory(const void* data, unsigned length)
+    {
+        size_t lengthInUChar = length / sizeof(UChar);
+        StringHasher hasher;
+        hasher.addCharactersAssumingAligned(static_cast<const UChar*>(data), lengthInUChar);
+
+        for (size_t i = 0; i < length % sizeof(UChar); ++i)
+            hasher.addCharacter(static_cast<const char*>(data)[lengthInUChar * sizeof(UChar) + i]);
+
+        return hasher.hash();
+    }
+
+    template<size_t length> static unsigned hashMemory(const void* data)
+    {
+        return hashMemory(data, length);
+    }
+
+    static constexpr unsigned finalize(unsigned hash)
+    {
+        return avoidZero(avalancheBits(hash));
+    }
+
+    static constexpr unsigned finalizeAndMaskTop8Bits(unsigned hash)
+    {
+        // Reserving space from the high bits for flags preserves most of the hash's
+        // value, since hash lookup typically masks out the high bits anyway.
+        return avoidZero(avalancheBits(hash) & StringHasher::maskHash);
+    }
+
+    template<typename T, unsigned characterCount>
+    static constexpr unsigned computeLiteralHash(const T (&characters)[characterCount])
+    {
+        return StringHasher::finalize(computeLiteralHashImpl(stringHashingStartValue, 0, characters, characterCount - 1));
+    }
+
+    template<typename T, unsigned characterCount>
+    static constexpr unsigned computeLiteralHashAndMaskTop8Bits(const T (&characters)[characterCount])
+    {
+        return StringHasher::finalizeAndMaskTop8Bits(computeLiteralHashImpl(stringHashingStartValue, 0, characters, characterCount - 1));
+    }
+
+private:
+    static UChar defaultConverter(UChar character)
+    {
+        return character;
+    }
+
+    static UChar defaultConverter(LChar character)
+    {
+        return character;
+    }
+
+    ALWAYS_INLINE static constexpr unsigned avalancheBits3(unsigned hash)
+    {
+        return hash ^ (hash << 10);
+    }
+
+    ALWAYS_INLINE static constexpr unsigned avalancheBits2(unsigned hash)
+    {
+        return avalancheBits3(hash + (hash >> 15));
+    }
+
+    ALWAYS_INLINE static constexpr unsigned avalancheBits1(unsigned hash)
+    {
+        return avalancheBits2(hash ^ (hash << 2));
+    }
+
+    ALWAYS_INLINE static constexpr unsigned avalancheBits0(unsigned hash)
+    {
+        return avalancheBits1(hash + (hash >> 5));
+    }
+
+    ALWAYS_INLINE static constexpr unsigned avalancheBits(unsigned hash)
+    {
+        return avalancheBits0(hash ^ (hash << 3));
+    }
+
+    // This avoids ever returning a hash code of 0, since that is used to
+    // signal "hash not computed yet". Setting the high bit maintains
+    // reasonable fidelity to a hash code of 0 because it is likely to yield
+    // exactly 0 when hash lookup masks out the high bits.
+    ALWAYS_INLINE static constexpr unsigned avoidZero(unsigned hash)
+    {
+        return hash ? hash : (0x80000000 >> StringHasher::flagCount);
+    }
+
+    unsigned processPendingCharacter() const
+    {
+        unsigned result = m_hash;
+
+        // Handle end case.
+        if (m_hasPendingCharacter) {
+            result += m_pendingCharacter;
+            result ^= result << 11;
+            result += result >> 17;
+        }
+        return result;
+    }
+
+    // FIXME: This code limits itself to the older, more limited C++11 constexpr capabilities, using
+    // recursion instead of looping, for example. Would be nice to rewrite this in a simpler way
+    // once we no longer need to support compilers like GCC 4.9 that do not yet support it.
+    static constexpr unsigned calculateWithRemainingLastCharacter1(unsigned hash)
+    {
+        return hash + (hash >> 17);
+    }
+
+    static constexpr unsigned calculateWithRemainingLastCharacter0(unsigned hash)
+    {
+        return calculateWithRemainingLastCharacter1((hash << 11) ^ hash);
+    }
+
+    static constexpr unsigned calculateWithRemainingLastCharacter(unsigned hash, unsigned character)
+    {
+        return calculateWithRemainingLastCharacter0(hash + character);
+    }
+
+    static constexpr unsigned calculate1(unsigned hash)
+    {
+        return hash + (hash >> 11);
+    }
+
+    static constexpr unsigned calculate0(unsigned hash, unsigned secondCharacter)
+    {
+        return calculate1((hash << 16) ^ ((secondCharacter << 11) ^ hash));
+    }
+
+    static constexpr unsigned calculate(unsigned hash, unsigned firstCharacter, unsigned secondCharacter)
+    {
+        return calculate0(hash + firstCharacter, secondCharacter);
+    }
+
+    static constexpr unsigned computeLiteralHashImpl(unsigned hash, unsigned index, const char* characters, unsigned length)
+    {
+        return (index == length)
+            ? hash : ((index + 1) == length)
+            ? calculateWithRemainingLastCharacter(hash, characters[index])
+            : computeLiteralHashImpl(calculate(hash, characters[index], characters[index + 1]), index + 2, characters, length);
+    }
+
+    unsigned m_hash;
+    bool m_hasPendingCharacter;
+    UChar m_pendingCharacter;
+};
+
+} // namespace WTF
+
+using WTF::StringHasher;

Modified: trunk/Source/WTF/wtf/text/StringImpl.h (225462 => 225463)


--- trunk/Source/WTF/wtf/text/StringImpl.h	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/wtf/text/StringImpl.h	2017-12-03 22:48:40 UTC (rev 225463)
@@ -27,8 +27,6 @@
 #include <unicode/ustring.h>
 #include <wtf/ASCIICType.h>
 #include <wtf/CheckedArithmetic.h>
-#include <wtf/Forward.h>
-#include <wtf/Hasher.h>
 #include <wtf/MathExtras.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/Vector.h>
@@ -35,7 +33,7 @@
 #include <wtf/text/ASCIIFastPath.h>
 #include <wtf/text/ConversionMode.h>
 #include <wtf/text/StringCommon.h>
-#include <wtf/text/StringMalloc.h>
+#include <wtf/text/StringHasher.h>
 #include <wtf/text/StringVector.h>
 
 #if USE(CF)

Modified: trunk/Source/WTF/wtf/text/WTFString.h (225462 => 225463)


--- trunk/Source/WTF/wtf/text/WTFString.h	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/wtf/text/WTFString.h	2017-12-03 22:48:40 UTC (rev 225463)
@@ -357,6 +357,7 @@
     String(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { }
     bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); }
 
+    unsigned hash() const { return isNull() ? 0 : impl()->hash(); }
     unsigned existingHash() const { return isNull() ? 0 : impl()->existingHash(); }
 
 #ifndef NDEBUG

Modified: trunk/Source/WTF/wtf/unicode/UTF8.cpp (225462 => 225463)


--- trunk/Source/WTF/wtf/unicode/UTF8.cpp	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Source/WTF/wtf/unicode/UTF8.cpp	2017-12-03 22:48:40 UTC (rev 225463)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, 2014 Apple Inc.  All rights reserved.
+ * Copyright (C) 2007, 2014 Apple Inc. All rights reserved.
  * Copyright (C) 2010 Patrick Gansterer <[email protected]>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
 #include "UTF8.h"
 
 #include "ASCIICType.h"
-#include <wtf/Hasher.h>
+#include <wtf/text/StringHasher.h>
 #include <wtf/unicode/CharacterNames.h>
 
 namespace WTF {

Modified: trunk/Tools/ChangeLog (225462 => 225463)


--- trunk/Tools/ChangeLog	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Tools/ChangeLog	2017-12-03 22:48:40 UTC (rev 225463)
@@ -1,3 +1,19 @@
+2017-12-03  Darin Adler  <[email protected]>
+
+        Add WTF::Hasher, an easier to use replacement for WTF::IntegerHasher
+        https://bugs.webkit.org/show_bug.cgi?id=180318
+
+        Reviewed by JF Bastien.
+
+        * TestWebKitAPI/CMakeLists.txt: Added Hasher.cpp.
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Ditto.
+
+        * TestWebKitAPI/Tests/WTF/Hasher.cpp: Added. Contains tests of the new
+        WTF::Hasher class.
+
+        * TestWebKitAPI/Tests/WTF/StringHasher.cpp: Include StringHasher.h instead of
+        Hasher.h.
+
 2017-12-01  Carlos Garcia Campos  <[email protected]>
 
         WebDriver: auto-install pytest instead of importing it from wpt tools directory

Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (225462 => 225463)


--- trunk/Tools/TestWebKitAPI/CMakeLists.txt	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt	2017-12-03 22:48:40 UTC (rev 225463)
@@ -103,6 +103,7 @@
     ${TESTWEBKITAPI_DIR}/Tests/WTF/HashCountedSet.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/HashMap.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/HashSet.cpp
+    ${TESTWEBKITAPI_DIR}/Tests/WTF/Hasher.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/IntegerToStringConversion.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/JSONValue.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/LEBDecoder.cpp

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (225462 => 225463)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-12-03 22:48:40 UTC (rev 225463)
@@ -532,6 +532,7 @@
 		9310CD381EF708FB0050FFE0 /* Function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9310CD361EF708FB0050FFE0 /* Function.cpp */; };
 		9329AA291DE3F81E003ABD07 /* TextBreakIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9329AA281DE3F81E003ABD07 /* TextBreakIterator.cpp */; };
 		932AE53D1D371047005DFFAF /* focus-inputs.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 93575C551D30366E000D604D /* focus-inputs.html */; };
+		933D631D1FCB76200032ECD6 /* Hasher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 933D631B1FCB76180032ECD6 /* Hasher.cpp */; };
 		9361002914DC95A70061379D /* lots-of-iframes.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9361002814DC957B0061379D /* lots-of-iframes.html */; };
 		93625D271CD9741C006DC1F1 /* large-video-without-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 93625D261CD973AF006DC1F1 /* large-video-without-audio.html */; };
 		936F72801CD7D9EC0068A0FB /* large-video-with-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 936F727E1CD7D9D00068A0FB /* large-video-with-audio.html */; };
@@ -1494,6 +1495,7 @@
 		9310CD361EF708FB0050FFE0 /* Function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Function.cpp; sourceTree = "<group>"; };
 		9329AA281DE3F81E003ABD07 /* TextBreakIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextBreakIterator.cpp; sourceTree = "<group>"; };
 		9331407B17B4419000F083B1 /* DidNotHandleKeyDown.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DidNotHandleKeyDown.cpp; sourceTree = "<group>"; };
+		933D631B1FCB76180032ECD6 /* Hasher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Hasher.cpp; sourceTree = "<group>"; };
 		93575C551D30366E000D604D /* focus-inputs.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "focus-inputs.html"; sourceTree = "<group>"; };
 		9361002814DC957B0061379D /* lots-of-iframes.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "lots-of-iframes.html"; sourceTree = "<group>"; };
 		93625D261CD973AF006DC1F1 /* large-video-without-audio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-video-without-audio.html"; sourceTree = "<group>"; };
@@ -2604,6 +2606,7 @@
 				9310CD361EF708FB0050FFE0 /* Function.cpp */,
 				83DB79671EF63B3C00BFA5E5 /* Function.cpp */,
 				7A38D7E51C752D5F004F157D /* HashCountedSet.cpp */,
+				933D631B1FCB76180032ECD6 /* Hasher.cpp */,
 				0BCD833414857CE400EA2003 /* HashMap.cpp */,
 				26B2DFF815BDE599004F691D /* HashSet.cpp */,
 				266FAFD215E5775200F61D5B /* IntegerToStringConversion.cpp */,
@@ -3164,6 +3167,7 @@
 				AD7C434D1DD2A54E0026888B /* Expected.cpp in Sources */,
 				9310CD381EF708FB0050FFE0 /* Function.cpp in Sources */,
 				6BFD294C1D5E6C1D008EC968 /* HashCountedSet.cpp in Sources */,
+				933D631D1FCB76200032ECD6 /* Hasher.cpp in Sources */,
 				7C83DED21D0A590C00FEBCF3 /* HashMap.cpp in Sources */,
 				7C83DED41D0A590C00FEBCF3 /* HashSet.cpp in Sources */,
 				7C83DEE01D0A590C00FEBCF3 /* IntegerToStringConversion.cpp in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WTF/Hasher.cpp (0 => 225463)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/Hasher.cpp	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/Hasher.cpp	2017-12-03 22:48:40 UTC (rev 225463)
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <array>
+#include <limits>
+#include <wtf/Hasher.h>
+#include <wtf/Optional.h>
+#include <wtf/Vector.h>
+
+namespace TestWebKitAPI {
+
+// Test against actual hash values.
+// We don't really depend on specific values, but it makes testing simpler.
+// Could instead construct tests that check hashes against each other.
+// No big deal to update all of these if we change the hash algorithm.
+
+const uint32_t emptyHash = 82610334U;
+const uint32_t zero32BitHash = 242183504U;
+const uint32_t zero64BitHash = 579236260U;
+const uint32_t _one32BitHash_ = 690138192U;
+const uint32_t _one64BitHash_ = 1621454911U;
+
+TEST(WTF, Hasher_integer)
+{
+    EXPECT_EQ(zero32BitHash, computeHash(0U));
+    EXPECT_EQ(zero32BitHash, computeHash(false));
+    EXPECT_EQ(zero32BitHash, computeHash(static_cast<char>(0)));
+    EXPECT_EQ(zero32BitHash, computeHash(static_cast<int8_t>(0)));
+    EXPECT_EQ(zero32BitHash, computeHash(static_cast<uint8_t>(0)));
+    EXPECT_EQ(zero32BitHash, computeHash(static_cast<int16_t>(0)));
+    EXPECT_EQ(zero32BitHash, computeHash(static_cast<uint16_t>(0)));
+    EXPECT_EQ(zero32BitHash, computeHash(0));
+
+    EXPECT_EQ(zero64BitHash, computeHash(0ULL));
+    EXPECT_EQ(zero64BitHash, computeHash(0L));
+    EXPECT_EQ(zero64BitHash, computeHash(0UL));
+    EXPECT_EQ(zero64BitHash, computeHash(0LL));
+
+    EXPECT_EQ(one32BitHash, computeHash(1U));
+    EXPECT_EQ(one32BitHash, computeHash(true));
+    EXPECT_EQ(one32BitHash, computeHash(static_cast<char>(1)));
+    EXPECT_EQ(one32BitHash, computeHash(static_cast<int8_t>(1)));
+    EXPECT_EQ(one32BitHash, computeHash(static_cast<uint8_t>(1)));
+    EXPECT_EQ(one32BitHash, computeHash(static_cast<int16_t>(1)));
+    EXPECT_EQ(one32BitHash, computeHash(static_cast<uint16_t>(1)));
+    EXPECT_EQ(one32BitHash, computeHash(1));
+
+    EXPECT_EQ(one64BitHash, computeHash(1ULL));
+    EXPECT_EQ(one64BitHash, computeHash(1L));
+    EXPECT_EQ(one64BitHash, computeHash(1UL));
+    EXPECT_EQ(one64BitHash, computeHash(1LL));
+
+    EXPECT_EQ(1772381661U, computeHash(0x7FU));
+    EXPECT_EQ(1772381661U, computeHash(std::numeric_limits<int8_t>::max()));
+
+    EXPECT_EQ(3730877340U, computeHash(0x80U));
+    EXPECT_EQ(3730877340U, computeHash(std::numeric_limits<int8_t>::min()));
+
+    EXPECT_EQ(376510634U, computeHash(0xFFU));
+    EXPECT_EQ(376510634U, computeHash(std::numeric_limits<uint8_t>::max()));
+    EXPECT_EQ(376510634U, computeHash(static_cast<char>(-1)));
+    EXPECT_EQ(376510634U, computeHash(static_cast<int8_t>(-1)));
+
+    EXPECT_EQ(262632278U, computeHash(0x7FFFU));
+    EXPECT_EQ(262632278U, computeHash(std::numeric_limits<int16_t>::max()));
+
+    EXPECT_EQ(2981978661U, computeHash(0x8000U));
+    EXPECT_EQ(2981978661U, computeHash(std::numeric_limits<int16_t>::min()));
+
+    EXPECT_EQ(894984179U, computeHash(0xFFFFU));
+    EXPECT_EQ(894984179U, computeHash(std::numeric_limits<uint16_t>::max()));
+    EXPECT_EQ(894984179U, computeHash(static_cast<int16_t>(-1)));
+
+    EXPECT_EQ(3430670328U, computeHash(0x7FFFFFFFU));
+    EXPECT_EQ(3430670328U, computeHash(std::numeric_limits<int32_t>::max()));
+
+    EXPECT_EQ(2425683428U, computeHash(0x80000000U));
+    EXPECT_EQ(2425683428U, computeHash(std::numeric_limits<int32_t>::min()));
+
+    EXPECT_EQ(1955511435U, computeHash(0xFFFFFFFFU));
+    EXPECT_EQ(1955511435U, computeHash(std::numeric_limits<uint32_t>::max()));
+    EXPECT_EQ(1955511435U, computeHash(-1));
+
+    EXPECT_EQ(1264532604U, computeHash(0x8000000000000000ULL));
+    EXPECT_EQ(1264532604U, computeHash(std::numeric_limits<int64_t>::min()));
+    EXPECT_EQ(1264532604U, computeHash(std::numeric_limits<long>::min()));
+
+    EXPECT_EQ(2961049834U, computeHash(0x7FFFFFFFFFFFFFFFULL));
+    EXPECT_EQ(2961049834U, computeHash(std::numeric_limits<int64_t>::max()));
+    EXPECT_EQ(2961049834U, computeHash(std::numeric_limits<long>::max()));
+
+    EXPECT_EQ(1106332091U, computeHash(0xFFFFFFFFFFFFFFFFULL));
+    EXPECT_EQ(1106332091U, computeHash(std::numeric_limits<uint64_t>::max()));
+    EXPECT_EQ(1106332091U, computeHash(std::numeric_limits<unsigned long>::max()));
+    EXPECT_EQ(1106332091U, computeHash(-1L));
+    EXPECT_EQ(1106332091U, computeHash(-1LL));
+}
+
+TEST(WTF, Hasher_floatingPoint)
+{
+    EXPECT_EQ(zero64BitHash, computeHash(0.0));
+    EXPECT_EQ(1264532604U, computeHash(-0.0)); // Note, not same as hash of 0.0.
+    EXPECT_EQ(one64BitHash, computeHash(std::numeric_limits<double>::denorm_min()));
+
+    EXPECT_EQ(2278399980U, computeHash(1.0));
+    EXPECT_EQ(3870689297U, computeHash(-1.0));
+
+    EXPECT_EQ(3016344414U, computeHash(std::numeric_limits<double>::min()));
+    EXPECT_EQ(1597662982U, computeHash(std::numeric_limits<double>::max()));
+
+    EXPECT_EQ(2501702556U, computeHash(std::numeric_limits<double>::lowest()));
+    EXPECT_EQ(2214439802U, computeHash(std::numeric_limits<double>::epsilon()));
+
+    EXPECT_EQ(2678086759U, computeHash(std::numeric_limits<double>::quiet_NaN()));
+    EXPECT_EQ(2304445393U, computeHash(std::numeric_limits<double>::infinity()));
+    EXPECT_EQ(2232593311U, computeHash(-std::numeric_limits<double>::infinity()));
+
+    EXPECT_EQ(zero32BitHash, computeHash(0.0f));
+    EXPECT_EQ(2425683428U, computeHash(-0.0f)); // Note, not same as hash of 0.0f.
+    EXPECT_EQ(one32BitHash, computeHash(std::numeric_limits<float>::denorm_min()));
+
+    EXPECT_EQ(1081575966U, computeHash(1.0f));
+    EXPECT_EQ(3262093188U, computeHash(-1.0f));
+
+    EXPECT_EQ(3170189524U, computeHash(std::numeric_limits<float>::min()));
+    EXPECT_EQ(11021299U, computeHash(std::numeric_limits<float>::max()));
+
+    EXPECT_EQ(3212069506U, computeHash(std::numeric_limits<float>::lowest()));
+    EXPECT_EQ(1308784506U, computeHash(std::numeric_limits<float>::epsilon()));
+
+    EXPECT_EQ(2751288511U, computeHash(std::numeric_limits<float>::quiet_NaN()));
+    EXPECT_EQ(3457049256U, computeHash(std::numeric_limits<float>::infinity()));
+    EXPECT_EQ(4208873971U, computeHash(-std::numeric_limits<float>::infinity()));
+}
+
+TEST(WTF, Hasher_multiple)
+{
+    EXPECT_EQ(emptyHash, computeHash());
+    EXPECT_EQ(emptyHash, computeHash(std::make_tuple()));
+    EXPECT_EQ(emptyHash, computeHash(std::array<int, 0> { }));
+    EXPECT_EQ(emptyHash, computeHash(Vector<int> { }));
+    EXPECT_EQ(emptyHash, computeHash(Vector<int, 1> { }));
+
+    EXPECT_EQ(zero32BitHash, computeHash(std::array<int, 1> { { 0 } }));
+    EXPECT_EQ(zero32BitHash, computeHash(Vector<int> { 0 }));
+    EXPECT_EQ(zero32BitHash, computeHash(Vector<int, 1> { 0 }));
+    EXPECT_EQ(zero32BitHash, computeHash(std::optional<int> { std::nullopt }));
+
+    EXPECT_EQ(one64BitHash, computeHash(1, 0));
+    EXPECT_EQ(one64BitHash, computeHash(std::make_tuple(1, 0)));
+    EXPECT_EQ(one64BitHash, computeHash(std::make_pair(1, 0)));
+    EXPECT_EQ(one64BitHash, computeHash(std::array<int, 2> { { 1, 0 } }));
+    EXPECT_EQ(one64BitHash, computeHash({ 1, 0 }));
+    EXPECT_EQ(one64BitHash, computeHash(std::optional<int> { 0 }));
+    EXPECT_EQ(one64BitHash, computeHash(Vector<int> { { 1, 0 } }));
+    EXPECT_EQ(one64BitHash, computeHash(Vector<int, 1> { { 1, 0 } }));
+
+    EXPECT_EQ(one64BitHash, computeHash(std::make_tuple(1), std::array<int, 1> { { 0 } }));
+    EXPECT_EQ(one64BitHash, computeHash(std::make_tuple(std::make_tuple(1), std::array<int, 1> { { 0 } })));
+
+    EXPECT_EQ(1652352321U, computeHash(1, 2, 3, 4));
+    EXPECT_EQ(1652352321U, computeHash(std::make_tuple(1, 2, 3, 4)));
+    EXPECT_EQ(1652352321U, computeHash(std::make_pair(std::make_pair(1, 2), std::make_pair(3, 4))));
+}
+
+struct HasherAddCustom1 { };
+
+void add(Hasher& hasher, const HasherAddCustom1&)
+{
+    add(hasher, 1, 2, 3, 4);
+}
+
+struct HasherAddCustom2 { };
+
+void add(Hasher& hasher, const HasherAddCustom2&)
+{
+    add(hasher, { 1, 2, 3, 4 });
+}
+
+TEST(WTF, Hasher_custom)
+{
+    EXPECT_EQ(1652352321U, computeHash(HasherAddCustom1 { }));
+    EXPECT_EQ(1652352321U, computeHash(HasherAddCustom2 { }));
+}
+
+#if 0 // FIXME: Add support for tuple-like classes.
+
+struct HasherAddTupleLikeClass1 {
+    std::array<int, 4> array { { 1, 2, 3, 4 } };
+    template<size_t i> int get() const { return std::get<i>(array); }
+};
+
+struct HasherAddTupleLikeClass2 {
+    std::array<int, 4> array { { 1, 2, 3, 4 } };
+};
+
+}
+
+namespace std {
+
+// FIXME: Documentation at cppreference.cpp says std::tuple_size is a struct, but it's a class in current macOS tools.
+// FIXME: It's inelegant to inject this into the std namespace. Is that really how a tuple-like class needs to be defined?
+// FIXME: This is so inconvenient that I am not sure it's something we want to do for lots of classes in WebKit.
+template<> class std::tuple_size<TestWebKitAPI::HasherAddTupleLikeClass1> : public std::integral_constant<size_t, std::tuple_size<decltype(TestWebKitAPI::HasherAddTupleLikeClass1::array)>::value> { };
+
+template<> class std::tuple_size<TestWebKitAPI::HasherAddTupleLikeClass2> : public std::integral_constant<size_t, std::tuple_size<decltype(TestWebKitAPI::HasherAddTupleLikeClass2::array)>::value> { };
+
+}
+
+namespace TestWebKitAPI {
+
+// FIXME: Is it OK for the get to be in the class's namespace and rely on argument-dependent lookup?
+// Or does this function template need to be moved into the std namespace like the tuple_size specialization?
+template<size_t i> int get(const HasherAddTupleLikeClass2& object)
+{
+    return get<i>(object.array);
+}
+
+TEST(WTF, Hasher_tupleLike)
+{
+    EXPECT_EQ(1652352321U, computeHash(HasherAddTupleLikeClass1 { }));
+    EXPECT_EQ(1652352321U, computeHash(HasherAddTupleLikeClass2 { }));
+}
+
+#endif
+
+} // namespace TestWebKitAPI
Property changes on: trunk/Tools/TestWebKitAPI/Tests/WTF/Hasher.cpp
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp (225462 => 225463)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp	2017-12-03 22:24:45 UTC (rev 225462)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp	2017-12-03 22:48:40 UTC (rev 225463)
@@ -25,7 +25,7 @@
 
 #include "config.h"
 
-#include <wtf/Hasher.h>
+#include <wtf/text/StringHasher.h>
 
 namespace TestWebKitAPI {
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to