1 /* Apache License, Version 2.0 */
2
3 #include "BLI_exception_safety_test_utils.hh"
4 #include "BLI_map.hh"
5 #include "BLI_rand.h"
6 #include "BLI_set.hh"
7 #include "BLI_strict_flags.h"
8 #include "BLI_timeit.hh"
9 #include "BLI_vector.hh"
10 #include "testing/testing.h"
11
12 namespace blender::tests {
13
TEST(map,DefaultConstructor)14 TEST(map, DefaultConstructor)
15 {
16 Map<int, float> map;
17 EXPECT_EQ(map.size(), 0);
18 EXPECT_TRUE(map.is_empty());
19 }
20
TEST(map,AddIncreasesSize)21 TEST(map, AddIncreasesSize)
22 {
23 Map<int, float> map;
24 EXPECT_EQ(map.size(), 0);
25 EXPECT_TRUE(map.is_empty());
26 map.add(2, 5.0f);
27 EXPECT_EQ(map.size(), 1);
28 EXPECT_FALSE(map.is_empty());
29 map.add(6, 2.0f);
30 EXPECT_EQ(map.size(), 2);
31 EXPECT_FALSE(map.is_empty());
32 }
33
TEST(map,Contains)34 TEST(map, Contains)
35 {
36 Map<int, float> map;
37 EXPECT_FALSE(map.contains(4));
38 map.add(5, 6.0f);
39 EXPECT_FALSE(map.contains(4));
40 map.add(4, 2.0f);
41 EXPECT_TRUE(map.contains(4));
42 }
43
TEST(map,LookupExisting)44 TEST(map, LookupExisting)
45 {
46 Map<int, float> map;
47 map.add(2, 6.0f);
48 map.add(4, 1.0f);
49 EXPECT_EQ(map.lookup(2), 6.0f);
50 EXPECT_EQ(map.lookup(4), 1.0f);
51 }
52
TEST(map,LookupNotExisting)53 TEST(map, LookupNotExisting)
54 {
55 Map<int, float> map;
56 map.add(2, 4.0f);
57 map.add(1, 1.0f);
58 EXPECT_EQ(map.lookup_ptr(0), nullptr);
59 EXPECT_EQ(map.lookup_ptr(5), nullptr);
60 }
61
TEST(map,AddMany)62 TEST(map, AddMany)
63 {
64 Map<int, int> map;
65 for (int i = 0; i < 100; i++) {
66 map.add(i * 30, i);
67 map.add(i * 31, i);
68 }
69 }
70
TEST(map,PopItem)71 TEST(map, PopItem)
72 {
73 Map<int, float> map;
74 map.add(2, 3.0f);
75 map.add(1, 9.0f);
76 EXPECT_TRUE(map.contains(2));
77 EXPECT_TRUE(map.contains(1));
78
79 EXPECT_EQ(map.pop(1), 9.0f);
80 EXPECT_TRUE(map.contains(2));
81 EXPECT_FALSE(map.contains(1));
82
83 EXPECT_EQ(map.pop(2), 3.0f);
84 EXPECT_FALSE(map.contains(2));
85 EXPECT_FALSE(map.contains(1));
86 }
87
TEST(map,PopTry)88 TEST(map, PopTry)
89 {
90 Map<int, int> map;
91 map.add(1, 5);
92 map.add(2, 7);
93 EXPECT_EQ(map.size(), 2);
94 std::optional<int> value = map.pop_try(4);
95 EXPECT_EQ(map.size(), 2);
96 EXPECT_FALSE(value.has_value());
97 value = map.pop_try(2);
98 EXPECT_EQ(map.size(), 1);
99 EXPECT_TRUE(value.has_value());
100 EXPECT_EQ(*value, 7);
101 EXPECT_EQ(*map.pop_try(1), 5);
102 EXPECT_EQ(map.size(), 0);
103 }
104
TEST(map,PopDefault)105 TEST(map, PopDefault)
106 {
107 Map<int, int> map;
108 map.add(1, 4);
109 map.add(2, 7);
110 map.add(3, 8);
111 EXPECT_EQ(map.size(), 3);
112 EXPECT_EQ(map.pop_default(4, 10), 10);
113 EXPECT_EQ(map.size(), 3);
114 EXPECT_EQ(map.pop_default(1, 10), 4);
115 EXPECT_EQ(map.size(), 2);
116 EXPECT_EQ(map.pop_default(2, 20), 7);
117 EXPECT_EQ(map.size(), 1);
118 EXPECT_EQ(map.pop_default(2, 20), 20);
119 EXPECT_EQ(map.size(), 1);
120 EXPECT_EQ(map.pop_default(3, 0), 8);
121 EXPECT_EQ(map.size(), 0);
122 }
123
TEST(map,PopItemMany)124 TEST(map, PopItemMany)
125 {
126 Map<int, int> map;
127 for (int i = 0; i < 100; i++) {
128 map.add_new(i, i);
129 }
130 for (int i = 25; i < 80; i++) {
131 EXPECT_EQ(map.pop(i), i);
132 }
133 for (int i = 0; i < 100; i++) {
134 EXPECT_EQ(map.contains(i), i < 25 || i >= 80);
135 }
136 }
137
TEST(map,ValueIterator)138 TEST(map, ValueIterator)
139 {
140 Map<int, float> map;
141 map.add(3, 5.0f);
142 map.add(1, 2.0f);
143 map.add(7, -2.0f);
144
145 blender::Set<float> values;
146
147 int iterations = 0;
148 for (float value : map.values()) {
149 values.add(value);
150 iterations++;
151 }
152
153 EXPECT_EQ(iterations, 3);
154 EXPECT_TRUE(values.contains(5.0f));
155 EXPECT_TRUE(values.contains(-2.0f));
156 EXPECT_TRUE(values.contains(2.0f));
157 }
158
TEST(map,KeyIterator)159 TEST(map, KeyIterator)
160 {
161 Map<int, float> map;
162 map.add(6, 3.0f);
163 map.add(2, 4.0f);
164 map.add(1, 3.0f);
165
166 blender::Set<int> keys;
167
168 int iterations = 0;
169 for (int key : map.keys()) {
170 keys.add(key);
171 iterations++;
172 }
173
174 EXPECT_EQ(iterations, 3);
175 EXPECT_TRUE(keys.contains(1));
176 EXPECT_TRUE(keys.contains(2));
177 EXPECT_TRUE(keys.contains(6));
178 }
179
TEST(map,ItemIterator)180 TEST(map, ItemIterator)
181 {
182 Map<int, float> map;
183 map.add(5, 3.0f);
184 map.add(2, 9.0f);
185 map.add(1, 0.0f);
186
187 blender::Set<int> keys;
188 blender::Set<float> values;
189
190 int iterations = 0;
191 const Map<int, float> &const_map = map;
192 for (auto item : const_map.items()) {
193 keys.add(item.key);
194 values.add(item.value);
195 iterations++;
196 }
197
198 EXPECT_EQ(iterations, 3);
199 EXPECT_TRUE(keys.contains(5));
200 EXPECT_TRUE(keys.contains(2));
201 EXPECT_TRUE(keys.contains(1));
202 EXPECT_TRUE(values.contains(3.0f));
203 EXPECT_TRUE(values.contains(9.0f));
204 EXPECT_TRUE(values.contains(0.0f));
205 }
206
TEST(map,MutableValueIterator)207 TEST(map, MutableValueIterator)
208 {
209 Map<int, int> map;
210 map.add(3, 6);
211 map.add(2, 1);
212
213 for (int &value : map.values()) {
214 value += 10;
215 }
216
217 EXPECT_EQ(map.lookup(3), 16);
218 EXPECT_EQ(map.lookup(2), 11);
219 }
220
TEST(map,MutableItemIterator)221 TEST(map, MutableItemIterator)
222 {
223 Map<int, int> map;
224 map.add(3, 6);
225 map.add(2, 1);
226
227 for (auto item : map.items()) {
228 item.value += item.key;
229 }
230
231 EXPECT_EQ(map.lookup(3), 9.0f);
232 EXPECT_EQ(map.lookup(2), 3.0f);
233 }
234
TEST(map,MutableItemToItemConversion)235 TEST(map, MutableItemToItemConversion)
236 {
237 Map<int, int> map;
238 map.add(3, 6);
239 map.add(2, 1);
240
241 Vector<int> keys, values;
242 for (Map<int, int>::Item item : map.items()) {
243 keys.append(item.key);
244 values.append(item.value);
245 }
246
247 EXPECT_EQ(keys.size(), 2);
248 EXPECT_EQ(values.size(), 2);
249 EXPECT_TRUE(keys.contains(3));
250 EXPECT_TRUE(keys.contains(2));
251 EXPECT_TRUE(values.contains(6));
252 EXPECT_TRUE(values.contains(1));
253 }
254
return_42()255 static float return_42()
256 {
257 return 42.0f;
258 }
259
TEST(map,LookupOrAddCB_SeparateFunction)260 TEST(map, LookupOrAddCB_SeparateFunction)
261 {
262 Map<int, float> map;
263 EXPECT_EQ(map.lookup_or_add_cb(0, return_42), 42.0f);
264 EXPECT_EQ(map.lookup(0), 42);
265
266 map.keys();
267 }
268
TEST(map,LookupOrAddCB_Lambdas)269 TEST(map, LookupOrAddCB_Lambdas)
270 {
271 Map<int, float> map;
272 auto lambda1 = []() { return 11.0f; };
273 EXPECT_EQ(map.lookup_or_add_cb(0, lambda1), 11.0f);
274 auto lambda2 = []() { return 20.0f; };
275 EXPECT_EQ(map.lookup_or_add_cb(1, lambda2), 20.0f);
276
277 EXPECT_EQ(map.lookup_or_add_cb(0, lambda2), 11.0f);
278 EXPECT_EQ(map.lookup_or_add_cb(1, lambda1), 20.0f);
279 }
280
TEST(map,AddOrModify)281 TEST(map, AddOrModify)
282 {
283 Map<int, float> map;
284 auto create_func = [](float *value) {
285 *value = 10.0f;
286 return true;
287 };
288 auto modify_func = [](float *value) {
289 *value += 5;
290 return false;
291 };
292 EXPECT_TRUE(map.add_or_modify(1, create_func, modify_func));
293 EXPECT_EQ(map.lookup(1), 10.0f);
294 EXPECT_FALSE(map.add_or_modify(1, create_func, modify_func));
295 EXPECT_EQ(map.lookup(1), 15.0f);
296 }
297
TEST(map,AddOverwrite)298 TEST(map, AddOverwrite)
299 {
300 Map<int, float> map;
301 EXPECT_FALSE(map.contains(3));
302 EXPECT_TRUE(map.add_overwrite(3, 6.0f));
303 EXPECT_EQ(map.lookup(3), 6.0f);
304 EXPECT_FALSE(map.add_overwrite(3, 7.0f));
305 EXPECT_EQ(map.lookup(3), 7.0f);
306 EXPECT_FALSE(map.add(3, 8.0f));
307 EXPECT_EQ(map.lookup(3), 7.0f);
308 }
309
TEST(map,LookupOrAddDefault)310 TEST(map, LookupOrAddDefault)
311 {
312 Map<int, float> map;
313 map.lookup_or_add_default(3) = 6;
314 EXPECT_EQ(map.lookup(3), 6);
315 map.lookup_or_add_default(5) = 2;
316 EXPECT_EQ(map.lookup(5), 2);
317 map.lookup_or_add_default(3) += 4;
318 EXPECT_EQ(map.lookup(3), 10);
319 }
320
TEST(map,LookupOrAdd)321 TEST(map, LookupOrAdd)
322 {
323 Map<int, int> map;
324 EXPECT_EQ(map.lookup_or_add(6, 4), 4);
325 EXPECT_EQ(map.lookup_or_add(6, 5), 4);
326 map.lookup_or_add(6, 4) += 10;
327 EXPECT_EQ(map.lookup(6), 14);
328 }
329
TEST(map,MoveConstructorSmall)330 TEST(map, MoveConstructorSmall)
331 {
332 Map<int, float> map1;
333 map1.add(1, 2.0f);
334 map1.add(4, 1.0f);
335 Map<int, float> map2(std::move(map1));
336 EXPECT_EQ(map2.size(), 2);
337 EXPECT_EQ(map2.lookup(1), 2.0f);
338 EXPECT_EQ(map2.lookup(4), 1.0f);
339 EXPECT_EQ(map1.size(), 0); /* NOLINT: bugprone-use-after-move */
340 EXPECT_EQ(map1.lookup_ptr(4), nullptr);
341 }
342
TEST(map,MoveConstructorLarge)343 TEST(map, MoveConstructorLarge)
344 {
345 Map<int, int> map1;
346 for (int i = 0; i < 100; i++) {
347 map1.add_new(i, i);
348 }
349 Map<int, int> map2(std::move(map1));
350 EXPECT_EQ(map2.size(), 100);
351 EXPECT_EQ(map2.lookup(1), 1);
352 EXPECT_EQ(map2.lookup(4), 4);
353 EXPECT_EQ(map1.size(), 0); /* NOLINT: bugprone-use-after-move */
354 EXPECT_EQ(map1.lookup_ptr(4), nullptr);
355 }
356
TEST(map,MoveAssignment)357 TEST(map, MoveAssignment)
358 {
359 Map<int, float> map1;
360 map1.add(1, 2.0f);
361 map1.add(4, 1.0f);
362 Map<int, float> map2;
363 map2 = std::move(map1);
364 EXPECT_EQ(map2.size(), 2);
365 EXPECT_EQ(map2.lookup(1), 2.0f);
366 EXPECT_EQ(map2.lookup(4), 1.0f);
367 EXPECT_EQ(map1.size(), 0); /* NOLINT: bugprone-use-after-move */
368 EXPECT_EQ(map1.lookup_ptr(4), nullptr);
369 }
370
TEST(map,CopyAssignment)371 TEST(map, CopyAssignment)
372 {
373 Map<int, float> map1;
374 map1.add(1, 2.0f);
375 map1.add(4, 1.0f);
376 Map<int, float> map2;
377 map2 = map1;
378 EXPECT_EQ(map2.size(), 2);
379 EXPECT_EQ(map2.lookup(1), 2.0f);
380 EXPECT_EQ(map2.lookup(4), 1.0f);
381 EXPECT_EQ(map1.size(), 2);
382 EXPECT_EQ(*map1.lookup_ptr(4), 1.0f);
383 }
384
TEST(map,Clear)385 TEST(map, Clear)
386 {
387 Map<int, float> map;
388 map.add(1, 1.0f);
389 map.add(2, 5.0f);
390
391 EXPECT_EQ(map.size(), 2);
392 EXPECT_TRUE(map.contains(1));
393 EXPECT_TRUE(map.contains(2));
394
395 map.clear();
396
397 EXPECT_EQ(map.size(), 0);
398 EXPECT_FALSE(map.contains(1));
399 EXPECT_FALSE(map.contains(2));
400 }
401
TEST(map,UniquePtrValue)402 TEST(map, UniquePtrValue)
403 {
404 auto value1 = std::unique_ptr<int>(new int());
405 auto value2 = std::unique_ptr<int>(new int());
406 auto value3 = std::unique_ptr<int>(new int());
407
408 int *value1_ptr = value1.get();
409
410 Map<int, std::unique_ptr<int>> map;
411 map.add_new(1, std::move(value1));
412 map.add(2, std::move(value2));
413 map.add_overwrite(3, std::move(value3));
414 map.lookup_or_add_cb(4, []() { return std::unique_ptr<int>(new int()); });
415 map.add_new(5, std::unique_ptr<int>(new int()));
416 map.add(6, std::unique_ptr<int>(new int()));
417 map.add_overwrite(7, std::unique_ptr<int>(new int()));
418 map.lookup_or_add(8, std::unique_ptr<int>(new int()));
419 map.pop_default(9, std::unique_ptr<int>(new int()));
420
421 EXPECT_EQ(map.lookup(1).get(), value1_ptr);
422 EXPECT_EQ(map.lookup_ptr(100), nullptr);
423 }
424
TEST(map,Remove)425 TEST(map, Remove)
426 {
427 Map<int, int> map;
428 map.add(2, 4);
429 EXPECT_EQ(map.size(), 1);
430 EXPECT_FALSE(map.remove(3));
431 EXPECT_EQ(map.size(), 1);
432 EXPECT_TRUE(map.remove(2));
433 EXPECT_EQ(map.size(), 0);
434 }
435
TEST(map,PointerKeys)436 TEST(map, PointerKeys)
437 {
438 char a, b, c, d;
439
440 Map<char *, int> map;
441 EXPECT_TRUE(map.add(&a, 5));
442 EXPECT_FALSE(map.add(&a, 4));
443 map.add_new(&b, 1);
444 map.add_new(&c, 1);
445 EXPECT_EQ(map.size(), 3);
446 EXPECT_TRUE(map.remove(&b));
447 EXPECT_TRUE(map.add(&b, 8));
448 EXPECT_FALSE(map.remove(&d));
449 EXPECT_TRUE(map.remove(&a));
450 EXPECT_TRUE(map.remove(&b));
451 EXPECT_TRUE(map.remove(&c));
452 EXPECT_TRUE(map.is_empty());
453 }
454
TEST(map,ConstKeysAndValues)455 TEST(map, ConstKeysAndValues)
456 {
457 Map<const std::string, const std::string> map;
458 map.reserve(10);
459 map.add("45", "643");
460 EXPECT_TRUE(map.contains("45"));
461 EXPECT_FALSE(map.contains("54"));
462 }
463
TEST(map,ForeachItem)464 TEST(map, ForeachItem)
465 {
466 Map<int, int> map;
467 map.add(3, 4);
468 map.add(1, 8);
469
470 Vector<int> keys;
471 Vector<int> values;
472 map.foreach_item([&](int key, int value) {
473 keys.append(key);
474 values.append(value);
475 });
476
477 EXPECT_EQ(keys.size(), 2);
478 EXPECT_EQ(values.size(), 2);
479 EXPECT_EQ(keys.first_index_of(3), values.first_index_of(4));
480 EXPECT_EQ(keys.first_index_of(1), values.first_index_of(8));
481 }
482
TEST(map,CopyConstructorExceptions)483 TEST(map, CopyConstructorExceptions)
484 {
485 using MapType = Map<ExceptionThrower, ExceptionThrower>;
486 MapType map;
487 map.add(2, 2);
488 map.add(4, 4);
489 map.lookup(2).throw_during_copy = true;
490 EXPECT_ANY_THROW({ MapType map_copy(map); });
491 }
492
TEST(map,MoveConstructorExceptions)493 TEST(map, MoveConstructorExceptions)
494 {
495 using MapType = Map<ExceptionThrower, ExceptionThrower>;
496 MapType map;
497 map.add(1, 1);
498 map.add(2, 2);
499 map.lookup(1).throw_during_move = true;
500 EXPECT_ANY_THROW({ MapType map_moved(std::move(map)); });
501 map.add(5, 5); /* NOLINT: bugprone-use-after-move */
502 }
503
TEST(map,AddNewExceptions)504 TEST(map, AddNewExceptions)
505 {
506 Map<ExceptionThrower, ExceptionThrower> map;
507 ExceptionThrower key1 = 1;
508 key1.throw_during_copy = true;
509 ExceptionThrower value1;
510 EXPECT_ANY_THROW({ map.add_new(key1, value1); });
511 EXPECT_EQ(map.size(), 0);
512 ExceptionThrower key2 = 2;
513 ExceptionThrower value2;
514 value2.throw_during_copy = true;
515 EXPECT_ANY_THROW({ map.add_new(key2, value2); });
516 }
517
TEST(map,ReserveExceptions)518 TEST(map, ReserveExceptions)
519 {
520 Map<ExceptionThrower, ExceptionThrower> map;
521 map.add(3, 3);
522 map.add(5, 5);
523 map.add(2, 2);
524 map.lookup(2).throw_during_move = true;
525 EXPECT_ANY_THROW({ map.reserve(100); });
526 map.add(1, 1);
527 map.add(5, 5);
528 }
529
TEST(map,PopExceptions)530 TEST(map, PopExceptions)
531 {
532 Map<ExceptionThrower, ExceptionThrower> map;
533 map.add(3, 3);
534 map.lookup(3).throw_during_move = true;
535 EXPECT_ANY_THROW({ map.pop(3); }); /* NOLINT: bugprone-throw-keyword-missing */
536 EXPECT_EQ(map.size(), 1);
537 map.add(1, 1);
538 EXPECT_EQ(map.size(), 2);
539 }
540
TEST(map,AddOrModifyExceptions)541 TEST(map, AddOrModifyExceptions)
542 {
543 Map<ExceptionThrower, ExceptionThrower> map;
544 auto create_fn = [](ExceptionThrower *UNUSED(v)) { throw std::runtime_error(""); };
545 auto modify_fn = [](ExceptionThrower *UNUSED(v)) {};
546 EXPECT_ANY_THROW({ map.add_or_modify(3, create_fn, modify_fn); });
547 }
548
549 /**
550 * Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
551 */
552 #if 0
553 template<typename MapT>
554 BLI_NOINLINE void benchmark_random_ints(StringRef name, int amount, int factor)
555 {
556 RNG *rng = BLI_rng_new(0);
557 Vector<int> values;
558 for (int i = 0; i < amount; i++) {
559 values.append(BLI_rng_get_int(rng) * factor);
560 }
561 BLI_rng_free(rng);
562
563 MapT map;
564 {
565 SCOPED_TIMER(name + " Add");
566 for (int value : values) {
567 map.add(value, value);
568 }
569 }
570 int count = 0;
571 {
572 SCOPED_TIMER(name + " Contains");
573 for (int value : values) {
574 count += map.contains(value);
575 }
576 }
577 {
578 SCOPED_TIMER(name + " Remove");
579 for (int value : values) {
580 count += map.remove(value);
581 }
582 }
583
584 /* Print the value for simple error checking and to avoid some compiler optimizations. */
585 std::cout << "Count: " << count << "\n";
586 }
587
588 TEST(map, Benchmark)
589 {
590 for (int i = 0; i < 3; i++) {
591 benchmark_random_ints<blender::Map<int, int>>("blender::Map ", 1000000, 1);
592 benchmark_random_ints<blender::StdUnorderedMapWrapper<int, int>>("std::unordered_map", 1000000, 1);
593 }
594 std::cout << "\n";
595 for (int i = 0; i < 3; i++) {
596 uint32_t factor = (3 << 10);
597 benchmark_random_ints<blender::Map<int, int>>("blender::Map ", 1000000, factor);
598 benchmark_random_ints<blender::StdUnorderedMapWrapper<int, int>>(
599 "std::unordered_map", 1000000, factor);
600 }
601 }
602
603 /**
604 * Timer 'blender::Map Add' took 61.7616 ms
605 * Timer 'blender::Map Contains' took 18.4989 ms
606 * Timer 'blender::Map Remove' took 20.5864 ms
607 * Count: 1999755
608 * Timer 'std::unordered_map Add' took 188.674 ms
609 * Timer 'std::unordered_map Contains' took 44.3741 ms
610 * Timer 'std::unordered_map Remove' took 169.52 ms
611 * Count: 1999755
612 * Timer 'blender::Map Add' took 37.9196 ms
613 * Timer 'blender::Map Contains' took 16.7361 ms
614 * Timer 'blender::Map Remove' took 20.9568 ms
615 * Count: 1999755
616 * Timer 'std::unordered_map Add' took 166.09 ms
617 * Timer 'std::unordered_map Contains' took 40.6133 ms
618 * Timer 'std::unordered_map Remove' took 142.85 ms
619 * Count: 1999755
620 * Timer 'blender::Map Add' took 37.3053 ms
621 * Timer 'blender::Map Contains' took 16.6731 ms
622 * Timer 'blender::Map Remove' took 18.8304 ms
623 * Count: 1999755
624 * Timer 'std::unordered_map Add' took 170.964 ms
625 * Timer 'std::unordered_map Contains' took 38.1824 ms
626 * Timer 'std::unordered_map Remove' took 140.263 ms
627 * Count: 1999755
628 *
629 * Timer 'blender::Map Add' took 50.1131 ms
630 * Timer 'blender::Map Contains' took 25.0491 ms
631 * Timer 'blender::Map Remove' took 32.4225 ms
632 * Count: 1889920
633 * Timer 'std::unordered_map Add' took 150.129 ms
634 * Timer 'std::unordered_map Contains' took 34.6999 ms
635 * Timer 'std::unordered_map Remove' took 120.907 ms
636 * Count: 1889920
637 * Timer 'blender::Map Add' took 50.4438 ms
638 * Timer 'blender::Map Contains' took 25.2677 ms
639 * Timer 'blender::Map Remove' took 32.3047 ms
640 * Count: 1889920
641 * Timer 'std::unordered_map Add' took 144.015 ms
642 * Timer 'std::unordered_map Contains' took 36.3387 ms
643 * Timer 'std::unordered_map Remove' took 119.109 ms
644 * Count: 1889920
645 * Timer 'blender::Map Add' took 48.6995 ms
646 * Timer 'blender::Map Contains' took 25.1846 ms
647 * Timer 'blender::Map Remove' took 33.0283 ms
648 * Count: 1889920
649 * Timer 'std::unordered_map Add' took 143.494 ms
650 * Timer 'std::unordered_map Contains' took 34.8905 ms
651 * Timer 'std::unordered_map Remove' took 122.739 ms
652 * Count: 1889920
653 */
654
655 #endif /* Benchmark */
656
657 } // namespace blender::tests
658