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/private/SkChecksum.h"
11 #include "include/private/SkTHash.h"
12 #include "src/core/SkOpts.h"
13 #include "tests/Test.h"
14
15 #include <tuple>
16
17 // Tests use of const foreach(). map.count() is of course the better way to do this.
count(const SkTHashMap<int,double> & map)18 static int count(const SkTHashMap<int, double>& map) {
19 int n = 0;
20 map.foreach([&n](int, double) { n++; });
21 return n;
22 }
23
DEF_TEST(HashMap,r)24 DEF_TEST(HashMap, r) {
25 SkTHashMap<int, double> map;
26
27 map.set(3, 4.0);
28 REPORTER_ASSERT(r, map.count() == 1);
29
30 REPORTER_ASSERT(r, map.approxBytesUsed() > 0);
31
32 double* found = map.find(3);
33 REPORTER_ASSERT(r, found);
34 REPORTER_ASSERT(r, *found == 4.0);
35
36 map.foreach([](int key, double* d){ *d = -key; });
37 REPORTER_ASSERT(r, count(map) == 1);
38
39 found = map.find(3);
40 REPORTER_ASSERT(r, found);
41 REPORTER_ASSERT(r, *found == -3.0);
42
43 REPORTER_ASSERT(r, !map.find(2));
44
45 const int N = 20;
46
47 for (int i = 0; i < N; i++) {
48 map.set(i, 2.0*i);
49 }
50
51 // Test walking the map with iterators, using preincrement (++iter).
52 for (SkTHashMap<int, double>::Iter iter = map.begin(); iter != map.end(); ++iter) {
53 REPORTER_ASSERT(r, iter->first * 2 == (*iter).second);
54 }
55
56 // Test walking the map with range-based for.
57 for (auto& entry : map) {
58 REPORTER_ASSERT(r, entry.first * 2 == entry.second);
59 }
60
61 // Ensure that iteration works equally well on a const map, using postincrement (iter++).
62 const auto& cmap = map;
63 for (SkTHashMap<int, double>::Iter iter = cmap.begin(); iter != cmap.end(); iter++) {
64 REPORTER_ASSERT(r, iter->first * 2 == (*iter).second);
65 }
66
67 // Ensure that range-based for works equally well on a const map.
68 for (const auto& entry : cmap) {
69 REPORTER_ASSERT(r, entry.first * 2 == entry.second);
70 }
71
72 // Ensure that structured bindings work.
73 for (const auto& [number, timesTwo] : cmap) {
74 REPORTER_ASSERT(r, number * 2 == timesTwo);
75 }
76
77 SkTHashMap<int, double> clone = map;
78
79 for (int i = 0; i < N; i++) {
80 found = map.find(i);
81 REPORTER_ASSERT(r, found);
82 REPORTER_ASSERT(r, *found == i*2.0);
83
84 found = clone.find(i);
85 REPORTER_ASSERT(r, found);
86 REPORTER_ASSERT(r, *found == i*2.0);
87 }
88 for (int i = N; i < 2*N; i++) {
89 REPORTER_ASSERT(r, !map.find(i));
90 REPORTER_ASSERT(r, !clone.find(i));
91 }
92
93 REPORTER_ASSERT(r, map.count() == N);
94 REPORTER_ASSERT(r, clone.count() == N);
95
96 for (int i = 0; i < N/2; i++) {
97 map.remove(i);
98 }
99 for (int i = 0; i < N; i++) {
100 found = map.find(i);
101 REPORTER_ASSERT(r, (found == nullptr) == (i < N/2));
102
103 found = clone.find(i);
104 REPORTER_ASSERT(r, *found == i*2.0);
105 }
106 REPORTER_ASSERT(r, map.count() == N/2);
107 REPORTER_ASSERT(r, clone.count() == N);
108
109 map.reset();
110 REPORTER_ASSERT(r, map.count() == 0);
111 REPORTER_ASSERT(r, clone.count() == N);
112
113 clone = map;
114 REPORTER_ASSERT(r, clone.count() == 0);
115
116 {
117 // Test that we don't leave dangling values in empty slots.
118 SkTHashMap<int, sk_sp<SkRefCnt>> refMap;
119 auto ref = sk_make_sp<SkRefCnt>();
120 REPORTER_ASSERT(r, ref->unique());
121
122 refMap.set(0, ref);
123 REPORTER_ASSERT(r, refMap.count() == 1);
124 REPORTER_ASSERT(r, !ref->unique());
125
126 refMap.remove(0);
127 REPORTER_ASSERT(r, refMap.count() == 0);
128 REPORTER_ASSERT(r, ref->unique());
129 }
130 }
131
DEF_TEST(HashSet,r)132 DEF_TEST(HashSet, r) {
133 SkTHashSet<SkString> set;
134
135 set.add(SkString("Hello"));
136 set.add(SkString("World"));
137 REPORTER_ASSERT(r, set.count() == 2);
138 REPORTER_ASSERT(r, set.contains(SkString("Hello")));
139 REPORTER_ASSERT(r, set.contains(SkString("World")));
140 REPORTER_ASSERT(r, !set.contains(SkString("Goodbye")));
141 REPORTER_ASSERT(r, set.find(SkString("Hello")));
142 REPORTER_ASSERT(r, *set.find(SkString("Hello")) == SkString("Hello"));
143
144 // Test walking the set with iterators, using preincrement (++iter).
145 for (SkTHashSet<SkString>::Iter iter = set.begin(); iter != set.end(); ++iter) {
146 REPORTER_ASSERT(r, iter->equals("Hello") || (*iter).equals("World"));
147 }
148
149 // Test walking the set with iterators, using postincrement (iter++).
150 for (SkTHashSet<SkString>::Iter iter = set.begin(); iter != set.end(); iter++) {
151 REPORTER_ASSERT(r, iter->equals("Hello") || (*iter).equals("World"));
152 }
153
154 // Test walking the set with range-based for.
155 for (auto& entry : set) {
156 REPORTER_ASSERT(r, entry.equals("Hello") || entry.equals("World"));
157 }
158
159 // Ensure that iteration works equally well on a const set.
160 const auto& cset = set;
161 for (SkTHashSet<SkString>::Iter iter = cset.begin(); iter != cset.end(); iter++) {
162 REPORTER_ASSERT(r, iter->equals("Hello") || (*iter).equals("World"));
163 }
164
165 // Ensure that range-based for works equally well on a const set.
166 for (auto& entry : cset) {
167 REPORTER_ASSERT(r, entry.equals("Hello") || entry.equals("World"));
168 }
169
170 SkTHashSet<SkString> clone = set;
171 REPORTER_ASSERT(r, clone.count() == 2);
172 REPORTER_ASSERT(r, clone.contains(SkString("Hello")));
173 REPORTER_ASSERT(r, clone.contains(SkString("World")));
174 REPORTER_ASSERT(r, !clone.contains(SkString("Goodbye")));
175 REPORTER_ASSERT(r, clone.find(SkString("Hello")));
176 REPORTER_ASSERT(r, *clone.find(SkString("Hello")) == SkString("Hello"));
177
178 set.remove(SkString("Hello"));
179 REPORTER_ASSERT(r, !set.contains(SkString("Hello")));
180 REPORTER_ASSERT(r, set.count() == 1);
181 REPORTER_ASSERT(r, clone.contains(SkString("Hello")));
182 REPORTER_ASSERT(r, clone.count() == 2);
183
184 set.reset();
185 REPORTER_ASSERT(r, set.count() == 0);
186
187 clone = set;
188 REPORTER_ASSERT(r, clone.count() == 0);
189 }
190
191 namespace {
192
193 class CopyCounter {
194 public:
CopyCounter()195 CopyCounter() : fID(0), fCounter(nullptr) {}
196
CopyCounter(uint32_t id,uint32_t * counter)197 CopyCounter(uint32_t id, uint32_t* counter) : fID(id), fCounter(counter) {}
198
CopyCounter(const CopyCounter & other)199 CopyCounter(const CopyCounter& other)
200 : fID(other.fID)
201 , fCounter(other.fCounter) {
202 SkASSERT(fCounter);
203 *fCounter += 1;
204 }
205
operator =(const CopyCounter & other)206 void operator=(const CopyCounter& other) {
207 fID = other.fID;
208 fCounter = other.fCounter;
209 *fCounter += 1;
210 }
211
CopyCounter(CopyCounter && other)212 CopyCounter(CopyCounter&& other) { *this = std::move(other); }
operator =(CopyCounter && other)213 void operator=(CopyCounter&& other) {
214 fID = other.fID;
215 fCounter = other.fCounter;
216 }
217
218
operator ==(const CopyCounter & other) const219 bool operator==(const CopyCounter& other) const {
220 return fID == other.fID;
221 }
222
223 private:
224 uint32_t fID;
225 uint32_t* fCounter;
226 };
227
228 struct HashCopyCounter {
operator ()__anon0462fb500311::HashCopyCounter229 uint32_t operator()(const CopyCounter&) const {
230 return 0; // let them collide, what do we care?
231 }
232 };
233
234 } // namespace
235
DEF_TEST(HashSetCopyCounter,r)236 DEF_TEST(HashSetCopyCounter, r) {
237 SkTHashSet<CopyCounter, HashCopyCounter> set;
238
239 uint32_t globalCounter = 0;
240 CopyCounter copyCounter1(1, &globalCounter);
241 CopyCounter copyCounter2(2, &globalCounter);
242 REPORTER_ASSERT(r, globalCounter == 0);
243
244 set.add(copyCounter1);
245 REPORTER_ASSERT(r, globalCounter == 1);
246 REPORTER_ASSERT(r, set.contains(copyCounter1));
247 REPORTER_ASSERT(r, globalCounter == 1);
248 set.add(copyCounter1);
249 // We allow copies for same-value adds for now.
250 REPORTER_ASSERT(r, globalCounter == 2);
251
252 set.add(copyCounter2);
253 REPORTER_ASSERT(r, globalCounter == 3);
254 REPORTER_ASSERT(r, set.contains(copyCounter1));
255 REPORTER_ASSERT(r, set.contains(copyCounter2));
256 REPORTER_ASSERT(r, globalCounter == 3);
257 set.add(copyCounter1);
258 set.add(copyCounter2);
259 // We allow copies for same-value adds for now.
260 REPORTER_ASSERT(r, globalCounter == 5);
261 }
262
263
DEF_TEST(HashFindOrNull,r)264 DEF_TEST(HashFindOrNull, r) {
265 struct Entry {
266 int key = 0;
267 int val = 0;
268 };
269
270 struct HashTraits {
271 static int GetKey(const Entry* e) { return e->key; }
272 static uint32_t Hash(int key) { return key; }
273 };
274
275 SkTHashTable<Entry*, int, HashTraits> table;
276
277 REPORTER_ASSERT(r, nullptr == table.findOrNull(7));
278
279 Entry seven = { 7, 24 };
280 table.set(&seven);
281
282 REPORTER_ASSERT(r, &seven == table.findOrNull(7));
283 }
284
DEF_TEST(HashTableGrowsAndShrinks,r)285 DEF_TEST(HashTableGrowsAndShrinks, r) {
286 SkTHashSet<int> s;
287 auto check_count_cap = [&](int count, int cap) {
288 REPORTER_ASSERT(r, s.count() == count);
289 REPORTER_ASSERT(r, s.approxBytesUsed() == (sizeof(int) + sizeof(uint32_t)) * cap);
290 };
291
292 // Add and remove some elements to test basic growth and shrink patterns.
293 check_count_cap(0,0);
294 s.add(1); check_count_cap(1,4);
295 s.add(2); check_count_cap(2,4);
296 s.add(3); check_count_cap(3,4);
297 s.add(4); check_count_cap(4,8);
298
299 s.remove(4); check_count_cap(3,8);
300 s.remove(3); check_count_cap(2,4);
301 s.remove(2); check_count_cap(1,4);
302 s.remove(1); check_count_cap(0,4);
303
304 s.add(1); check_count_cap(1,4);
305 s.add(2); check_count_cap(2,4);
306 s.add(3); check_count_cap(3,4);
307 s.add(4); check_count_cap(4,8);
308
309 // Add and remove single elements repeatedly to test hysteresis
310 // avoids reallocating these small tables all the time.
311 for (int i = 0; i < 10; i++) {
312 s. add(5); check_count_cap(5,8);
313 s.remove(5); check_count_cap(4,8);
314 }
315
316 s.remove(4); check_count_cap(3,8);
317 for (int i = 0; i < 10; i++) {
318 s. add(4); check_count_cap(4,8);
319 s.remove(4); check_count_cap(3,8);
320 }
321
322 s.remove(3); check_count_cap(2,4);
323 for (int i = 0; i < 10; i++) {
324 s. add(4); check_count_cap(3,4);
325 s.remove(4); check_count_cap(2,4);
326 }
327
328 s.remove(2); check_count_cap(1,4);
329 for (int i = 0; i < 10; i++) {
330 s. add(2); check_count_cap(2,4);
331 s.remove(2); check_count_cap(1,4);
332 }
333 }
334
DEF_TEST(HashCollision,r)335 DEF_TEST(HashCollision, r) {
336
337 // Two different sets of data. Same hash.
338 uint8_t data1[] = {
339 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,
340 };
341 uint8_t data2[] = {
342 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,
343 };
344
345 REPORTER_ASSERT(r, sizeof(data1) == sizeof(data2));
346 REPORTER_ASSERT(r, memcmp(data1, data2, sizeof(data1)) != 0);
347
348 uint32_t hash1 = SkOpts::hash(data1, sizeof(data1), 0);
349 uint32_t hash2 = SkOpts::hash(data2, sizeof(data2), 0);
350 REPORTER_ASSERT(r, hash1 != hash2);
351 }
352