Flutter Engine
The Flutter Engine
Functions
HashTest.cpp File Reference
#include "include/core/SkRefCnt.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "src/core/SkTHash.h"
#include "tests/Test.h"
#include <cstdint>
#include <initializer_list>
#include <string>
#include <string_view>
#include <utility>

Go to the source code of this file.

Functions

static int count (const THashMap< int, double > &map)
 
 DEF_TEST (HashMap, r)
 
 DEF_TEST (HashMapCtor, r)
 
 DEF_TEST (HashMapCtorOneElem, r)
 
 DEF_TEST (HashSetCtor, r)
 
 DEF_TEST (HashSetCtorOneElem, r)
 
template<typename T >
static void test_hash_set (skiatest::Reporter *r)
 
 DEF_TEST (HashSetWithSkString, r)
 
 DEF_TEST (HashSetWithStdString, r)
 
 DEF_TEST (HashSetWithStdStringView, r)
 
 DEF_TEST (HashSetCopyCounter, r)
 
 DEF_TEST (HashFindOrNull, r)
 
 DEF_TEST (HashTableGrowsAndShrinks, r)
 
 DEF_TEST (HashMapSwap, r)
 
 DEF_TEST (HashSetSwap, r)
 

Function Documentation

◆ count()

static int count ( const THashMap< int, double > &  map)
static

Definition at line 23 of file HashTest.cpp.

23 {
24 int n = 0;
25 map.foreach([&n](int, double) { n++; });
26 return n;
27}
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition: SkVx.h:680

◆ DEF_TEST() [1/13]

DEF_TEST ( HashFindOrNull  ,
 
)

Definition at line 378 of file HashTest.cpp.

378 {
379 struct Entry {
380 int key = 0;
381 int val = 0;
382 };
383
384 struct HashTraits {
385 static int GetKey(const Entry* e) { return e->key; }
386 static uint32_t Hash(int key) { return key; }
387 };
388
390
391 REPORTER_ASSERT(r, nullptr == table.findOrNull(7));
392
393 Entry seven = { 7, 24 };
394 table.set(&seven);
395
396 REPORTER_ASSERT(r, &seven == table.findOrNull(7));
397}
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
SI F table(const skcms_Curve *curve, F v)
static uint32_t Hash(uint32_t key)
Definition: hashmap_test.cc:65

◆ DEF_TEST() [2/13]

DEF_TEST ( HashMap  ,
 
)

Definition at line 29 of file HashTest.cpp.

29 {
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 foreach(const K&, V)
57 map.foreach([&](const int& key, double value) {
58 REPORTER_ASSERT(r, key * 2 == value);
59 });
60
61 // Test walking the map with foreach(const K&, V*)
62 map.foreach([&](const int& key, double* value) {
63 REPORTER_ASSERT(r, key * 2 == *value);
64 });
65
66 // Test walking the map with foreach(const Pair&)
67 map.foreach([&](const THashMap<int, double>::Pair& pair) {
68 REPORTER_ASSERT(r, pair.first * 2 == pair.second);
69 });
70
71 // Test walking the map with iterators, using preincrement (++iter).
72 for (THashMap<int, double>::Iter iter = map.begin(); iter != map.end(); ++iter) {
73 REPORTER_ASSERT(r, iter->first * 2 == (*iter).second);
74 }
75
76 // Test walking the map with range-based for.
77 for (auto& entry : map) {
78 REPORTER_ASSERT(r, entry.first * 2 == entry.second);
79 }
80
81 // Ensure that iteration works equally well on a const map, using postincrement (iter++).
82 const auto& cmap = map;
83 for (THashMap<int, double>::Iter iter = cmap.begin(); iter != cmap.end(); iter++) {
84 REPORTER_ASSERT(r, iter->first * 2 == (*iter).second);
85 }
86
87 // Ensure that range-based for works equally well on a const map.
88 for (const auto& entry : cmap) {
89 REPORTER_ASSERT(r, entry.first * 2 == entry.second);
90 }
91
92 // Ensure that structured bindings work.
93 for (const auto& [number, timesTwo] : cmap) {
94 REPORTER_ASSERT(r, number * 2 == timesTwo);
95 }
96
98
99 for (int i = 0; i < N; i++) {
100 found = map.find(i);
101 REPORTER_ASSERT(r, found);
102 REPORTER_ASSERT(r, *found == i*2.0);
103
104 found = clone.find(i);
105 REPORTER_ASSERT(r, found);
106 REPORTER_ASSERT(r, *found == i*2.0);
107 }
108 for (int i = N; i < 2*N; i++) {
109 REPORTER_ASSERT(r, !map.find(i));
110 REPORTER_ASSERT(r, !clone.find(i));
111 }
112
113 REPORTER_ASSERT(r, map.count() == N);
114 REPORTER_ASSERT(r, clone.count() == N);
115
116 for (int i = 0; i < N/2; i++) {
117 map.remove(i);
118 }
119 for (int i = 0; i < N; i++) {
120 found = map.find(i);
121 REPORTER_ASSERT(r, (found == nullptr) == (i < N/2));
122
123 found = clone.find(i);
124 REPORTER_ASSERT(r, *found == i*2.0);
125 }
126 REPORTER_ASSERT(r, map.count() == N/2);
127 REPORTER_ASSERT(r, clone.count() == N);
128
129 map.reset();
130 REPORTER_ASSERT(r, map.count() == 0);
131 REPORTER_ASSERT(r, clone.count() == N);
132
133 clone = map;
134 REPORTER_ASSERT(r, clone.count() == 0);
135
136 {
137 // Test that we don't leave dangling values in empty slots.
139 auto ref = sk_make_sp<SkRefCnt>();
140 REPORTER_ASSERT(r, ref->unique());
141
142 refMap.set(0, ref);
143 REPORTER_ASSERT(r, refMap.count() == 1);
144 REPORTER_ASSERT(r, !ref->unique());
145
146 refMap.remove(0);
147 REPORTER_ASSERT(r, refMap.count() == 0);
148 REPORTER_ASSERT(r, ref->unique());
149 }
150}
static int count(const THashMap< int, double > &map)
Definition: HashTest.cpp:23
#define N
Definition: beziers.cpp:19
int count() const
Definition: SkTHash.h:471
V * find(const K &key) const
Definition: SkTHash.h:494
V * set(K key, V val)
Definition: SkTHash.h:487
void remove(const K &key)
Definition: SkTHash.h:509
typename THashTable< Pair, K >::template Iter< std::pair< K, V > > Iter
Definition: SkTHash.h:540
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
uint8_t value

◆ DEF_TEST() [3/13]

DEF_TEST ( HashMapCtor  ,
 
)

Definition at line 152 of file HashTest.cpp.

152 {
153 THashMap<int, std::string_view> map{{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}};
154 REPORTER_ASSERT(r, map.count() == 4);
155 REPORTER_ASSERT(r, map.approxBytesUsed() >= 4 * (sizeof(int) + sizeof(std::string_view)));
156
157 std::string_view* found = map.find(1);
158 REPORTER_ASSERT(r, found);
159 REPORTER_ASSERT(r, *found == "one");
160
161 found = map.find(2);
162 REPORTER_ASSERT(r, found);
163 REPORTER_ASSERT(r, *found == "two");
164
165 found = map.find(3);
166 REPORTER_ASSERT(r, found);
167 REPORTER_ASSERT(r, *found == "three");
168
169 found = map.find(4);
170 REPORTER_ASSERT(r, found);
171 REPORTER_ASSERT(r, *found == "four");
172
173 found = map.find(5);
174 REPORTER_ASSERT(r, !found);
175
176 found = map.find(6);
177 REPORTER_ASSERT(r, !found);
178}

◆ DEF_TEST() [4/13]

DEF_TEST ( HashMapCtorOneElem  ,
 
)

Definition at line 180 of file HashTest.cpp.

180 {
181 // Start out with a single element. The initializer list constructor sets the capacity
182 // conservatively. Searching for elements beyond the capacity should succeed.
184 REPORTER_ASSERT(r, map.count() == 1);
185 REPORTER_ASSERT(r, map.approxBytesUsed() >= (sizeof(int) + sizeof(std::string_view)));
186
187 std::string_view* found = map.find(1);
188 REPORTER_ASSERT(r, found);
189 REPORTER_ASSERT(r, *found == "one");
190
191 found = map.find(2);
192 REPORTER_ASSERT(r, !found);
193
194 // Grow the collection by one element. Searching for non-existing elements should still succeed.
195 map.set(2, "two");
196 found = map.find(2);
197 REPORTER_ASSERT(r, found);
198 REPORTER_ASSERT(r, *found == "two");
199
200 found = map.find(3);
201 REPORTER_ASSERT(r, !found);
202}

◆ DEF_TEST() [5/13]

DEF_TEST ( HashMapSwap  ,
 
)

Definition at line 449 of file HashTest.cpp.

449 {
450 // Swap two maps.
451 THashMap<int, std::string_view> a{{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}};
452 THashMap<int, std::string_view> b{{1, "ichi"}, {2, "ni"}, {3, "san"}};
453
454 a.swap(b);
455 REPORTER_ASSERT(r, a.count() == 3);
456 REPORTER_ASSERT(r, a[1] == "ichi");
457 REPORTER_ASSERT(r, a[2] == "ni");
458 REPORTER_ASSERT(r, a[3] == "san");
459
460 REPORTER_ASSERT(r, b.count() == 4);
461 REPORTER_ASSERT(r, b[1] == "one");
462 REPORTER_ASSERT(r, b[2] == "two");
463 REPORTER_ASSERT(r, b[3] == "three");
464 REPORTER_ASSERT(r, b[4] == "four");
465
466 // Swap with an rvalue.
468 REPORTER_ASSERT(r, a.empty());
469}
static bool b
struct MyStruct a[10]

◆ DEF_TEST() [6/13]

DEF_TEST ( HashSetCopyCounter  ,
 
)

Definition at line 351 of file HashTest.cpp.

351 {
353
354 uint32_t globalCounter = 0;
355 CopyCounter copyCounter1(1, &globalCounter);
356 CopyCounter copyCounter2(2, &globalCounter);
357 REPORTER_ASSERT(r, globalCounter == 0);
358
359 set.add(copyCounter1);
360 REPORTER_ASSERT(r, globalCounter == 1);
361 REPORTER_ASSERT(r, set.contains(copyCounter1));
362 REPORTER_ASSERT(r, globalCounter == 1);
363 set.add(copyCounter1);
364 // We allow copies for same-value adds for now.
365 REPORTER_ASSERT(r, globalCounter == 2);
366
367 set.add(copyCounter2);
368 REPORTER_ASSERT(r, globalCounter == 3);
369 REPORTER_ASSERT(r, set.contains(copyCounter1));
370 REPORTER_ASSERT(r, set.contains(copyCounter2));
371 REPORTER_ASSERT(r, globalCounter == 3);
372 set.add(copyCounter1);
373 set.add(copyCounter2);
374 // We allow copies for same-value adds for now.
375 REPORTER_ASSERT(r, globalCounter == 5);
376}
bool contains(double x, double y)
Definition: path.cc:287
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76

◆ DEF_TEST() [7/13]

DEF_TEST ( HashSetCtor  ,
 
)

Definition at line 204 of file HashTest.cpp.

204 {
205 THashSet<std::string_view> set{"one", "two", "three", "four"};
206 REPORTER_ASSERT(r, set.count() == 4);
207 REPORTER_ASSERT(r, set.approxBytesUsed() >= 4 * sizeof(std::string_view));
208
209 REPORTER_ASSERT(r, set.contains("one"));
210 REPORTER_ASSERT(r, set.contains("two"));
211 REPORTER_ASSERT(r, set.contains("three"));
212 REPORTER_ASSERT(r, set.contains("four"));
213 REPORTER_ASSERT(r, !set.contains("five"));
214 REPORTER_ASSERT(r, !set.contains("six"));
215}

◆ DEF_TEST() [8/13]

DEF_TEST ( HashSetCtorOneElem  ,
 
)

Definition at line 217 of file HashTest.cpp.

217 {
218 // Start out with a single element. The initializer list constructor sets the capacity
219 // conservatively. Searching for elements beyond the capacity should succeed.
221 REPORTER_ASSERT(r, set.count() == 1);
222 REPORTER_ASSERT(r, set.approxBytesUsed() >= sizeof(std::string_view));
223
224 REPORTER_ASSERT(r, set.contains("one"));
225 REPORTER_ASSERT(r, !set.contains("two"));
226
227 // Grow the collection by one element. Searching for non-existing elements should still succeed.
228 set.add("two");
229 REPORTER_ASSERT(r, set.contains("one"));
230 REPORTER_ASSERT(r, set.contains("two"));
231 REPORTER_ASSERT(r, !set.contains("three"));
232}

◆ DEF_TEST() [9/13]

DEF_TEST ( HashSetSwap  ,
 
)

Definition at line 471 of file HashTest.cpp.

471 {
472 // Swap two maps.
473 THashSet<std::string_view> a{"one", "two", "three", "four"};
474 THashSet<std::string_view> b{"ichi", "ni", "san"};
475
476 a.swap(b);
477 REPORTER_ASSERT(r, a.count() == 3);
478 REPORTER_ASSERT(r, a.contains("ichi"));
479 REPORTER_ASSERT(r, a.contains("ni"));
480 REPORTER_ASSERT(r, a.contains("san"));
481
482 REPORTER_ASSERT(r, b.count() == 4);
483 REPORTER_ASSERT(r, b.contains("one"));
484 REPORTER_ASSERT(r, b.contains("two"));
485 REPORTER_ASSERT(r, b.contains("three"));
486 REPORTER_ASSERT(r, b.contains("four"));
487
488 // Swap with an rvalue.
490 REPORTER_ASSERT(r, a.empty());
491}

◆ DEF_TEST() [10/13]

DEF_TEST ( HashSetWithSkString  ,
 
)

Definition at line 294 of file HashTest.cpp.

294 {
295 test_hash_set<SkString>(r);
296}

◆ DEF_TEST() [11/13]

DEF_TEST ( HashSetWithStdString  ,
 
)

Definition at line 298 of file HashTest.cpp.

298 {
299 test_hash_set<std::string>(r);
300}

◆ DEF_TEST() [12/13]

DEF_TEST ( HashSetWithStdStringView  ,
 
)

Definition at line 302 of file HashTest.cpp.

302 {
303 test_hash_set<std::string_view>(r);
304}

◆ DEF_TEST() [13/13]

DEF_TEST ( HashTableGrowsAndShrinks  ,
 
)

Definition at line 399 of file HashTest.cpp.

399 {
401 auto check_count_cap = [&](int count, int cap) {
402 REPORTER_ASSERT(r, s.count() == count);
403 REPORTER_ASSERT(r, s.approxBytesUsed() == (sizeof(int) + sizeof(uint32_t)) * cap);
404 };
405
406 // Add and remove some elements to test basic growth and shrink patterns.
407 check_count_cap(0,0);
408 s.add(1); check_count_cap(1,4);
409 s.add(2); check_count_cap(2,4);
410 s.add(3); check_count_cap(3,4);
411 s.add(4); check_count_cap(4,8);
412
413 s.remove(4); check_count_cap(3,8);
414 s.remove(3); check_count_cap(2,4);
415 s.remove(2); check_count_cap(1,4);
416 s.remove(1); check_count_cap(0,4);
417
418 s.add(1); check_count_cap(1,4);
419 s.add(2); check_count_cap(2,4);
420 s.add(3); check_count_cap(3,4);
421 s.add(4); check_count_cap(4,8);
422
423 // Add and remove single elements repeatedly to test hysteresis
424 // avoids reallocating these small tables all the time.
425 for (int i = 0; i < 10; i++) {
426 s. add(5); check_count_cap(5,8);
427 s.remove(5); check_count_cap(4,8);
428 }
429
430 s.remove(4); check_count_cap(3,8);
431 for (int i = 0; i < 10; i++) {
432 s. add(4); check_count_cap(4,8);
433 s.remove(4); check_count_cap(3,8);
434 }
435
436 s.remove(3); check_count_cap(2,4);
437 for (int i = 0; i < 10; i++) {
438 s. add(4); check_count_cap(3,4);
439 s.remove(4); check_count_cap(2,4);
440 }
441
442 s.remove(2); check_count_cap(1,4);
443 for (int i = 0; i < 10; i++) {
444 s. add(2); check_count_cap(2,4);
445 s.remove(2); check_count_cap(1,4);
446 }
447}
struct MyStruct s

◆ test_hash_set()

template<typename T >
static void test_hash_set ( skiatest::Reporter r)
static

Definition at line 235 of file HashTest.cpp.

235 {
237
238 set.add(T("Hello"));
239 set.add(T("World"));
240 REPORTER_ASSERT(r, set.count() == 2);
241 REPORTER_ASSERT(r, set.contains(T("Hello")));
242 REPORTER_ASSERT(r, set.contains(T("World")));
243 REPORTER_ASSERT(r, !set.contains(T("Goodbye")));
244 REPORTER_ASSERT(r, set.find(T("Hello")));
245 REPORTER_ASSERT(r, *set.find(T("Hello")) == T("Hello"));
246
247 // Test walking the set with iterators, using preincrement (++iter).
248 for (typename THashSet<T>::Iter iter = set.begin(); iter != set.end(); ++iter) {
249 REPORTER_ASSERT(r, *iter == T("Hello") || *iter == T("World"));
250 }
251
252 // Test walking the set with iterators, using postincrement (iter++).
253 for (typename THashSet<T>::Iter iter = set.begin(); iter != set.end(); iter++) {
254 REPORTER_ASSERT(r, *iter == T("Hello") || *iter == T("World"));
255 }
256
257 // Test walking the set with range-based for.
258 for (auto& entry : set) {
259 REPORTER_ASSERT(r, entry == T("Hello") || entry == T("World"));
260 }
261
262 // Ensure that iteration works equally well on a const set.
263 const auto& cset = set;
264 for (typename THashSet<T>::Iter iter = cset.begin(); iter != cset.end(); iter++) {
265 REPORTER_ASSERT(r, *iter == T("Hello") || *iter == T("World"));
266 }
267
268 // Ensure that range-based for works equally well on a const set.
269 for (auto& entry : cset) {
270 REPORTER_ASSERT(r, entry == T("Hello") || entry == T("World"));
271 }
272
273 THashSet<T> clone = set;
274 REPORTER_ASSERT(r, clone.count() == 2);
275 REPORTER_ASSERT(r, clone.contains(T("Hello")));
276 REPORTER_ASSERT(r, clone.contains(T("World")));
277 REPORTER_ASSERT(r, !clone.contains(T("Goodbye")));
278 REPORTER_ASSERT(r, clone.find(T("Hello")));
279 REPORTER_ASSERT(r, *clone.find(T("Hello")) == T("Hello"));
280
281 set.remove(T("Hello"));
282 REPORTER_ASSERT(r, !set.contains(T("Hello")));
283 REPORTER_ASSERT(r, set.count() == 1);
284 REPORTER_ASSERT(r, clone.contains(T("Hello")));
285 REPORTER_ASSERT(r, clone.count() == 2);
286
287 set.reset();
288 REPORTER_ASSERT(r, set.count() == 0);
289
290 clone = set;
291 REPORTER_ASSERT(r, clone.count() == 0);
292}
int count() const
Definition: SkTHash.h:579
const T * find(const T &item) const
Definition: SkTHash.h:599
bool contains(const T &item) const
Definition: SkTHash.h:595
typename THashTable< T, T, Traits >::template Iter< T > Iter
Definition: SkTHash.h:620
#define T
Definition: precompiler.cc:65