1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkRefCnt.h"
9 #include "include/core/SkString.h"
10 #include "include/core/SkTypes.h"
11 #include "src/core/SkOpts.h"
12 #include "src/core/SkTHash.h"
13 #include "tests/Test.h"
14
15 #include <cstdint>
16 #include <cstring>
17 #include <initializer_list>
18 #include <string>
19 #include <string_view>
20 #include <utility>
21
22 // Tests use of const foreach(). map.count() is of course the better way to do this.
count(const SkTHashMap<int,double> & map)23 static int count(const SkTHashMap<int, double>& map) {
24 int n = 0;
25 map.foreach([&n](int, double) { n++; });
26 return n;
27 }
28
DEF_TEST(HashMap,r)29 DEF_TEST(HashMap, r) {
30 SkTHashMap<int, double> map;
31
32 map.set(3, 4.0);
33 REPORTER_ASSERT(r, map.count() == 1);
34
35 REPORTER_ASSERT(r, map.approxBytesUsed() > 0);
36
37 double* found = map.find(3);
38 REPORTER_ASSERT(r, found);
39 REPORTER_ASSERT(r, *found == 4.0);
40
41 map.foreach([](int key, double* d){ *d = -key; });
42 REPORTER_ASSERT(r, count(map) == 1);
43
44 found = map.find(3);
45 REPORTER_ASSERT(r, found);
46 REPORTER_ASSERT(r, *found == -3.0);
47
48 REPORTER_ASSERT(r, !map.find(2));
49
50 const int N = 20;
51
52 for (int i = 0; i < N; i++) {
53 map.set(i, 2.0*i);
54 }
55
56 // Test walking the map with iterators, using preincrement (++iter).
57 for (SkTHashMap<int, double>::Iter iter = map.begin(); iter != map.end(); ++iter) {
58 REPORTER_ASSERT(r, iter->first * 2 == (*iter).second);
59 }
60
61 // Test walking the map with range-based for.
62 for (auto& entry : map) {
63 REPORTER_ASSERT(r, entry.first * 2 == entry.second);
64 }
65
66 // Ensure that iteration works equally well on a const map, using postincrement (iter++).
67 const auto& cmap = map;
68 for (SkTHashMap<int, double>::Iter iter = cmap.begin(); iter != cmap.end(); iter++) {
69 REPORTER_ASSERT(r, iter->first * 2 == (*iter).second);
70 }
71
72 // Ensure that range-based for works equally well on a const map.
73 for (const auto& entry : cmap) {
74 REPORTER_ASSERT(r, entry.first * 2 == entry.second);
75 }
76
77 // Ensure that structured bindings work.
78 for (const auto& [number, timesTwo] : cmap) {
79 REPORTER_ASSERT(r, number * 2 == timesTwo);
80 }
81
82 SkTHashMap<int, double> clone = map;
83
84 for (int i = 0; i < N; i++) {
85 found = map.find(i);
86 REPORTER_ASSERT(r, found);
87 REPORTER_ASSERT(r, *found == i*2.0);
88
89 found = clone.find(i);
90 REPORTER_ASSERT(r, found);
91 REPORTER_ASSERT(r, *found == i*2.0);
92 }
93 for (int i = N; i < 2*N; i++) {
94 REPORTER_ASSERT(r, !map.find(i));
95 REPORTER_ASSERT(r, !clone.find(i));
96 }
97
98 REPORTER_ASSERT(r, map.count() == N);
99 REPORTER_ASSERT(r, clone.count() == N);
100
101 for (int i = 0; i < N/2; i++) {
102 map.remove(i);
103 }
104 for (int i = 0; i < N; i++) {
105 found = map.find(i);
106 REPORTER_ASSERT(r, (found == nullptr) == (i < N/2));
107
108 found = clone.find(i);
109 REPORTER_ASSERT(r, *found == i*2.0);
110 }
111 REPORTER_ASSERT(r, map.count() == N/2);
112 REPORTER_ASSERT(r, clone.count() == N);
113
114 map.reset();
115 REPORTER_ASSERT(r, map.count() == 0);
116 REPORTER_ASSERT(r, clone.count() == N);
117
118 clone = map;
119 REPORTER_ASSERT(r, clone.count() == 0);
120
121 {
122 // Test that we don't leave dangling values in empty slots.
123 SkTHashMap<int, sk_sp<SkRefCnt>> refMap;
124 auto ref = sk_make_sp<SkRefCnt>();
125 REPORTER_ASSERT(r, ref->unique());
126
127 refMap.set(0, ref);
128 REPORTER_ASSERT(r, refMap.count() == 1);
129 REPORTER_ASSERT(r, !ref->unique());
130
131 refMap.remove(0);
132 REPORTER_ASSERT(r, refMap.count() == 0);
133 REPORTER_ASSERT(r, ref->unique());
134 }
135 }
136
DEF_TEST(HashMapCtor,r)137 DEF_TEST(HashMapCtor, r) {
138 SkTHashMap<int, std::string_view> map{{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}};
139 REPORTER_ASSERT(r, map.count() == 4);
140 REPORTER_ASSERT(r, map.approxBytesUsed() >= 4 * (sizeof(int) + sizeof(std::string_view)));
141
142 std::string_view* found = map.find(1);
143 REPORTER_ASSERT(r, found);
144 REPORTER_ASSERT(r, *found == "one");
145
146 found = map.find(2);
147 REPORTER_ASSERT(r, found);
148 REPORTER_ASSERT(r, *found == "two");
149
150 found = map.find(3);
151 REPORTER_ASSERT(r, found);
152 REPORTER_ASSERT(r, *found == "three");
153
154 found = map.find(4);
155 REPORTER_ASSERT(r, found);
156 REPORTER_ASSERT(r, *found == "four");
157
158 found = map.find(5);
159 REPORTER_ASSERT(r, !found);
160
161 found = map.find(6);
162 REPORTER_ASSERT(r, !found);
163 }
164
DEF_TEST(HashMapCtorOneElem,r)165 DEF_TEST(HashMapCtorOneElem, r) {
166 // Start out with a single element. The initializer list constructor sets the capacity
167 // conservatively. Searching for elements beyond the capacity should succeed.
168 SkTHashMap<int, std::string_view> map{{1, "one"}};
169 REPORTER_ASSERT(r, map.count() == 1);
170 REPORTER_ASSERT(r, map.approxBytesUsed() >= (sizeof(int) + sizeof(std::string_view)));
171
172 std::string_view* found = map.find(1);
173 REPORTER_ASSERT(r, found);
174 REPORTER_ASSERT(r, *found == "one");
175
176 found = map.find(2);
177 REPORTER_ASSERT(r, !found);
178
179 // Grow the collection by one element. Searching for non-existing elements should still succeed.
180 map.set(2, "two");
181 found = map.find(2);
182 REPORTER_ASSERT(r, found);
183 REPORTER_ASSERT(r, *found == "two");
184
185 found = map.find(3);
186 REPORTER_ASSERT(r, !found);
187 }
188
DEF_TEST(HashSetCtor,r)189 DEF_TEST(HashSetCtor, r) {
190 SkTHashSet<std::string_view> set{"one", "two", "three", "four"};
191 REPORTER_ASSERT(r, set.count() == 4);
192 REPORTER_ASSERT(r, set.approxBytesUsed() >= 4 * sizeof(std::string_view));
193
194 REPORTER_ASSERT(r, set.contains("one"));
195 REPORTER_ASSERT(r, set.contains("two"));
196 REPORTER_ASSERT(r, set.contains("three"));
197 REPORTER_ASSERT(r, set.contains("four"));
198 REPORTER_ASSERT(r, !set.contains("five"));
199 REPORTER_ASSERT(r, !set.contains("six"));
200 }
201
DEF_TEST(HashSetCtorOneElem,r)202 DEF_TEST(HashSetCtorOneElem, r) {
203 // Start out with a single element. The initializer list constructor sets the capacity
204 // conservatively. Searching for elements beyond the capacity should succeed.
205 SkTHashSet<std::string_view> set{"one"};
206 REPORTER_ASSERT(r, set.count() == 1);
207 REPORTER_ASSERT(r, set.approxBytesUsed() >= sizeof(std::string_view));
208
209 REPORTER_ASSERT(r, set.contains("one"));
210 REPORTER_ASSERT(r, !set.contains("two"));
211
212 // Grow the collection by one element. Searching for non-existing elements should still succeed.
213 set.add("two");
214 REPORTER_ASSERT(r, set.contains("one"));
215 REPORTER_ASSERT(r, set.contains("two"));
216 REPORTER_ASSERT(r, !set.contains("three"));
217 }
218
219 template <typename T>
test_hash_set(skiatest::Reporter * r)220 static void test_hash_set(skiatest::Reporter* r) {
221 SkTHashSet<T> set;
222
223 set.add(T("Hello"));
224 set.add(T("World"));
225 REPORTER_ASSERT(r, set.count() == 2);
226 REPORTER_ASSERT(r, set.contains(T("Hello")));
227 REPORTER_ASSERT(r, set.contains(T("World")));
228 REPORTER_ASSERT(r, !set.contains(T("Goodbye")));
229 REPORTER_ASSERT(r, set.find(T("Hello")));
230 REPORTER_ASSERT(r, *set.find(T("Hello")) == T("Hello"));
231
232 // Test walking the set with iterators, using preincrement (++iter).
233 for (typename SkTHashSet<T>::Iter iter = set.begin(); iter != set.end(); ++iter) {
234 REPORTER_ASSERT(r, *iter == T("Hello") || *iter == T("World"));
235 }
236
237 // Test walking the set with iterators, using postincrement (iter++).
238 for (typename SkTHashSet<T>::Iter iter = set.begin(); iter != set.end(); iter++) {
239 REPORTER_ASSERT(r, *iter == T("Hello") || *iter == T("World"));
240 }
241
242 // Test walking the set with range-based for.
243 for (auto& entry : set) {
244 REPORTER_ASSERT(r, entry == T("Hello") || entry == T("World"));
245 }
246
247 // Ensure that iteration works equally well on a const set.
248 const auto& cset = set;
249 for (typename SkTHashSet<T>::Iter iter = cset.begin(); iter != cset.end(); iter++) {
250 REPORTER_ASSERT(r, *iter == T("Hello") || *iter == T("World"));
251 }
252
253 // Ensure that range-based for works equally well on a const set.
254 for (auto& entry : cset) {
255 REPORTER_ASSERT(r, entry == T("Hello") || entry == T("World"));
256 }
257
258 SkTHashSet<T> clone = set;
259 REPORTER_ASSERT(r, clone.count() == 2);
260 REPORTER_ASSERT(r, clone.contains(T("Hello")));
261 REPORTER_ASSERT(r, clone.contains(T("World")));
262 REPORTER_ASSERT(r, !clone.contains(T("Goodbye")));
263 REPORTER_ASSERT(r, clone.find(T("Hello")));
264 REPORTER_ASSERT(r, *clone.find(T("Hello")) == T("Hello"));
265
266 set.remove(T("Hello"));
267 REPORTER_ASSERT(r, !set.contains(T("Hello")));
268 REPORTER_ASSERT(r, set.count() == 1);
269 REPORTER_ASSERT(r, clone.contains(T("Hello")));
270 REPORTER_ASSERT(r, clone.count() == 2);
271
272 set.reset();
273 REPORTER_ASSERT(r, set.count() == 0);
274
275 clone = set;
276 REPORTER_ASSERT(r, clone.count() == 0);
277 }
278
DEF_TEST(HashSetWithSkString,r)279 DEF_TEST(HashSetWithSkString, r) {
280 test_hash_set<SkString>(r);
281 }
282
DEF_TEST(HashSetWithStdString,r)283 DEF_TEST(HashSetWithStdString, r) {
284 test_hash_set<std::string>(r);
285 }
286
DEF_TEST(HashSetWithStdStringView,r)287 DEF_TEST(HashSetWithStdStringView, r) {
288 test_hash_set<std::string_view>(r);
289 }
290
291 namespace {
292
293 class CopyCounter {
294 public:
CopyCounter()295 CopyCounter() : fID(0), fCounter(nullptr) {}
296
CopyCounter(uint32_t id,uint32_t * counter)297 CopyCounter(uint32_t id, uint32_t* counter) : fID(id), fCounter(counter) {}
298
CopyCounter(const CopyCounter & other)299 CopyCounter(const CopyCounter& other)
300 : fID(other.fID)
301 , fCounter(other.fCounter) {
302 SkASSERT(fCounter);
303 *fCounter += 1;
304 }
305
operator =(const CopyCounter & other)306 void operator=(const CopyCounter& other) {
307 fID = other.fID;
308 fCounter = other.fCounter;
309 *fCounter += 1;
310 }
311
CopyCounter(CopyCounter && other)312 CopyCounter(CopyCounter&& other) { *this = std::move(other); }
operator =(CopyCounter && other)313 void operator=(CopyCounter&& other) {
314 fID = other.fID;
315 fCounter = other.fCounter;
316 }
317
318
operator ==(const CopyCounter & other) const319 bool operator==(const CopyCounter& other) const {
320 return fID == other.fID;
321 }
322
323 private:
324 uint32_t fID;
325 uint32_t* fCounter;
326 };
327
328 struct HashCopyCounter {
operator ()__anonb26bbe040311::HashCopyCounter329 uint32_t operator()(const CopyCounter&) const {
330 return 0; // let them collide, what do we care?
331 }
332 };
333
334 } // namespace
335
DEF_TEST(HashSetCopyCounter,r)336 DEF_TEST(HashSetCopyCounter, r) {
337 SkTHashSet<CopyCounter, HashCopyCounter> set;
338
339 uint32_t globalCounter = 0;
340 CopyCounter copyCounter1(1, &globalCounter);
341 CopyCounter copyCounter2(2, &globalCounter);
342 REPORTER_ASSERT(r, globalCounter == 0);
343
344 set.add(copyCounter1);
345 REPORTER_ASSERT(r, globalCounter == 1);
346 REPORTER_ASSERT(r, set.contains(copyCounter1));
347 REPORTER_ASSERT(r, globalCounter == 1);
348 set.add(copyCounter1);
349 // We allow copies for same-value adds for now.
350 REPORTER_ASSERT(r, globalCounter == 2);
351
352 set.add(copyCounter2);
353 REPORTER_ASSERT(r, globalCounter == 3);
354 REPORTER_ASSERT(r, set.contains(copyCounter1));
355 REPORTER_ASSERT(r, set.contains(copyCounter2));
356 REPORTER_ASSERT(r, globalCounter == 3);
357 set.add(copyCounter1);
358 set.add(copyCounter2);
359 // We allow copies for same-value adds for now.
360 REPORTER_ASSERT(r, globalCounter == 5);
361 }
362
363
DEF_TEST(HashFindOrNull,r)364 DEF_TEST(HashFindOrNull, r) {
365 struct Entry {
366 int key = 0;
367 int val = 0;
368 };
369
370 struct HashTraits {
371 static int GetKey(const Entry* e) { return e->key; }
372 static uint32_t Hash(int key) { return key; }
373 };
374
375 SkTHashTable<Entry*, int, HashTraits> table;
376
377 REPORTER_ASSERT(r, nullptr == table.findOrNull(7));
378
379 Entry seven = { 7, 24 };
380 table.set(&seven);
381
382 REPORTER_ASSERT(r, &seven == table.findOrNull(7));
383 }
384
DEF_TEST(HashTableGrowsAndShrinks,r)385 DEF_TEST(HashTableGrowsAndShrinks, r) {
386 SkTHashSet<int> s;
387 auto check_count_cap = [&](int count, int cap) {
388 REPORTER_ASSERT(r, s.count() == count);
389 REPORTER_ASSERT(r, s.approxBytesUsed() == (sizeof(int) + sizeof(uint32_t)) * cap);
390 };
391
392 // Add and remove some elements to test basic growth and shrink patterns.
393 check_count_cap(0,0);
394 s.add(1); check_count_cap(1,4);
395 s.add(2); check_count_cap(2,4);
396 s.add(3); check_count_cap(3,4);
397 s.add(4); check_count_cap(4,8);
398
399 s.remove(4); check_count_cap(3,8);
400 s.remove(3); check_count_cap(2,4);
401 s.remove(2); check_count_cap(1,4);
402 s.remove(1); check_count_cap(0,4);
403
404 s.add(1); check_count_cap(1,4);
405 s.add(2); check_count_cap(2,4);
406 s.add(3); check_count_cap(3,4);
407 s.add(4); check_count_cap(4,8);
408
409 // Add and remove single elements repeatedly to test hysteresis
410 // avoids reallocating these small tables all the time.
411 for (int i = 0; i < 10; i++) {
412 s. add(5); check_count_cap(5,8);
413 s.remove(5); check_count_cap(4,8);
414 }
415
416 s.remove(4); check_count_cap(3,8);
417 for (int i = 0; i < 10; i++) {
418 s. add(4); check_count_cap(4,8);
419 s.remove(4); check_count_cap(3,8);
420 }
421
422 s.remove(3); check_count_cap(2,4);
423 for (int i = 0; i < 10; i++) {
424 s. add(4); check_count_cap(3,4);
425 s.remove(4); check_count_cap(2,4);
426 }
427
428 s.remove(2); check_count_cap(1,4);
429 for (int i = 0; i < 10; i++) {
430 s. add(2); check_count_cap(2,4);
431 s.remove(2); check_count_cap(1,4);
432 }
433 }
434
DEF_TEST(HashCollision,r)435 DEF_TEST(HashCollision, r) {
436
437 // Two different sets of data. Same hash.
438 uint8_t data1[] = {
439 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 2, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 3, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 7, 0, 0, 0, 5, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 6, 0, 0, 0, 13, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 6, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 8, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 8, 0, 0, 0, 17, 0, 0, 0, 18, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 27, 0, 0, 0, 16, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 16, 0, 0, 0, 21, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 28, 0, 0, 0, 21, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 16, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 28, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 31, 0, 0, 0, 27, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 32, 0, 0, 0, 27, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 33, 0, 0, 0, 23, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 33, 0, 0, 0, 23, 0, 0, 0, 24, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
440 };
441 uint8_t data2[] = {
442 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 2, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 3, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 7, 0, 0, 0, 5, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 6, 0, 0, 0, 13, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 6, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 8, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 8, 0, 0, 0, 17, 0, 0, 0, 18, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 27, 0, 0, 0, 16, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 16, 0, 0, 0, 21, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 28, 0, 0, 0, 21, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 16, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 28, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 31, 0, 0, 0, 27, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 32, 0, 0, 0, 27, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 33, 0, 0, 0, 23, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 33, 0, 0, 0, 23, 0, 0, 0, 24, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
443 };
444
445 REPORTER_ASSERT(r, sizeof(data1) == sizeof(data2));
446 REPORTER_ASSERT(r, memcmp(data1, data2, sizeof(data1)) != 0);
447
448 uint32_t hash1 = SkOpts::hash(data1, sizeof(data1), 0);
449 uint32_t hash2 = SkOpts::hash(data2, sizeof(data2), 0);
450 REPORTER_ASSERT(r, hash1 != hash2);
451 }
452