1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include <array>
29#include <limits>
30#include <wtf/Hasher.h>
31#include <wtf/Optional.h>
32#include <wtf/Vector.h>
33
34namespace TestWebKitAPI {
35
36// Test against actual hash values.
37// We don't really depend on specific values, but it makes testing simpler.
38// Could instead construct tests that check hashes against each other.
39// No big deal to update all of these if we change the hash algorithm.
40
41const uint32_t emptyHash = 82610334U;
42const uint32_t zero32BitHash = 242183504U;
43const uint32_t zero64BitHash = 579236260U;
44const uint32_t one32BitHash = 690138192U;
45const uint32_t one64BitHash = 1621454911U;
46
47TEST(WTF, Hasher_integer)
48{
49 EXPECT_EQ(zero32BitHash, computeHash(0U));
50 EXPECT_EQ(zero32BitHash, computeHash(false));
51 EXPECT_EQ(zero32BitHash, computeHash(static_cast<char>(0)));
52 EXPECT_EQ(zero32BitHash, computeHash(static_cast<int8_t>(0)));
53 EXPECT_EQ(zero32BitHash, computeHash(static_cast<uint8_t>(0)));
54 EXPECT_EQ(zero32BitHash, computeHash(static_cast<int16_t>(0)));
55 EXPECT_EQ(zero32BitHash, computeHash(static_cast<uint16_t>(0)));
56 EXPECT_EQ(zero32BitHash, computeHash(0));
57
58 EXPECT_EQ(zero64BitHash, computeHash(0ULL));
59 EXPECT_EQ(sizeof(long) == sizeof(int32_t) ? zero32BitHash : zero64BitHash, computeHash(0L));
60 EXPECT_EQ(sizeof(unsigned long) == sizeof(uint32_t) ? zero32BitHash : zero64BitHash, computeHash(0UL));
61 EXPECT_EQ(zero64BitHash, computeHash(0LL));
62
63 EXPECT_EQ(one32BitHash, computeHash(1U));
64 EXPECT_EQ(one32BitHash, computeHash(true));
65 EXPECT_EQ(one32BitHash, computeHash(static_cast<char>(1)));
66 EXPECT_EQ(one32BitHash, computeHash(static_cast<int8_t>(1)));
67 EXPECT_EQ(one32BitHash, computeHash(static_cast<uint8_t>(1)));
68 EXPECT_EQ(one32BitHash, computeHash(static_cast<int16_t>(1)));
69 EXPECT_EQ(one32BitHash, computeHash(static_cast<uint16_t>(1)));
70 EXPECT_EQ(one32BitHash, computeHash(1));
71
72 EXPECT_EQ(one64BitHash, computeHash(1ULL));
73 EXPECT_EQ(sizeof(long) == sizeof(int32_t) ? one32BitHash : one64BitHash, computeHash(1L));
74 EXPECT_EQ(sizeof(unsigned long) == sizeof(uint32_t) ? one32BitHash : one64BitHash, computeHash(1UL));
75 EXPECT_EQ(one64BitHash, computeHash(1LL));
76
77 EXPECT_EQ(1772381661U, computeHash(0x7FU));
78 EXPECT_EQ(1772381661U, computeHash(std::numeric_limits<int8_t>::max()));
79
80 EXPECT_EQ(3730877340U, computeHash(0x80U));
81 EXPECT_EQ(3730877340U, computeHash(std::numeric_limits<int8_t>::min()));
82
83 EXPECT_EQ(376510634U, computeHash(0xFFU));
84 EXPECT_EQ(376510634U, computeHash(std::numeric_limits<uint8_t>::max()));
85 EXPECT_EQ(376510634U, computeHash(static_cast<char>(-1)));
86 EXPECT_EQ(376510634U, computeHash(static_cast<int8_t>(-1)));
87
88 EXPECT_EQ(262632278U, computeHash(0x7FFFU));
89 EXPECT_EQ(262632278U, computeHash(std::numeric_limits<int16_t>::max()));
90
91 EXPECT_EQ(2981978661U, computeHash(0x8000U));
92 EXPECT_EQ(2981978661U, computeHash(std::numeric_limits<int16_t>::min()));
93
94 EXPECT_EQ(894984179U, computeHash(0xFFFFU));
95 EXPECT_EQ(894984179U, computeHash(std::numeric_limits<uint16_t>::max()));
96 EXPECT_EQ(894984179U, computeHash(static_cast<int16_t>(-1)));
97
98 EXPECT_EQ(3430670328U, computeHash(0x7FFFFFFFU));
99 EXPECT_EQ(3430670328U, computeHash(std::numeric_limits<int32_t>::max()));
100
101 EXPECT_EQ(2425683428U, computeHash(0x80000000U));
102 EXPECT_EQ(2425683428U, computeHash(std::numeric_limits<int32_t>::min()));
103
104 EXPECT_EQ(1955511435U, computeHash(0xFFFFFFFFU));
105 EXPECT_EQ(1955511435U, computeHash(std::numeric_limits<uint32_t>::max()));
106 EXPECT_EQ(1955511435U, computeHash(-1));
107
108 EXPECT_EQ(1264532604U, computeHash(0x8000000000000000ULL));
109 EXPECT_EQ(1264532604U, computeHash(std::numeric_limits<int64_t>::min()));
110 EXPECT_EQ(sizeof(long) == sizeof(int32_t) ? 2425683428U : 1264532604U, computeHash(std::numeric_limits<long>::min()));
111
112 EXPECT_EQ(2961049834U, computeHash(0x7FFFFFFFFFFFFFFFULL));
113 EXPECT_EQ(2961049834U, computeHash(std::numeric_limits<int64_t>::max()));
114 EXPECT_EQ(sizeof(long) == sizeof(int32_t) ? 3430670328U : 2961049834U, computeHash(std::numeric_limits<long>::max()));
115
116 EXPECT_EQ(1106332091U, computeHash(0xFFFFFFFFFFFFFFFFULL));
117 EXPECT_EQ(1106332091U, computeHash(std::numeric_limits<uint64_t>::max()));
118 EXPECT_EQ(sizeof(long) == sizeof(int32_t) ? 1955511435U : 1106332091U, computeHash(std::numeric_limits<unsigned long>::max()));
119 EXPECT_EQ(sizeof(long) == sizeof(int32_t) ? 1955511435U : 1106332091U, computeHash(-1L));
120 EXPECT_EQ(1106332091U, computeHash(-1LL));
121}
122
123TEST(WTF, Hasher_floatingPoint)
124{
125 EXPECT_EQ(zero64BitHash, computeHash(0.0));
126 EXPECT_EQ(1264532604U, computeHash(-0.0)); // Note, not same as hash of 0.0.
127 EXPECT_EQ(one64BitHash, computeHash(std::numeric_limits<double>::denorm_min()));
128
129 EXPECT_EQ(2278399980U, computeHash(1.0));
130 EXPECT_EQ(3870689297U, computeHash(-1.0));
131
132 EXPECT_EQ(3016344414U, computeHash(std::numeric_limits<double>::min()));
133 EXPECT_EQ(1597662982U, computeHash(std::numeric_limits<double>::max()));
134
135 EXPECT_EQ(2501702556U, computeHash(std::numeric_limits<double>::lowest()));
136 EXPECT_EQ(2214439802U, computeHash(std::numeric_limits<double>::epsilon()));
137
138 EXPECT_EQ(2678086759U, computeHash(std::numeric_limits<double>::quiet_NaN()));
139 EXPECT_EQ(2304445393U, computeHash(std::numeric_limits<double>::infinity()));
140 EXPECT_EQ(2232593311U, computeHash(-std::numeric_limits<double>::infinity()));
141
142 EXPECT_EQ(zero32BitHash, computeHash(0.0f));
143 EXPECT_EQ(2425683428U, computeHash(-0.0f)); // Note, not same as hash of 0.0f.
144 EXPECT_EQ(one32BitHash, computeHash(std::numeric_limits<float>::denorm_min()));
145
146 EXPECT_EQ(1081575966U, computeHash(1.0f));
147 EXPECT_EQ(3262093188U, computeHash(-1.0f));
148
149 EXPECT_EQ(3170189524U, computeHash(std::numeric_limits<float>::min()));
150 EXPECT_EQ(11021299U, computeHash(std::numeric_limits<float>::max()));
151
152 EXPECT_EQ(3212069506U, computeHash(std::numeric_limits<float>::lowest()));
153 EXPECT_EQ(1308784506U, computeHash(std::numeric_limits<float>::epsilon()));
154
155 EXPECT_EQ(2751288511U, computeHash(std::numeric_limits<float>::quiet_NaN()));
156 EXPECT_EQ(3457049256U, computeHash(std::numeric_limits<float>::infinity()));
157 EXPECT_EQ(4208873971U, computeHash(-std::numeric_limits<float>::infinity()));
158}
159
160TEST(WTF, Hasher_multiple)
161{
162 EXPECT_EQ(emptyHash, computeHash());
163 EXPECT_EQ(emptyHash, computeHash(std::make_tuple()));
164 EXPECT_EQ(emptyHash, computeHash(std::array<int, 0> { }));
165 EXPECT_EQ(emptyHash, computeHash(Vector<int> { }));
166 EXPECT_EQ(emptyHash, computeHash(Vector<int, 1> { }));
167
168 EXPECT_EQ(zero32BitHash, computeHash(std::array<int, 1> { { 0 } }));
169 EXPECT_EQ(zero32BitHash, computeHash(Vector<int> { 0 }));
170 EXPECT_EQ(zero32BitHash, computeHash(Vector<int, 1> { 0 }));
171 EXPECT_EQ(zero32BitHash, computeHash(Optional<int> { WTF::nullopt }));
172 EXPECT_EQ(zero32BitHash, computeHash(std::make_tuple(0)));
173
174 EXPECT_EQ(one64BitHash, computeHash(1, 0));
175 EXPECT_EQ(one64BitHash, computeHash(std::make_tuple(1, 0)));
176 EXPECT_EQ(one64BitHash, computeHash(std::make_pair(1, 0)));
177 EXPECT_EQ(one64BitHash, computeHash(std::array<int, 2> { { 1, 0 } }));
178 EXPECT_EQ(one64BitHash, computeHash({ 1, 0 }));
179 EXPECT_EQ(one64BitHash, computeHash(Optional<int> { 0 }));
180 EXPECT_EQ(one64BitHash, computeHash(Vector<int> { { 1, 0 } }));
181 EXPECT_EQ(one64BitHash, computeHash(Vector<int, 1> { { 1, 0 } }));
182
183 EXPECT_EQ(one64BitHash, computeHash(std::make_tuple(1), std::array<int, 1> { { 0 } }));
184 EXPECT_EQ(one64BitHash, computeHash(std::make_tuple(std::make_tuple(1), std::array<int, 1> { { 0 } })));
185
186 EXPECT_EQ(1652352321U, computeHash(1, 2, 3, 4));
187 EXPECT_EQ(1652352321U, computeHash(std::make_tuple(1, 2, 3, 4)));
188 EXPECT_EQ(1652352321U, computeHash(std::make_pair(std::make_pair(1, 2), std::make_pair(3, 4))));
189}
190
191struct HasherAddCustom1 { };
192
193void add(Hasher& hasher, const HasherAddCustom1&)
194{
195 add(hasher, 1, 2, 3, 4);
196}
197
198struct HasherAddCustom2 { };
199
200void add(Hasher& hasher, const HasherAddCustom2&)
201{
202 add(hasher, { 1, 2, 3, 4 });
203}
204
205TEST(WTF, Hasher_custom)
206{
207 EXPECT_EQ(1652352321U, computeHash(HasherAddCustom1 { }));
208 EXPECT_EQ(1652352321U, computeHash(HasherAddCustom2 { }));
209}
210
211#if 0 // FIXME: Add support for tuple-like classes.
212
213struct HasherAddTupleLikeClass1 {
214 std::array<int, 4> array { { 1, 2, 3, 4 } };
215 template<size_t i> int get() const { return std::get<i>(array); }
216};
217
218struct HasherAddTupleLikeClass2 {
219 std::array<int, 4> array { { 1, 2, 3, 4 } };
220};
221
222}
223
224namespace std {
225
226// FIXME: Documentation at cppreference.cpp says std::tuple_size is a struct, but it's a class in current macOS tools.
227// FIXME: It's inelegant to inject this into the std namespace. Is that really how a tuple-like class needs to be defined?
228// FIXME: This is so inconvenient that I am not sure it's something we want to do for lots of classes in WebKit.
229template<> class std::tuple_size<TestWebKitAPI::HasherAddTupleLikeClass1> : public std::integral_constant<size_t, std::tuple_size<decltype(TestWebKitAPI::HasherAddTupleLikeClass1::array)>::value> { };
230
231template<> class std::tuple_size<TestWebKitAPI::HasherAddTupleLikeClass2> : public std::integral_constant<size_t, std::tuple_size<decltype(TestWebKitAPI::HasherAddTupleLikeClass2::array)>::value> { };
232
233}
234
235namespace TestWebKitAPI {
236
237// FIXME: Is it OK for the get to be in the class's namespace and rely on argument-dependent lookup?
238// Or does this function template need to be moved into the std namespace like the tuple_size specialization?
239template<size_t i> int get(const HasherAddTupleLikeClass2& object)
240{
241 return get<i>(object.array);
242}
243
244TEST(WTF, Hasher_tupleLike)
245{
246 EXPECT_EQ(1652352321U, computeHash(HasherAddTupleLikeClass1 { }));
247 EXPECT_EQ(1652352321U, computeHash(HasherAddTupleLikeClass2 { }));
248}
249
250#endif
251
252} // namespace TestWebKitAPI
253