/* * Copyright (C) 2016-2021 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 * 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 #include #include #include #include namespace WTF { template uint32_t computeHash(const Types&...); template uint32_t computeHash(std::initializer_list, std::initializer_list...); template std::enable_if_t::value && sizeof(UnsignedInteger) <= sizeof(uint32_t), void> add(Hasher&, UnsignedInteger); class Hasher { WTF_MAKE_FAST_ALLOCATED; public: template friend uint32_t computeHash(const Types&... values) { Hasher hasher; addArgs(hasher, values...); return hasher.m_underlyingHasher.hash(); } template friend uint32_t computeHash(std::initializer_list list, std::initializer_list... otherLists) { Hasher hasher; add(hasher, list); addArgs(hasher, otherLists...); return hasher.m_underlyingHasher.hash(); } template friend std::enable_if_t::value && sizeof(UnsignedInteger) <= sizeof(uint32_t), void> add(Hasher& hasher, UnsignedInteger integer) { // 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); } unsigned hash() const { return m_underlyingHasher.hash(); } private: StringHasher m_underlyingHasher; }; template std::enable_if_t::value && sizeof(UnsignedInteger) == sizeof(uint64_t), void> add(Hasher& hasher, UnsignedInteger integer) { add(hasher, static_cast(integer)); add(hasher, static_cast(integer >> 32)); } template std::enable_if_t::value, void> add(Hasher& hasher, SignedArithmetic number) { // We overloaded for double and float below, just deal with integers here. add(hasher, static_cast>(number)); } inline void add(Hasher& hasher, bool boolean) { add(hasher, static_cast(boolean)); } inline void add(Hasher& hasher, double number) { add(hasher, bitwise_cast(number)); } inline void add(Hasher& hasher, float number) { add(hasher, bitwise_cast(number)); } inline void add(Hasher& hasher, const String& string) { // Chose to hash the characters here. Assuming this is better than hashing the possibly-already-computed hash of the characters. bool remainder = string.length() & 1; unsigned roundedLength = string.length() - remainder; for (unsigned i = 0; i < roundedLength; i += 2) add(hasher, (string[i] << 16) | string[i + 1]); if (remainder) add(hasher, string[roundedLength]); } inline void add(Hasher& hasher, const AtomString& string) { // Chose to hash the pointer here. Assuming this is better than hashing the characters or hashing the already-computed hash of the characters. add(hasher, bitwise_cast(string.impl())); } inline void add(Hasher& hasher, const URL& url) { add(hasher, url.string()); } template std::enable_if_t::value, void> add(Hasher& hasher, Enumeration value) { add(hasher, static_cast>(value)); } template inline constexpr bool HasBeginFunctionMember = false; template inline constexpr bool HasBeginFunctionMember().begin())>> = true; template std::enable_if_t && !IsTypeComplete>, void> add(Hasher& hasher, const Container& container) { for (const auto& value : container) add(hasher, value); } inline void addArgs(Hasher&) { } template void addArgs(Hasher& hasher, const Arg& arg, const Args&... args) { add(hasher, arg); addArgs(hasher, args...); } template inline constexpr bool HasGetFunctionMember = false; template inline constexpr bool HasGetFunctionMember().template get<0>())>> = true; template void addTupleLikeHelper(Hasher& hasher, const TupleLike& tupleLike, std::index_sequence) { if constexpr (HasGetFunctionMember) addArgs(hasher, tupleLike.template get()...); else { using std::get; addArgs(hasher, get(tupleLike)...); } } template std::enable_if_t>, void> add(Hasher& hasher, const TupleLike& tuple) { addTupleLikeHelper(hasher, tuple, std::make_index_sequence::value> { }); } template void add(Hasher& hasher, const std::optional& optional) { add(hasher, optional.has_value()); if (optional.has_value()) add(hasher, optional.value()); } template void add(Hasher& hasher, const Variant& variant) { add(hasher, variant.index()); visit([&hasher] (auto& value) { add(hasher, value); }, variant); } template void add(Hasher& hasher, const T1& value1, const T2& value2, const OtherTypes&... otherValues) { add(hasher, value1); add(hasher, value2); addArgs(hasher, otherValues...); } template void add(Hasher& hasher, std::initializer_list values) { for (auto& value : values) add(hasher, value); } } // namespace WTF using WTF::computeHash; using WTF::Hasher;