Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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)
 

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/11]

DEF_TEST ( HashFindOrNull  ,
 
)

Definition at line 379 of file HashTest.cpp.

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

◆ DEF_TEST() [2/11]

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}
int count
#define N
Definition beziers.cpp:19
int count() const
Definition SkTHash.h:460
V * find(const K &key) const
Definition SkTHash.h:479
V * set(K key, V val)
Definition SkTHash.h:472
void remove(const K &key)
Definition SkTHash.h:494
typename THashTable< Pair, K >::template Iter< std::pair< K, V > > Iter
Definition SkTHash.h:525
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19

◆ DEF_TEST() [3/11]

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/11]

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/11]

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() [6/11]

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() [7/11]

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() [8/11]

DEF_TEST ( HashSetWithSkString  ,
 
)

Definition at line 294 of file HashTest.cpp.

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

◆ DEF_TEST() [9/11]

DEF_TEST ( HashSetWithStdString  ,
 
)

Definition at line 298 of file HashTest.cpp.

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

◆ DEF_TEST() [10/11]

DEF_TEST ( HashSetWithStdStringView  ,
 
)

Definition at line 302 of file HashTest.cpp.

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

◆ DEF_TEST() [11/11]

DEF_TEST ( HashTableGrowsAndShrinks  ,
 
)

Definition at line 400 of file HashTest.cpp.

400 {
402 auto check_count_cap = [&](int count, int cap) {
403 REPORTER_ASSERT(r, s.count() == count);
404 REPORTER_ASSERT(r, s.approxBytesUsed() == (sizeof(int) + sizeof(uint32_t)) * cap);
405 };
406
407 // Add and remove some elements to test basic growth and shrink patterns.
408 check_count_cap(0,0);
409 s.add(1); check_count_cap(1,4);
410 s.add(2); check_count_cap(2,4);
411 s.add(3); check_count_cap(3,4);
412 s.add(4); check_count_cap(4,8);
413
414 s.remove(4); check_count_cap(3,8);
415 s.remove(3); check_count_cap(2,4);
416 s.remove(2); check_count_cap(1,4);
417 s.remove(1); check_count_cap(0,4);
418
419 s.add(1); check_count_cap(1,4);
420 s.add(2); check_count_cap(2,4);
421 s.add(3); check_count_cap(3,4);
422 s.add(4); check_count_cap(4,8);
423
424 // Add and remove single elements repeatedly to test hysteresis
425 // avoids reallocating these small tables all the time.
426 for (int i = 0; i < 10; i++) {
427 s. add(5); check_count_cap(5,8);
428 s.remove(5); check_count_cap(4,8);
429 }
430
431 s.remove(4); check_count_cap(3,8);
432 for (int i = 0; i < 10; i++) {
433 s. add(4); check_count_cap(4,8);
434 s.remove(4); check_count_cap(3,8);
435 }
436
437 s.remove(3); check_count_cap(2,4);
438 for (int i = 0; i < 10; i++) {
439 s. add(4); check_count_cap(3,4);
440 s.remove(4); check_count_cap(2,4);
441 }
442
443 s.remove(2); check_count_cap(1,4);
444 for (int i = 0; i < 10; i++) {
445 s. add(2); check_count_cap(2,4);
446 s.remove(2); check_count_cap(1,4);
447 }
448}
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:564
const T * find(const T &item) const
Definition SkTHash.h:580
bool contains(const T &item) const
Definition SkTHash.h:576
typename THashTable< T, T, Traits >::template Iter< T > Iter
Definition SkTHash.h:601
#define T