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