Blender V5.0
BLI_map_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include <memory>
6#include <unordered_map>
7
8#include "testing/testing.h"
9
11#include "BLI_map.hh"
12#include "BLI_rand.h"
13#include "BLI_set.hh"
14#include "BLI_timeit.hh"
15#include "BLI_vector.hh"
16
17#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
18
19namespace blender::tests {
20
21TEST(map, DefaultConstructor)
22{
24 EXPECT_EQ(map.size(), 0);
25 EXPECT_TRUE(map.is_empty());
26}
27
28TEST(map, ItemsConstructor)
29{
30 {
31 Map<int, std::string> map = {{1, "where"}, {3, "when"}, {5, "why"}};
32 EXPECT_EQ(map.size(), 3);
33 EXPECT_EQ(map.lookup(1), "where");
34 EXPECT_EQ(map.lookup(3), "when");
35 EXPECT_EQ(map.lookup(5), "why");
36 }
37 {
38 Map<int, std::string> map{{1, "where"}, {3, "when"}, {5, "why"}};
39 EXPECT_EQ(map.size(), 3);
40 EXPECT_EQ(map.lookup(1), "where");
41 EXPECT_EQ(map.lookup(3), "when");
42 EXPECT_EQ(map.lookup(5), "why");
43 }
44 {
45 Map<int, std::string> map{{{1, "where"}, {3, "when"}, {5, "why"}}};
46 EXPECT_EQ(map.size(), 3);
47 EXPECT_EQ(map.lookup(1), "where");
48 EXPECT_EQ(map.lookup(3), "when");
49 EXPECT_EQ(map.lookup(5), "why");
50 }
51 {
52 const Array<std::pair<int, std::string>> items = {{1, "where"}, {3, "when"}, {5, "why"}};
53 Map<int, std::string> map{items};
54 EXPECT_EQ(map.size(), 3);
55 EXPECT_EQ(map.lookup(1), "where");
56 EXPECT_EQ(map.lookup(3), "when");
57 EXPECT_EQ(map.lookup(5), "why");
58 }
59}
60
61TEST(map, ItemsConstructorDuplicates)
62{
63 Map<int, int> map = {{1, 2}, {3, 4}, {1, 4}, {2, 5}, {2, 6}};
64 EXPECT_EQ(map.size(), 3);
65 EXPECT_EQ(map.lookup(1), 2);
66 EXPECT_EQ(map.lookup(2), 5);
67 EXPECT_EQ(map.lookup(3), 4);
68}
69
70TEST(map, AddIncreasesSize)
71{
73 EXPECT_EQ(map.size(), 0);
74 EXPECT_TRUE(map.is_empty());
75 map.add(2, 5.0f);
76 EXPECT_EQ(map.size(), 1);
77 EXPECT_FALSE(map.is_empty());
78 map.add(6, 2.0f);
79 EXPECT_EQ(map.size(), 2);
80 EXPECT_FALSE(map.is_empty());
81}
82
83TEST(map, Contains)
84{
86 EXPECT_FALSE(map.contains(4));
87 map.add(5, 6.0f);
88 EXPECT_FALSE(map.contains(4));
89 map.add(4, 2.0f);
90 EXPECT_TRUE(map.contains(4));
91}
92
93TEST(map, LookupExisting)
94{
96 map.add(2, 6.0f);
97 map.add(4, 1.0f);
98 EXPECT_EQ(map.lookup(2), 6.0f);
99 EXPECT_EQ(map.lookup(4), 1.0f);
100}
101
102TEST(map, LookupNotExisting)
103{
104 Map<int, float> map;
105 map.add(2, 4.0f);
106 map.add(1, 1.0f);
107 EXPECT_EQ(map.lookup_ptr(0), nullptr);
108 EXPECT_EQ(map.lookup_ptr(5), nullptr);
109}
110
111TEST(map, AddMany)
112{
113 Map<int, int> map;
114 for (int i = 0; i < 100; i++) {
115 map.add(i * 30, i);
116 map.add(i * 31, i);
117 }
118}
119
120TEST(map, PopItem)
121{
122 Map<int, float> map;
123 map.add(2, 3.0f);
124 map.add(1, 9.0f);
125 EXPECT_TRUE(map.contains(2));
126 EXPECT_TRUE(map.contains(1));
127
128 EXPECT_EQ(map.pop(1), 9.0f);
129 EXPECT_TRUE(map.contains(2));
130 EXPECT_FALSE(map.contains(1));
131
132 EXPECT_EQ(map.pop(2), 3.0f);
133 EXPECT_FALSE(map.contains(2));
134 EXPECT_FALSE(map.contains(1));
135}
136
137TEST(map, PopTry)
138{
139 Map<int, int> map;
140 map.add(1, 5);
141 map.add(2, 7);
142 EXPECT_EQ(map.size(), 2);
143 std::optional<int> value = map.pop_try(4);
144 EXPECT_EQ(map.size(), 2);
145 EXPECT_FALSE(value.has_value());
146 value = map.pop_try(2);
147 EXPECT_EQ(map.size(), 1);
148 EXPECT_TRUE(value.has_value());
149 EXPECT_EQ(*value, 7);
150 EXPECT_EQ(*map.pop_try(1), 5);
151 EXPECT_EQ(map.size(), 0);
152}
153
154TEST(map, PopDefault)
155{
156 Map<int, int> map;
157 map.add(1, 4);
158 map.add(2, 7);
159 map.add(3, 8);
160 EXPECT_EQ(map.size(), 3);
161 EXPECT_EQ(map.pop_default(4, 10), 10);
162 EXPECT_EQ(map.size(), 3);
163 EXPECT_EQ(map.pop_default(1, 10), 4);
164 EXPECT_EQ(map.size(), 2);
165 EXPECT_EQ(map.pop_default(2, 20), 7);
166 EXPECT_EQ(map.size(), 1);
167 EXPECT_EQ(map.pop_default(2, 20), 20);
168 EXPECT_EQ(map.size(), 1);
169 EXPECT_EQ(map.pop_default(3, 0), 8);
170 EXPECT_EQ(map.size(), 0);
171}
172
173TEST(map, PopItemMany)
174{
175 Map<int, int> map;
176 for (int i = 0; i < 100; i++) {
177 map.add_new(i, i);
178 }
179 for (int i = 25; i < 80; i++) {
180 EXPECT_EQ(map.pop(i), i);
181 }
182 for (int i = 0; i < 100; i++) {
184 }
185}
186
187TEST(map, ValueIterator)
188{
189 Map<int, float> map;
190 map.add(3, 5.0f);
191 map.add(1, 2.0f);
192 map.add(7, -2.0f);
193
194 blender::Set<float> values;
195
196 int iterations = 0;
197 for (float value : map.values()) {
198 values.add(value);
199 iterations++;
200 }
201
202 EXPECT_EQ(iterations, 3);
203 EXPECT_TRUE(values.contains(5.0f));
204 EXPECT_TRUE(values.contains(-2.0f));
205 EXPECT_TRUE(values.contains(2.0f));
206}
207
208TEST(map, KeyIterator)
209{
210 Map<int, float> map;
211 map.add(6, 3.0f);
212 map.add(2, 4.0f);
213 map.add(1, 3.0f);
214
216
217 int iterations = 0;
218 for (int key : map.keys()) {
219 keys.add(key);
220 iterations++;
221 }
222
223 EXPECT_EQ(iterations, 3);
224 EXPECT_TRUE(keys.contains(1));
225 EXPECT_TRUE(keys.contains(2));
226 EXPECT_TRUE(keys.contains(6));
227}
228
230{
231 Map<int, float> map;
232 map.add(5, 3.0f);
233 map.add(2, 9.0f);
234 map.add(1, 0.0f);
235
237 blender::Set<float> values;
238
239 int iterations = 0;
240 const Map<int, float> &const_map = map;
241 for (auto item : const_map.items()) {
242 keys.add(item.key);
243 values.add(item.value);
244 iterations++;
245 }
246
247 EXPECT_EQ(iterations, 3);
248 EXPECT_TRUE(keys.contains(5));
249 EXPECT_TRUE(keys.contains(2));
250 EXPECT_TRUE(keys.contains(1));
251 EXPECT_TRUE(values.contains(3.0f));
252 EXPECT_TRUE(values.contains(9.0f));
253 EXPECT_TRUE(values.contains(0.0f));
254}
255
256TEST(map, MutableValueIterator)
257{
258 Map<int, int> map;
259 map.add(3, 6);
260 map.add(2, 1);
261
262 for (int &value : map.values()) {
263 value += 10;
264 }
265
266 EXPECT_EQ(map.lookup(3), 16);
267 EXPECT_EQ(map.lookup(2), 11);
268}
269
270TEST(map, MutableItemIterator)
271{
272 Map<int, int> map;
273 map.add(3, 6);
274 map.add(2, 1);
275
276 for (auto item : map.items()) {
277 item.value += item.key;
278 }
279
280 EXPECT_EQ(map.lookup(3), 9.0f);
281 EXPECT_EQ(map.lookup(2), 3.0f);
282}
283
284TEST(map, MutableItemToItemConversion)
285{
286 Map<int, int> map;
287 map.add(3, 6);
288 map.add(2, 1);
289
290 Vector<int> keys, values;
291 for (MapItem<int, int> item : map.items()) {
292 keys.append(item.key);
293 values.append(item.value);
294 }
295
296 EXPECT_EQ(keys.size(), 2);
297 EXPECT_EQ(values.size(), 2);
298 EXPECT_TRUE(keys.contains(3));
299 EXPECT_TRUE(keys.contains(2));
300 EXPECT_TRUE(values.contains(6));
301 EXPECT_TRUE(values.contains(1));
302}
303
304static float return_42()
305{
306 return 42.0f;
307}
308
309TEST(map, LookupOrAddCB_SeparateFunction)
310{
311 Map<int, float> map;
312 EXPECT_EQ(map.lookup_or_add_cb(0, return_42), 42.0f);
313 EXPECT_EQ(map.lookup(0), 42);
314
315 map.keys();
316}
317
318TEST(map, LookupOrAddCB_Lambdas)
319{
320 Map<int, float> map;
321 auto lambda1 = []() { return 11.0f; };
322 EXPECT_EQ(map.lookup_or_add_cb(0, lambda1), 11.0f);
323 auto lambda2 = []() { return 20.0f; };
324 EXPECT_EQ(map.lookup_or_add_cb(1, lambda2), 20.0f);
325
326 EXPECT_EQ(map.lookup_or_add_cb(0, lambda2), 11.0f);
327 EXPECT_EQ(map.lookup_or_add_cb(1, lambda1), 20.0f);
328}
329
330TEST(map, AddOrModify)
331{
332 Map<int, float> map;
333 auto create_func = [](float *value) {
334 *value = 10.0f;
335 return true;
336 };
337 auto modify_func = [](float *value) {
338 *value += 5;
339 return false;
340 };
341 EXPECT_TRUE(map.add_or_modify(1, create_func, modify_func));
342 EXPECT_EQ(map.lookup(1), 10.0f);
343 EXPECT_FALSE(map.add_or_modify(1, create_func, modify_func));
344 EXPECT_EQ(map.lookup(1), 15.0f);
345}
346
347TEST(map, AddOrModifyReference)
348{
350 auto create_func = [](std::unique_ptr<int> *value) -> int & {
351 new (value) std::unique_ptr<int>(new int{10});
352 return **value;
353 };
354 auto modify_func = [](std::unique_ptr<int> *value) -> int & {
355 **value += 5;
356 return **value;
357 };
358 EXPECT_EQ(map.add_or_modify(1, create_func, modify_func), 10);
359 int &a = map.add_or_modify(1, create_func, modify_func);
360 EXPECT_EQ(a, 15);
361 a = 100;
362 EXPECT_EQ(*map.lookup(1), 100);
363}
364
365TEST(map, AddOverwrite)
366{
367 Map<int, float> map;
368 EXPECT_FALSE(map.contains(3));
369 EXPECT_TRUE(map.add_overwrite(3, 6.0f));
370 EXPECT_EQ(map.lookup(3), 6.0f);
371 EXPECT_FALSE(map.add_overwrite(3, 7.0f));
372 EXPECT_EQ(map.lookup(3), 7.0f);
373 EXPECT_FALSE(map.add(3, 8.0f));
374 EXPECT_EQ(map.lookup(3), 7.0f);
375}
376
377TEST(map, LookupOrAddDefault)
378{
379 Map<int, float> map;
380 map.lookup_or_add_default(3) = 6;
381 EXPECT_EQ(map.lookup(3), 6);
382 map.lookup_or_add_default(5) = 2;
383 EXPECT_EQ(map.lookup(5), 2);
384 map.lookup_or_add_default(3) += 4;
385 EXPECT_EQ(map.lookup(3), 10);
386}
387
388TEST(map, LookupOrAdd)
389{
390 Map<int, int> map;
391 EXPECT_EQ(map.lookup_or_add(6, 4), 4);
392 EXPECT_EQ(map.lookup_or_add(6, 5), 4);
393 map.lookup_or_add(6, 4) += 10;
394 EXPECT_EQ(map.lookup(6), 14);
395}
396
397TEST(map, LookupTry)
398{
399 Map<int, int> map;
400 map.add(1, 10);
401 map.add(2, 20);
402 EXPECT_EQ(map.lookup_try(1), 10);
403 EXPECT_EQ(map.lookup_try(2), 20);
404 EXPECT_EQ(map.lookup_try(3), std::nullopt);
405}
406
407TEST(map, MoveConstructorSmall)
408{
409 Map<int, float> map1;
410 map1.add(1, 2.0f);
411 map1.add(4, 1.0f);
412 Map<int, float> map2(std::move(map1));
413 EXPECT_EQ(map2.size(), 2);
414 EXPECT_EQ(map2.lookup(1), 2.0f);
415 EXPECT_EQ(map2.lookup(4), 1.0f);
416 EXPECT_EQ(map1.size(), 0); /* NOLINT: bugprone-use-after-move */
417 EXPECT_EQ(map1.lookup_ptr(4), nullptr);
418}
419
420TEST(map, MoveConstructorLarge)
421{
422 Map<int, int> map1;
423 for (int i = 0; i < 100; i++) {
424 map1.add_new(i, i);
425 }
426 Map<int, int> map2(std::move(map1));
427 EXPECT_EQ(map2.size(), 100);
428 EXPECT_EQ(map2.lookup(1), 1);
429 EXPECT_EQ(map2.lookup(4), 4);
430 EXPECT_EQ(map1.size(), 0); /* NOLINT: bugprone-use-after-move */
431 EXPECT_EQ(map1.lookup_ptr(4), nullptr);
432}
433
434TEST(map, MoveAssignment)
435{
436 Map<int, float> map1;
437 map1.add(1, 2.0f);
438 map1.add(4, 1.0f);
439 Map<int, float> map2;
440 map2 = std::move(map1);
441 EXPECT_EQ(map2.size(), 2);
442 EXPECT_EQ(map2.lookup(1), 2.0f);
443 EXPECT_EQ(map2.lookup(4), 1.0f);
444 EXPECT_EQ(map1.size(), 0); /* NOLINT: bugprone-use-after-move */
445 EXPECT_EQ(map1.lookup_ptr(4), nullptr);
446}
447
448TEST(map, CopyAssignment)
449{
450 Map<int, float> map1;
451 map1.add(1, 2.0f);
452 map1.add(4, 1.0f);
453 Map<int, float> map2;
454 map2 = map1;
455 EXPECT_EQ(map2.size(), 2);
456 EXPECT_EQ(map2.lookup(1), 2.0f);
457 EXPECT_EQ(map2.lookup(4), 1.0f);
458 EXPECT_EQ(map1.size(), 2);
459 EXPECT_EQ(*map1.lookup_ptr(4), 1.0f);
460}
461
462TEST(map, Clear)
463{
464 Map<int, float> map;
465 map.add(1, 1.0f);
466 map.add(2, 5.0f);
467
468 EXPECT_EQ(map.size(), 2);
469 EXPECT_TRUE(map.contains(1));
470 EXPECT_TRUE(map.contains(2));
471
472 map.clear();
473
474 EXPECT_EQ(map.size(), 0);
475 EXPECT_FALSE(map.contains(1));
476 EXPECT_FALSE(map.contains(2));
477}
478
479TEST(map, UniquePtrValue)
480{
481 auto value1 = std::make_unique<int>();
482 auto value2 = std::make_unique<int>();
483 auto value3 = std::make_unique<int>();
484
485 int *value1_ptr = value1.get();
486
488 map.add_new(1, std::move(value1));
489 map.add(2, std::move(value2));
490 map.add_overwrite(3, std::move(value3));
491 map.lookup_or_add_cb(4, []() { return std::make_unique<int>(); });
492 map.add_new(5, std::make_unique<int>());
493 map.add(6, std::make_unique<int>());
494 map.add_overwrite(7, std::make_unique<int>());
495 map.lookup_or_add(8, std::make_unique<int>());
496 map.pop_default(9, std::make_unique<int>());
497
498 EXPECT_EQ(map.lookup(1).get(), value1_ptr);
499 EXPECT_EQ(map.lookup_ptr(100), nullptr);
500}
501
502TEST(map, Remove)
503{
504 Map<int, int> map;
505 map.add(2, 4);
506 EXPECT_EQ(map.size(), 1);
507 EXPECT_FALSE(map.remove(3));
508 EXPECT_EQ(map.size(), 1);
509 EXPECT_TRUE(map.remove(2));
510 EXPECT_EQ(map.size(), 0);
511}
512
513TEST(map, PointerKeys)
514{
515 char a, b, c, d;
516
518 EXPECT_TRUE(map.add(&a, 5));
519 EXPECT_FALSE(map.add(&a, 4));
520 map.add_new(&b, 1);
521 map.add_new(&c, 1);
522 EXPECT_EQ(map.size(), 3);
523 EXPECT_TRUE(map.remove(&b));
524 EXPECT_TRUE(map.add(&b, 8));
525 EXPECT_FALSE(map.remove(&d));
526 EXPECT_TRUE(map.remove(&a));
527 EXPECT_TRUE(map.remove(&b));
528 EXPECT_TRUE(map.remove(&c));
529 EXPECT_TRUE(map.is_empty());
530}
531
532TEST(map, ConstKeysAndValues)
533{
535 map.reserve(10);
536 map.add("45", "643");
537 EXPECT_TRUE(map.contains("45"));
538 EXPECT_FALSE(map.contains("54"));
539}
540
541TEST(map, ForeachItem)
542{
543 Map<int, int> map;
544 map.add(3, 4);
545 map.add(1, 8);
546
547 Vector<int> keys;
548 Vector<int> values;
549 map.foreach_item([&](int key, int value) {
550 keys.append(key);
551 values.append(value);
552 });
553
554 EXPECT_EQ(keys.size(), 2);
555 EXPECT_EQ(values.size(), 2);
556 EXPECT_EQ(keys.first_index_of(3), values.first_index_of(4));
557 EXPECT_EQ(keys.first_index_of(1), values.first_index_of(8));
558}
559
560TEST(map, CopyConstructorExceptions)
561{
563 MapType map;
564 map.add(2, 2);
565 map.add(4, 4);
566 map.lookup(2).throw_during_copy = true;
567 EXPECT_ANY_THROW({ MapType map_copy(map); });
568}
569
570TEST(map, MoveConstructorExceptions)
571{
573 MapType map;
574 map.add(1, 1);
575 map.add(2, 2);
576 map.lookup(1).throw_during_move = true;
577 EXPECT_ANY_THROW({ MapType map_moved(std::move(map)); });
578 map.add(5, 5); /* NOLINT: bugprone-use-after-move */
579}
580
581TEST(map, AddNewExceptions)
582{
584 ExceptionThrower key1 = 1;
585 key1.throw_during_copy = true;
586 ExceptionThrower value1;
587 EXPECT_ANY_THROW({ map.add_new(key1, value1); });
588 EXPECT_EQ(map.size(), 0);
589 ExceptionThrower key2 = 2;
590 ExceptionThrower value2;
591 value2.throw_during_copy = true;
592 EXPECT_ANY_THROW({ map.add_new(key2, value2); });
593}
594
595TEST(map, ReserveExceptions)
596{
598 map.add(3, 3);
599 map.add(5, 5);
600 map.add(2, 2);
601 map.lookup(2).throw_during_move = true;
602 EXPECT_ANY_THROW({ map.reserve(100); });
603 map.add(1, 1);
604 map.add(5, 5);
605}
606
607TEST(map, PopExceptions)
608{
610 map.add(3, 3);
611 map.lookup(3).throw_during_move = true;
612 EXPECT_ANY_THROW({ map.pop(3); }); /* NOLINT: bugprone-throw-keyword-missing */
613 EXPECT_EQ(map.size(), 1);
614 map.add(1, 1);
615 EXPECT_EQ(map.size(), 2);
616}
617
618TEST(map, AddOrModifyExceptions)
619{
621 auto create_fn = [](ExceptionThrower * /*v*/) { throw std::runtime_error(""); };
622 auto modify_fn = [](ExceptionThrower * /*v*/) {};
623 EXPECT_ANY_THROW({ map.add_or_modify(3, create_fn, modify_fn); });
624}
625
626namespace {
627enum class TestEnum {
628 A = 0,
629 B = 1,
630 C = 2,
631 D = 1,
632};
633}
634
635TEST(map, EnumKey)
636{
638 map.add(TestEnum::A, 4);
639 map.add(TestEnum::B, 6);
640 EXPECT_EQ(map.lookup(TestEnum::A), 4);
641 EXPECT_EQ(map.lookup(TestEnum::B), 6);
642 EXPECT_EQ(map.lookup(TestEnum::D), 6);
643 EXPECT_FALSE(map.contains(TestEnum::C));
644 map.lookup(TestEnum::D) = 10;
645 EXPECT_EQ(map.lookup(TestEnum::B), 10);
646}
647
648TEST(map, GenericAlgorithms)
649{
650 Map<int, int> map;
651 map.add(5, 2);
652 map.add(1, 4);
653 map.add(2, 2);
654 map.add(7, 1);
655 map.add(8, 6);
656 EXPECT_TRUE(std::any_of(map.keys().begin(), map.keys().end(), [](int v) { return v == 1; }));
657 EXPECT_TRUE(std::any_of(map.values().begin(), map.values().end(), [](int v) { return v == 1; }));
658 EXPECT_TRUE(std::any_of(
659 map.items().begin(), map.items().end(), [](auto item) { return item.value == 1; }));
660 EXPECT_EQ(std::count(map.values().begin(), map.values().end(), 2), 2);
661 EXPECT_EQ(std::count(map.values().begin(), map.values().end(), 4), 1);
662 EXPECT_EQ(std::count(map.keys().begin(), map.keys().end(), 7), 1);
663}
664
665TEST(map, AddAsVariadic)
666{
668 map.add_as(3, "hello", 2);
669 map.add_as(2, "test", 1);
670 EXPECT_EQ(map.lookup(3), "he");
671 EXPECT_EQ(map.lookup(2), "t");
672}
673
674TEST(map, RemoveDuringIteration)
675{
676 Map<int, int> map;
677 map.add(2, 1);
678 map.add(5, 2);
679 map.add(1, 2);
680 map.add(6, 0);
681 map.add(3, 3);
682
683 EXPECT_EQ(map.size(), 5);
684
686 Iter begin = map.items().begin();
687 Iter end = map.items().end();
688 for (Iter iter = begin; iter != end; ++iter) {
689 MutableMapItem<int, int> item = *iter;
690 if (item.value == 2) {
691 map.remove(iter);
692 }
693 }
694
695 EXPECT_EQ(map.size(), 3);
696 EXPECT_EQ(map.lookup(2), 1);
697 EXPECT_EQ(map.lookup(6), 0);
698 EXPECT_EQ(map.lookup(3), 3);
699}
700
701TEST(map, RemoveIf)
702{
704 for (const int64_t i : IndexRange(100)) {
705 map.add(i * i, i);
706 }
707 const int64_t removed = map.remove_if([](auto item) { return item.key > 100; });
708 EXPECT_EQ(map.size() + removed, 100);
709 for (const int64_t i : IndexRange(100)) {
710 if (i <= 10) {
711 EXPECT_EQ(map.lookup(i * i), i);
712 }
713 else {
714 EXPECT_FALSE(map.contains(i * i));
715 }
716 }
717}
718
719TEST(map, LookupKey)
720{
722 map.add("a", 0);
723 map.add("b", 1);
724 map.add("c", 2);
725 EXPECT_EQ(map.lookup_key("a"), "a");
726 EXPECT_EQ(map.lookup_key_as("c"), "c");
727 EXPECT_EQ(map.lookup_key_ptr_as("d"), nullptr);
728 EXPECT_EQ(map.lookup_key_ptr_as("b")->size(), 1);
729 EXPECT_EQ(map.lookup_key_ptr("a"), map.lookup_key_ptr_as("a"));
730}
731
732TEST(map, VectorKey)
733{
734 Map<Vector<int>, int> map;
735 map.add({1, 2, 3}, 100);
736 map.add({3, 2, 1}, 200);
737
738 EXPECT_EQ(map.size(), 2);
739 EXPECT_EQ(map.lookup({1, 2, 3}), 100);
740 EXPECT_EQ(map.lookup({3, 2, 1}), 200);
741 EXPECT_FALSE(map.contains({1, 2}));
742
743 std::array<int, 3> array = {1, 2, 3};
744 EXPECT_EQ(map.lookup_as(array), 100);
745
746 map.remove_as(Vector<int>({1, 2, 3}).as_mutable_span());
747 EXPECT_EQ(map.size(), 1);
748}
749
750TEST(map, Equality)
751{
754
755 EXPECT_EQ(a, b);
756 a.add(3, 4);
757 EXPECT_NE(a, b);
758 b.add(3, 4);
759 EXPECT_EQ(a, b);
760
761 a.add(4, 10);
762 b.add(4, 11);
763 EXPECT_NE(a, b);
764}
765
766TEST(map, AddCbMove)
767{
769 std::string value = "a";
770 bool value_checked = false;
771 map.lookup_or_add_cb(std::move(value), [&]() {
772 EXPECT_EQ(value, "a");
773 value_checked = true;
774 return 10;
775 });
776 EXPECT_TRUE(value_checked);
777 EXPECT_EQ(value, "");
778}
779
783#if 0
784template<typename MapT>
785BLI_NOINLINE void benchmark_random_ints(StringRef name, int amount, int factor)
786{
787 RNG *rng = BLI_rng_new(0);
788 Vector<int> values;
789 for (int i = 0; i < amount; i++) {
790 values.append(BLI_rng_get_int(rng) * factor);
791 }
792 BLI_rng_free(rng);
793
794 MapT map;
795 {
796 SCOPED_TIMER(name + " Add");
797 for (int value : values) {
798 map.add(value, value);
799 }
800 }
801 int count = 0;
802 {
803 SCOPED_TIMER(name + " Contains");
804 for (int value : values) {
805 count += map.contains(value);
806 }
807 }
808 {
809 SCOPED_TIMER(name + " Remove");
810 for (int value : values) {
811 count += map.remove(value);
812 }
813 }
814
815 /* Print the value for simple error checking and to avoid some compiler optimizations. */
816 std::cout << "Count: " << count << "\n";
817}
818
823template<typename Key, typename Value> class StdUnorderedMapWrapper {
824 private:
825 using MapType = std::unordered_map<Key, Value, blender::DefaultHash<Key>>;
826 MapType map_;
827
828 public:
829 int64_t size() const
830 {
831 return int64_t(map_.size());
832 }
833
834 bool is_empty() const
835 {
836 return map_.empty();
837 }
838
839 void reserve(int64_t n)
840 {
841 map_.reserve(n);
842 }
843
844 template<typename ForwardKey, typename... ForwardValue>
845 void add_new(ForwardKey &&key, ForwardValue &&...value)
846 {
847 map_.insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)});
848 }
849
850 template<typename ForwardKey, typename... ForwardValue>
851 bool add(ForwardKey &&key, ForwardValue &&...value)
852 {
853 return map_
854 .insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)})
855 .second;
856 }
857
858 bool contains(const Key &key) const
859 {
860 return map_.find(key) != map_.end();
861 }
862
863 bool remove(const Key &key)
864 {
865 return bool(map_.erase(key));
866 }
867
868 Value &lookup(const Key &key)
869 {
870 return map_.find(key)->second;
871 }
872
873 const Value &lookup(const Key &key) const
874 {
875 return map_.find(key)->second;
876 }
877
878 void clear()
879 {
880 map_.clear();
881 }
882
883 void print_stats(StringRef /*name*/ = "") const {}
884};
885
886TEST(map, Benchmark)
887{
888 for (int i = 0; i < 3; i++) {
889 benchmark_random_ints<blender::Map<int, int>>("blender::Map ", 1000000, 1);
890 benchmark_random_ints<blender::StdUnorderedMapWrapper<int, int>>(
891 "std::unordered_map", 1000000, 1);
892 }
893 std::cout << "\n";
894 for (int i = 0; i < 3; i++) {
895 uint32_t factor = (3 << 10);
896 benchmark_random_ints<blender::Map<int, int>>("blender::Map ", 1000000, factor);
897 benchmark_random_ints<blender::StdUnorderedMapWrapper<int, int>>(
898 "std::unordered_map", 1000000, factor);
899 }
900}
901
953
954#endif /* Benchmark */
955
956} // namespace blender::tests
#define D
#define BLI_NOINLINE
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
Random number functions.
void int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:73
struct RNG * BLI_rng_new(unsigned int seed)
Definition rand.cc:39
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:53
#define SCOPED_TIMER(name)
Definition BLI_timeit.hh:70
struct Key Key
#define C
Definition RandGen.cpp:29
iter begin(iter)
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define A
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SubIterator begin() const
Definition BLI_map.hh:768
SubIterator end() const
Definition BLI_map.hh:778
void clear()
Definition BLI_map.hh:1038
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
Value pop(const Key &key)
Definition BLI_map.hh:402
std::optional< Value > lookup_try(const Key &key) const
Definition BLI_map.hh:531
std::optional< Value > pop_try(const Key &key)
Definition BLI_map.hh:419
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:639
const Key & lookup_key_as(const ForwardKey &key) const
Definition BLI_map.hh:660
bool remove_as(const ForwardKey &key)
Definition BLI_map.hh:372
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:325
ValueIterator values() const &
Definition BLI_map.hh:884
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
const Key * lookup_key_ptr_as(const ForwardKey &key) const
Definition BLI_map.hh:674
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:620
void foreach_item(const FuncT &func) const
Definition BLI_map.hh:687
const Key & lookup_key(const Key &key) const
Definition BLI_map.hh:656
bool add_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:312
const Key * lookup_key_ptr(const Key &key) const
Definition BLI_map.hh:670
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
const Value & lookup_as(const ForwardKey &key) const
Definition BLI_map.hh:553
bool remove(const Key &key)
Definition BLI_map.hh:368
int64_t size() const
Definition BLI_map.hh:976
KeyIterator keys() const &
Definition BLI_map.hh:875
bool is_empty() const
Definition BLI_map.hh:986
void reserve(int64_t n)
Definition BLI_map.hh:1028
bool contains(const Key &key) const
Definition BLI_map.hh:353
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:481
int64_t remove_if(Predicate &&predicate)
Definition BLI_map.hh:948
Value pop_default(const Key &key, const Value &default_value)
Definition BLI_map.hh:439
ItemIterator items() const &
Definition BLI_map.hh:902
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:588
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
int64_t size() const
bool contains(const T &value) const
void append(const T &value)
int64_t first_index_of(const T &value) const
MutableSpan< T > as_mutable_span()
blender::Vector< blender::nodes::ItemDeclarationPtr >::const_iterator ItemIterator
int count
#define B
static void clear(Message &msg)
Definition msgfmt.cc:213
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
bool contains(const VArray< bool > &varray, const IndexMask &indices_to_check, bool value)
bool remove(void *owner, const StringRef name)
GAttributeReader lookup(const void *owner, const StringRef name)
static float return_42()
TEST(blf_load, load)
Definition BLF_tests.cc:34
static PyObject * create_func(PyObject *, PyObject *args)
Definition python.cpp:157
const char * name
Definition rand.cc:33
i
Definition text_draw.cc:230