1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_containers/intrusive_map.h"
16
17 #include "pw_compilation_testing/negative_compilation.h"
18 #include "pw_containers/intrusive_multimap.h"
19 #include "pw_span/span.h"
20 #include "pw_unit_test/framework.h"
21
22 namespace {
23
24 // Base pair.
25 class BaseItem {
26 public:
BaseItem(const char * name)27 explicit BaseItem(const char* name) : name_(name) {}
28
name() const29 constexpr const char* name() const { return name_; }
set_name(const char * name)30 void set_name(const char* name) { name_ = name; }
31
32 private:
33 const char* name_;
34 };
35
36 // A basic pair that can be used in a map.
37 class TestPair : public ::pw::IntrusiveMap<size_t, TestPair>::Pair,
38 public BaseItem {
39 private:
40 using Pair = ::pw::IntrusiveMap<size_t, TestPair>::Pair;
41
42 public:
TestPair(size_t key,const char * name)43 TestPair(size_t key, const char* name) : Pair(key), BaseItem(name) {}
44 };
45
46 // Test fixture.
47 class IntrusiveMapTest : public ::testing::Test {
48 protected:
49 using IntrusiveMap = ::pw::IntrusiveMap<size_t, TestPair>;
50 static constexpr size_t kNumPairs = 10;
51
SetUp()52 void SetUp() override { map_.insert(pairs_.begin(), pairs_.end()); }
53
TearDown()54 void TearDown() override { map_.clear(); }
55
56 std::array<TestPair, kNumPairs> pairs_ = {{
57 {30, "a"},
58 {50, "b"},
59 {20, "c"},
60 {40, "d"},
61 {10, "e"},
62 {35, "A"},
63 {55, "B"},
64 {25, "C"},
65 {45, "D"},
66 {15, "E"},
67 }};
68
69 IntrusiveMap map_;
70 };
71
72 // Unit tests.
73
TEST_F(IntrusiveMapTest,Construct_Default)74 TEST_F(IntrusiveMapTest, Construct_Default) {
75 IntrusiveMap map;
76 EXPECT_TRUE(map.empty());
77 EXPECT_EQ(map.begin(), map.end());
78 EXPECT_EQ(map.rbegin(), map.rend());
79 EXPECT_EQ(map.size(), 0U);
80 EXPECT_EQ(map.lower_bound(0), map.end());
81 EXPECT_EQ(map.upper_bound(0), map.end());
82 }
83
TEST_F(IntrusiveMapTest,Construct_ObjectIterators)84 TEST_F(IntrusiveMapTest, Construct_ObjectIterators) {
85 map_.clear();
86 IntrusiveMap map(pairs_.begin(), pairs_.end());
87 EXPECT_FALSE(map.empty());
88 EXPECT_EQ(map.size(), pairs_.size());
89 map.clear();
90 }
91
TEST_F(IntrusiveMapTest,Construct_ObjectIterators_Empty)92 TEST_F(IntrusiveMapTest, Construct_ObjectIterators_Empty) {
93 IntrusiveMap map(pairs_.end(), pairs_.end());
94 EXPECT_TRUE(map.empty());
95 EXPECT_EQ(map.size(), 0U);
96 }
97
TEST_F(IntrusiveMapTest,Construct_PointerIterators)98 TEST_F(IntrusiveMapTest, Construct_PointerIterators) {
99 std::array<TestPair*, 3> ptrs = {&pairs_[0], &pairs_[1], &pairs_[2]};
100 map_.clear();
101 IntrusiveMap map(ptrs.begin(), ptrs.end());
102 EXPECT_FALSE(map.empty());
103 EXPECT_EQ(map.size(), 3U);
104 map.clear();
105 }
106
TEST_F(IntrusiveMapTest,Construct_PointerIterators_Empty)107 TEST_F(IntrusiveMapTest, Construct_PointerIterators_Empty) {
108 std::array<TestPair*, 0> ptrs;
109 IntrusiveMap map(ptrs.begin(), ptrs.end());
110 EXPECT_TRUE(map.empty());
111 EXPECT_EQ(map.size(), 0U);
112 map.clear();
113 }
114
TEST_F(IntrusiveMapTest,Construct_InitializerList)115 TEST_F(IntrusiveMapTest, Construct_InitializerList) {
116 map_.clear();
117 IntrusiveMap map({&pairs_[0], &pairs_[2], &pairs_[4]});
118 auto iter = map.begin();
119 EXPECT_EQ((iter++)->key(), 10U);
120 EXPECT_EQ((iter++)->key(), 20U);
121 EXPECT_EQ((iter++)->key(), 30U);
122 map.clear();
123 }
124
TEST_F(IntrusiveMapTest,Construct_InitializerList_Empty)125 TEST_F(IntrusiveMapTest, Construct_InitializerList_Empty) {
126 IntrusiveMap map({});
127 EXPECT_TRUE(map.empty());
128 EXPECT_EQ(map.size(), 0U);
129 }
130
TEST_F(IntrusiveMapTest,Construct_CustomCompare)131 TEST_F(IntrusiveMapTest, Construct_CustomCompare) {
132 auto greater_than = [](const size_t& lhs, const size_t& rhs) {
133 return lhs > rhs;
134 };
135 map_.clear();
136 IntrusiveMap map({&pairs_[0], &pairs_[2], &pairs_[4]},
137 std::move(greater_than));
138 auto iter = map.begin();
139 EXPECT_EQ((iter++)->key(), 30U);
140 EXPECT_EQ((iter++)->key(), 20U);
141 EXPECT_EQ((iter++)->key(), 10U);
142 map.clear();
143 }
144
145 // A map pair that includes a key accessor method.
146 struct HalvedKey : public ::pw::IntrusiveMap<size_t, HalvedKey>::Item,
147 public BaseItem {
148 public:
HalvedKey__anonb120837f0111::HalvedKey149 HalvedKey(size_t half_key, const char* name)
150 : BaseItem(name), half_key_(half_key) {}
key__anonb120837f0111::HalvedKey151 size_t key() const { return half_key_ * 2; }
152
153 private:
154 const size_t half_key_;
155 };
156
TEST_F(IntrusiveMapTest,Construct_CustomItem)157 TEST_F(IntrusiveMapTest, Construct_CustomItem) {
158 std::array<HalvedKey, 3> items = {{
159 {50, "B"},
160 {40, "D"},
161 {60, "F"},
162 }};
163 pw::IntrusiveMap<size_t, HalvedKey> map(items.begin(), items.end());
164
165 auto iter = map.find(80);
166 ASSERT_NE(iter, map.end());
167 EXPECT_STREQ(iter->name(), "D");
168
169 iter = map.find(100);
170 ASSERT_NE(iter, map.end());
171 EXPECT_STREQ(iter->name(), "B");
172
173 iter = map.find(120);
174 ASSERT_NE(iter, map.end());
175 EXPECT_STREQ(iter->name(), "F");
176
177 map.clear();
178 }
179
180 // A map item that has no explicit key.
181 struct NoKey : public ::pw::IntrusiveMap<size_t, NoKey>::Item, public BaseItem {
182 public:
NoKey__anonb120837f0111::NoKey183 explicit NoKey(const char* name) : BaseItem(name) {}
184 };
185
186 // A functor to get an implied key from a `NoKey` item.
187 struct GetImpliedKey {
operator ()__anonb120837f0111::GetImpliedKey188 size_t operator()(const NoKey& item) const {
189 return std::strlen(item.name());
190 }
191 };
192
TEST_F(IntrusiveMapTest,Construct_CustomGetKey)193 TEST_F(IntrusiveMapTest, Construct_CustomGetKey) {
194 std::array<NoKey, 4> items = {
195 NoKey("CC"),
196 NoKey("AAA"),
197 NoKey("B"),
198 NoKey("DDDD"),
199 };
200 pw::IntrusiveMap<size_t, NoKey> map((std::less<>()), GetImpliedKey());
201 map.insert(items.begin(), items.end());
202
203 auto iter = map.begin();
204 EXPECT_STREQ((iter++)->name(), "B");
205 EXPECT_STREQ((iter++)->name(), "CC");
206 EXPECT_STREQ((iter++)->name(), "AAA");
207 EXPECT_STREQ((iter++)->name(), "DDDD");
208 map.clear();
209 }
210
211 // A struct that is not a map pair.
212 class NotAnItem : public BaseItem {
213 public:
NotAnItem(const char * name,size_t key)214 NotAnItem(const char* name, size_t key) : BaseItem(name), key_(key) {}
key() const215 size_t key() const { return key_; }
216
217 private:
218 const size_t key_;
219 };
220
221 #if PW_NC_TEST(IncompatibleItem)
222 PW_NC_EXPECT(
223 "IntrusiveMap items must be derived from IntrusiveMap<Key, T>::Item");
224
225 class BadItem : public ::pw::IntrusiveMap<size_t, NotAnItem>::Item {
226 public:
BadItem(size_t key)227 constexpr explicit BadItem(size_t key) : key_(key) {}
key() const228 constexpr size_t key() const { return key_; }
operator <(const Pair & rhs)229 constexpr bool operator<(const Pair& rhs) { return key_ < rhs.key(); }
230
231 private:
232 const size_t key_;
233 };
234
235 using Compare = Function<bool(Key, Key)>;
236 using GetKey = Function<Key(const V&)>;
237
238 [[maybe_unused]] ::pw::IntrusiveMap<size_t, BadItem> bad_map1;
239
240 #elif PW_NC_TEST(DoesNotInheritFromItem)
241 PW_NC_EXPECT(
242 "IntrusiveMap items must be derived from IntrusiveMap<Key, T>::Item");
243
244 [[maybe_unused]] ::pw::IntrusiveMap<size_t, NotAnItem> bad_map2;
245
246 #endif // PW_NC_TEST
247
248 // Element access
249
TEST_F(IntrusiveMapTest,At)250 TEST_F(IntrusiveMapTest, At) {
251 const IntrusiveMap& map = map_;
252 for (const auto& pair : pairs_) {
253 EXPECT_EQ(&(map.at(pair.key())), &pair);
254 }
255 }
256
257 // Iterators
258
TEST_F(IntrusiveMapTest,Iterator)259 TEST_F(IntrusiveMapTest, Iterator) {
260 const IntrusiveMap& map = map_;
261 auto iter = map.begin();
262 size_t key = 10;
263 for (size_t i = 0; i < kNumPairs; ++i) {
264 auto& pair = *iter++;
265 EXPECT_EQ(pair.key(), key);
266 key += 5;
267 }
268 EXPECT_EQ(key, 60U);
269 EXPECT_EQ(iter, map.end());
270 EXPECT_EQ(iter, map.cend());
271 for (size_t i = 0; i < kNumPairs; ++i) {
272 key -= 5;
273 EXPECT_EQ((--iter)->key(), key);
274 }
275 EXPECT_EQ(key, 10U);
276 EXPECT_EQ(iter, map.begin());
277 EXPECT_EQ(iter, map.cbegin());
278 }
279
TEST_F(IntrusiveMapTest,ReverseIterator)280 TEST_F(IntrusiveMapTest, ReverseIterator) {
281 const IntrusiveMap& map = map_;
282 auto iter = map.rbegin();
283 size_t key = 55;
284 for (size_t i = 0; i < kNumPairs; ++i) {
285 auto& pair = *iter++;
286 EXPECT_EQ(pair.key(), key);
287 key -= 5;
288 }
289 EXPECT_EQ(key, 5U);
290 EXPECT_EQ(iter, map.rend());
291 EXPECT_EQ(iter, map.crend());
292 for (size_t i = 0; i < kNumPairs; ++i) {
293 key += 5;
294 EXPECT_EQ((--iter)->key(), key);
295 }
296 EXPECT_EQ(key, 55U);
297 EXPECT_EQ(iter, map.rbegin());
298 EXPECT_EQ(iter, map.crbegin());
299 }
300
TEST_F(IntrusiveMapTest,ConstIterator_CompareNonConst)301 TEST_F(IntrusiveMapTest, ConstIterator_CompareNonConst) {
302 EXPECT_EQ(map_.end(), map_.cend());
303 }
304
305 // A map pair that is distinct from TestPair
306 struct OtherPair : public ::pw::IntrusiveMap<size_t, OtherPair>::Pair,
307 public BaseItem {
308 private:
309 using Pair = ::pw::IntrusiveMap<size_t, OtherPair>::Pair;
310
311 public:
OtherPair__anonb120837f0111::OtherPair312 OtherPair(size_t key, const char* name) : Pair(key), BaseItem(name) {}
313 };
314
TEST_F(IntrusiveMapTest,ConstIterator_CompareNonConst_CompilationFails)315 TEST_F(IntrusiveMapTest, ConstIterator_CompareNonConst_CompilationFails) {
316 ::pw::IntrusiveMap<size_t, OtherPair> map;
317 #if PW_NC_TEST(CannotCompareIncompatibleIteratorsEqual)
318 PW_NC_EXPECT("map_\.end\(\) == map\.end\(\)");
319 static_cast<void>(map_.end() == map.end());
320 #elif PW_NC_TEST(CannotCompareIncompatibleIteratorsInequal)
321 PW_NC_EXPECT("map_\.end\(\) != map\.end\(\)");
322 static_cast<void>(map_.end() != map.end());
323 #endif // PW_NC_TEST
324 }
325
326 #if PW_NC_TEST(CannotModifyThroughConstIterator)
327 PW_NC_EXPECT("function is not marked const|discards qualifiers");
328
TEST_F(IntrusiveMapTest,ConstIterator_Modify)329 TEST_F(IntrusiveMapTest, ConstIterator_Modify) {
330 const IntrusiveMap& map = map_;
331 auto iter = map.begin();
332 iter->set_name("nope");
333 }
334
335 #endif // PW_NC_TEST
336
337 // Capacity
338
TEST_F(IntrusiveMapTest,IsEmpty)339 TEST_F(IntrusiveMapTest, IsEmpty) {
340 const IntrusiveMap& map = map_;
341 EXPECT_FALSE(map.empty());
342 map_.clear();
343 EXPECT_TRUE(map.empty());
344 }
345
TEST_F(IntrusiveMapTest,GetSize)346 TEST_F(IntrusiveMapTest, GetSize) {
347 const IntrusiveMap& map = map_;
348 EXPECT_EQ(map.size(), kNumPairs);
349 map_.clear();
350 EXPECT_EQ(map.size(), 0U);
351 }
352
TEST_F(IntrusiveMapTest,GetMaxSize)353 TEST_F(IntrusiveMapTest, GetMaxSize) {
354 const IntrusiveMap& map = map_;
355 EXPECT_EQ(map.max_size(), size_t(std::numeric_limits<ptrdiff_t>::max()));
356 }
357
358 // Modifiers
359
360 // This functions allows tests to use `std::is_sorted` without specializing
361 // `std::less<TestPair>`. Since `std::less` is the default value for the
362 // `Compare` template parameter, leaving it untouched avoids accidentally
363 // masking type-handling errors.
LessThan(const TestPair & lhs,const TestPair & rhs)364 constexpr bool LessThan(const TestPair& lhs, const TestPair& rhs) {
365 return lhs.key() < rhs.key();
366 }
367
TEST_F(IntrusiveMapTest,Insert)368 TEST_F(IntrusiveMapTest, Insert) {
369 map_.clear();
370 bool sorted = true;
371 size_t prev_key = 0;
372 for (auto& pair : pairs_) {
373 sorted &= prev_key < pair.key();
374
375 // Use the "hinted" version of insert.
376 map_.insert(map_.end(), pair);
377 prev_key = pair.key();
378 }
379 EXPECT_FALSE(sorted);
380
381 EXPECT_EQ(map_.size(), kNumPairs);
382 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
383 }
384
TEST_F(IntrusiveMapTest,Insert_Duplicate)385 TEST_F(IntrusiveMapTest, Insert_Duplicate) {
386 TestPair pair1(60, "1");
387 TestPair pair2(60, "2");
388
389 auto result = map_.insert(pair1);
390 EXPECT_STREQ(result.first->name(), "1");
391 EXPECT_TRUE(result.second);
392
393 result = map_.insert(pair2);
394 EXPECT_STREQ(result.first->name(), "1");
395 EXPECT_FALSE(result.second);
396
397 EXPECT_EQ(map_.size(), kNumPairs + 1);
398 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
399
400 // Explicitly clear the map before pair 1 goes out of scope.
401 map_.clear();
402 }
403
TEST_F(IntrusiveMapTest,Insert_ObjectIterators)404 TEST_F(IntrusiveMapTest, Insert_ObjectIterators) {
405 map_.clear();
406 map_.insert(pairs_.begin(), pairs_.end());
407 EXPECT_EQ(map_.size(), kNumPairs);
408 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
409 }
410
TEST_F(IntrusiveMapTest,Insert_ObjectIterators_Empty)411 TEST_F(IntrusiveMapTest, Insert_ObjectIterators_Empty) {
412 map_.insert(pairs_.end(), pairs_.end());
413 EXPECT_EQ(map_.size(), kNumPairs);
414 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
415 }
416
TEST_F(IntrusiveMapTest,Insert_ObjectIterators_WithDuplicates)417 TEST_F(IntrusiveMapTest, Insert_ObjectIterators_WithDuplicates) {
418 std::array<TestPair, 3> pairs = {{
419 {50, "B"},
420 {40, "D"},
421 {60, "F"},
422 }};
423
424 map_.insert(pairs.begin(), pairs.end());
425 EXPECT_EQ(map_.size(), kNumPairs + 1);
426 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
427 EXPECT_STREQ(map_.at(40).name(), "d");
428 EXPECT_STREQ(map_.at(50).name(), "b");
429 EXPECT_STREQ(map_.at(60).name(), "F");
430
431 // Explicitly clear the map before pairs goes out of scope.
432 map_.clear();
433 }
434
TEST_F(IntrusiveMapTest,Insert_PointerIterators)435 TEST_F(IntrusiveMapTest, Insert_PointerIterators) {
436 map_.clear();
437 std::array<TestPair*, 3> ptrs = {&pairs_[0], &pairs_[1], &pairs_[2]};
438
439 map_.insert(ptrs.begin(), ptrs.end());
440 EXPECT_EQ(map_.size(), 3U);
441 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
442 }
443
TEST_F(IntrusiveMapTest,Insert_PointerIterators_Empty)444 TEST_F(IntrusiveMapTest, Insert_PointerIterators_Empty) {
445 std::array<TestPair*, 0> ptrs;
446
447 map_.insert(ptrs.begin(), ptrs.end());
448 EXPECT_EQ(map_.size(), kNumPairs);
449 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
450 }
451
TEST_F(IntrusiveMapTest,Insert_PointerIterators_WithDuplicates)452 TEST_F(IntrusiveMapTest, Insert_PointerIterators_WithDuplicates) {
453 TestPair pair1(50, "B");
454 TestPair pair2(40, "D");
455 TestPair pair3(60, "F");
456 std::array<TestPair*, 3> ptrs = {&pair1, &pair2, &pair3};
457
458 map_.insert(ptrs.begin(), ptrs.end());
459 EXPECT_EQ(map_.size(), kNumPairs + 1);
460 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
461 EXPECT_STREQ(map_.at(40).name(), "d");
462 EXPECT_STREQ(map_.at(50).name(), "b");
463 EXPECT_STREQ(map_.at(60).name(), "F");
464
465 // Explicitly clear the map before pairs goes out of scope.
466 map_.clear();
467 }
468
TEST_F(IntrusiveMapTest,Insert_InitializerList)469 TEST_F(IntrusiveMapTest, Insert_InitializerList) {
470 map_.clear();
471 map_.insert({&pairs_[0], &pairs_[2], &pairs_[4]});
472 EXPECT_EQ(map_.size(), 3U);
473 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
474 }
475
TEST_F(IntrusiveMapTest,Insert_InitializerList_Empty)476 TEST_F(IntrusiveMapTest, Insert_InitializerList_Empty) {
477 map_.insert({});
478 EXPECT_EQ(map_.size(), kNumPairs);
479 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
480 }
481
TEST_F(IntrusiveMapTest,Insert_InitializerList_WithDuplicates)482 TEST_F(IntrusiveMapTest, Insert_InitializerList_WithDuplicates) {
483 TestPair pair1(50, "B");
484 TestPair pair2(40, "D");
485 TestPair pair3(60, "F");
486
487 map_.insert({&pair1, &pair2, &pair3});
488 EXPECT_EQ(map_.size(), kNumPairs + 1);
489 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
490 EXPECT_STREQ(map_.at(40).name(), "d");
491 EXPECT_STREQ(map_.at(50).name(), "b");
492 EXPECT_STREQ(map_.at(60).name(), "F");
493
494 // Explicitly clear the map before pairs goes out of scope.
495 map_.clear();
496 }
497
498 // A pair derived from TestPair.
499 struct DerivedPair : public TestPair {
DerivedPair__anonb120837f0111::DerivedPair500 DerivedPair(size_t n, const char* name) : TestPair(n * 10, name) {}
501 };
502
TEST_F(IntrusiveMapTest,Insert_DerivedPairs)503 TEST_F(IntrusiveMapTest, Insert_DerivedPairs) {
504 DerivedPair pair1(6, "f");
505 map_.insert(pair1);
506
507 DerivedPair pair2(7, "g");
508 map_.insert(pair2);
509
510 EXPECT_EQ(map_.size(), kNumPairs + 2);
511 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
512
513 // Explicitly clear the map before pairs goes out of scope.
514 map_.clear();
515 }
516
TEST_F(IntrusiveMapTest,Insert_DerivedPairs_CompilationFails)517 TEST_F(IntrusiveMapTest, Insert_DerivedPairs_CompilationFails) {
518 ::pw::IntrusiveMap<size_t, DerivedPair> derived_from_compatible_pair_type;
519
520 DerivedPair pair1(6, "f");
521 derived_from_compatible_pair_type.insert(pair1);
522
523 EXPECT_EQ(derived_from_compatible_pair_type.size(), 1U);
524
525 #if PW_NC_TEST(CannotAddBaseClassToDerivedClassMap)
526 PW_NC_EXPECT("derived_from_compatible_pair_type\.insert\(pair2\)");
527
528 TestPair pair2(70, "g");
529 derived_from_compatible_pair_type.insert(pair2);
530 #endif
531 derived_from_compatible_pair_type.clear();
532 }
533
TEST_F(IntrusiveMapTest,Erase_One_ByItem)534 TEST_F(IntrusiveMapTest, Erase_One_ByItem) {
535 for (size_t i = 0; i < kNumPairs; ++i) {
536 EXPECT_EQ(map_.size(), kNumPairs);
537 auto iter = map_.erase(pairs_[i]);
538 if (iter != map_.end()) {
539 EXPECT_GT(iter->key(), pairs_[i].key());
540 }
541 EXPECT_EQ(map_.size(), kNumPairs - 1);
542 EXPECT_EQ(map_.find(pairs_[i].key()), map_.end());
543 map_.insert(pairs_[i]);
544 }
545 }
546
TEST_F(IntrusiveMapTest,Erase_One_ByKey)547 TEST_F(IntrusiveMapTest, Erase_One_ByKey) {
548 for (size_t i = 0; i < kNumPairs; ++i) {
549 EXPECT_EQ(map_.size(), kNumPairs);
550 EXPECT_EQ(map_.erase(pairs_[i].key()), 1U);
551 EXPECT_EQ(map_.size(), kNumPairs - 1);
552 auto iter = map_.find(pairs_[i].key());
553 EXPECT_EQ(iter, map_.end());
554 map_.insert(pairs_[i]);
555 }
556 }
557
TEST_F(IntrusiveMapTest,Erase_OnlyItem)558 TEST_F(IntrusiveMapTest, Erase_OnlyItem) {
559 map_.clear();
560 map_.insert(pairs_[0]);
561 EXPECT_EQ(map_.size(), 1U);
562
563 EXPECT_EQ(map_.erase(pairs_[0].key()), 1U);
564 EXPECT_EQ(map_.size(), 0U);
565 }
566
TEST_F(IntrusiveMapTest,Erase_AllOnebyOne)567 TEST_F(IntrusiveMapTest, Erase_AllOnebyOne) {
568 auto iter = map_.begin();
569 for (size_t n = kNumPairs; n != 0; --n) {
570 ASSERT_NE(iter, map_.end());
571 iter = map_.erase(iter);
572 }
573 EXPECT_EQ(iter, map_.end());
574 EXPECT_EQ(map_.size(), 0U);
575 }
576
TEST_F(IntrusiveMapTest,Erase_Range)577 TEST_F(IntrusiveMapTest, Erase_Range) {
578 auto first = map_.begin();
579 auto last = map_.end();
580 ++first;
581 --last;
582 auto iter = map_.erase(first, last);
583 EXPECT_EQ(map_.size(), 2U);
584 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
585 EXPECT_EQ(iter->key(), 55U);
586 }
587
TEST_F(IntrusiveMapTest,Erase_MissingItem)588 TEST_F(IntrusiveMapTest, Erase_MissingItem) { EXPECT_EQ(map_.erase(100), 0U); }
589
TEST_F(IntrusiveMapTest,Erase_Reinsert)590 TEST_F(IntrusiveMapTest, Erase_Reinsert) {
591 EXPECT_EQ(map_.size(), pairs_.size());
592
593 EXPECT_EQ(map_.erase(pairs_[0].key()), 1U);
594 EXPECT_EQ(map_.find(pairs_[0].key()), map_.end());
595
596 EXPECT_EQ(map_.erase(pairs_[2].key()), 1U);
597 EXPECT_EQ(map_.find(pairs_[2].key()), map_.end());
598
599 EXPECT_EQ(map_.erase(pairs_[4].key()), 1U);
600 EXPECT_EQ(map_.find(pairs_[4].key()), map_.end());
601
602 EXPECT_EQ(map_.size(), pairs_.size() - 3);
603
604 map_.insert(pairs_[4]);
605 auto iter = map_.find(pairs_[4].key());
606 EXPECT_NE(iter, map_.end());
607
608 map_.insert(pairs_[0]);
609 iter = map_.find(pairs_[0].key());
610 EXPECT_NE(iter, map_.end());
611
612 map_.insert(pairs_[2]);
613 iter = map_.find(pairs_[2].key());
614 EXPECT_NE(iter, map_.end());
615
616 EXPECT_EQ(map_.size(), pairs_.size());
617 }
618
TEST_F(IntrusiveMapTest,Swap)619 TEST_F(IntrusiveMapTest, Swap) {
620 std::array<TestPair, 3> pairs = {{
621 {50, "B"},
622 {40, "D"},
623 {60, "F"},
624 }};
625 IntrusiveMap map(pairs.begin(), pairs.end());
626
627 map_.swap(map);
628 EXPECT_EQ(map.size(), kNumPairs);
629 EXPECT_TRUE(std::is_sorted(map.begin(), map.end(), LessThan));
630 EXPECT_EQ(map.at(30).name(), "a");
631 EXPECT_EQ(map.at(50).name(), "b");
632 EXPECT_EQ(map.at(20).name(), "c");
633 EXPECT_EQ(map.at(40).name(), "d");
634 EXPECT_EQ(map.at(10).name(), "e");
635 map.clear();
636
637 EXPECT_EQ(map_.size(), 3U);
638 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
639 EXPECT_STREQ(map_.at(50).name(), "B");
640 EXPECT_STREQ(map_.at(40).name(), "D");
641 EXPECT_STREQ(map_.at(60).name(), "F");
642
643 // Explicitly clear the map before pairs goes out of scope.
644 map_.clear();
645 }
646
TEST_F(IntrusiveMapTest,Swap_Empty)647 TEST_F(IntrusiveMapTest, Swap_Empty) {
648 IntrusiveMap map;
649
650 map_.swap(map);
651 EXPECT_EQ(map.size(), kNumPairs);
652 EXPECT_TRUE(std::is_sorted(map.begin(), map.end(), LessThan));
653 EXPECT_EQ(map.at(30).name(), "a");
654 EXPECT_EQ(map.at(50).name(), "b");
655 EXPECT_EQ(map.at(20).name(), "c");
656 EXPECT_EQ(map.at(40).name(), "d");
657 EXPECT_EQ(map.at(10).name(), "e");
658 map.clear();
659
660 EXPECT_EQ(map_.size(), 0U);
661 }
662
TEST_F(IntrusiveMapTest,Merge)663 TEST_F(IntrusiveMapTest, Merge) {
664 std::array<TestPair, 3> pairs = {{
665 {5, "f"},
666 {75, "g"},
667 {85, "h"},
668 }};
669 IntrusiveMap map(pairs.begin(), pairs.end());
670
671 map_.merge(map);
672 EXPECT_TRUE(map.empty());
673 EXPECT_EQ(map_.size(), kNumPairs + 3);
674 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
675 EXPECT_STREQ(map_.at(30).name(), "a");
676 EXPECT_STREQ(map_.at(35).name(), "A");
677 EXPECT_STREQ(map_.at(50).name(), "b");
678 EXPECT_STREQ(map_.at(55).name(), "B");
679 EXPECT_STREQ(map_.at(20).name(), "c");
680 EXPECT_STREQ(map_.at(25).name(), "C");
681 EXPECT_STREQ(map_.at(40).name(), "d");
682 EXPECT_STREQ(map_.at(45).name(), "D");
683 EXPECT_STREQ(map_.at(10).name(), "e");
684 EXPECT_STREQ(map_.at(15).name(), "E");
685 EXPECT_STREQ(map_.at(5).name(), "f");
686 EXPECT_STREQ(map_.at(75).name(), "g");
687 EXPECT_STREQ(map_.at(85).name(), "h");
688
689 // Explicitly clear the map before pairs goes out of scope.
690 map_.clear();
691 }
692
TEST_F(IntrusiveMapTest,Merge_Empty)693 TEST_F(IntrusiveMapTest, Merge_Empty) {
694 IntrusiveMap map;
695
696 map_.merge(map);
697 EXPECT_EQ(map_.size(), kNumPairs);
698 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
699
700 map.merge(map_);
701 EXPECT_TRUE(map_.empty());
702 EXPECT_EQ(map.size(), kNumPairs);
703 EXPECT_TRUE(std::is_sorted(map.begin(), map.end(), LessThan));
704
705 map.clear();
706 }
707
TEST_F(IntrusiveMapTest,Merge_WithDuplicates)708 TEST_F(IntrusiveMapTest, Merge_WithDuplicates) {
709 std::array<TestPair, 3> pairs = {{
710 {50, "B"},
711 {40, "D"},
712 {60, "F"},
713 }};
714 IntrusiveMap map(pairs.begin(), pairs.end());
715
716 map_.merge(map);
717 EXPECT_TRUE(map.empty());
718 EXPECT_EQ(map_.size(), kNumPairs + 1);
719 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
720 EXPECT_STREQ(map_.at(30).name(), "a");
721 EXPECT_STREQ(map_.at(50).name(), "b");
722 EXPECT_STREQ(map_.at(20).name(), "c");
723 EXPECT_STREQ(map_.at(40).name(), "d");
724 EXPECT_STREQ(map_.at(10).name(), "e");
725 EXPECT_STREQ(map_.at(60).name(), "F");
726
727 // Explicitly clear the map before pairs goes out of scope.
728 map_.clear();
729 }
730
TEST_F(IntrusiveMapTest,Merge_MultiMap)731 TEST_F(IntrusiveMapTest, Merge_MultiMap) {
732 std::array<TestPair, 3> pairs = {{
733 {50, "B"},
734 {40, "D"},
735 {60, "F"},
736 }};
737 ::pw::IntrusiveMultiMap<size_t, TestPair> multimap(pairs.begin(),
738 pairs.end());
739
740 map_.merge(multimap);
741 EXPECT_TRUE(multimap.empty());
742 EXPECT_EQ(map_.size(), kNumPairs + 1);
743 EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan));
744 EXPECT_STREQ(map_.at(30).name(), "a");
745 EXPECT_STREQ(map_.at(50).name(), "b");
746 EXPECT_STREQ(map_.at(20).name(), "c");
747 EXPECT_STREQ(map_.at(40).name(), "d");
748 EXPECT_STREQ(map_.at(10).name(), "e");
749 EXPECT_STREQ(map_.at(60).name(), "F");
750
751 // Explicitly clear the map before pairs goes out of scope.
752 map_.clear();
753 }
754
TEST_F(IntrusiveMapTest,Count)755 TEST_F(IntrusiveMapTest, Count) {
756 const IntrusiveMap& map = map_;
757 EXPECT_EQ(map.count(10), 1U);
758 EXPECT_EQ(map.count(20), 1U);
759 EXPECT_EQ(map.count(30), 1U);
760 EXPECT_EQ(map.count(40), 1U);
761 EXPECT_EQ(map.count(50), 1U);
762 }
763
TEST_F(IntrusiveMapTest,Count_NoSuchKey)764 TEST_F(IntrusiveMapTest, Count_NoSuchKey) {
765 const IntrusiveMap& map = map_;
766 EXPECT_EQ(map.count(60), 0U);
767 }
768
TEST_F(IntrusiveMapTest,Find)769 TEST_F(IntrusiveMapTest, Find) {
770 const IntrusiveMap& map = map_;
771 size_t key = 10;
772 for (size_t i = 0; i < kNumPairs; ++i) {
773 auto iter = map.find(key);
774 ASSERT_NE(iter, map.end());
775 EXPECT_EQ(iter->key(), key);
776 key += 5;
777 }
778 }
779
TEST_F(IntrusiveMapTest,Find_NoSuchKey)780 TEST_F(IntrusiveMapTest, Find_NoSuchKey) {
781 const IntrusiveMap& map = map_;
782 auto iter = map.find(60);
783 EXPECT_EQ(iter, map.end());
784 }
785
TEST_F(IntrusiveMapTest,LowerBound)786 TEST_F(IntrusiveMapTest, LowerBound) {
787 const IntrusiveMap& map = map_;
788 auto iter = map.lower_bound(10);
789 ASSERT_NE(iter, map.end());
790 EXPECT_STREQ(iter->name(), "e");
791
792 iter = map.lower_bound(20);
793 ASSERT_NE(iter, map.end());
794 EXPECT_STREQ(iter->name(), "c");
795
796 iter = map.lower_bound(30);
797 ASSERT_NE(iter, map.end());
798 EXPECT_STREQ(iter->name(), "a");
799
800 iter = map.lower_bound(40);
801 ASSERT_NE(iter, map.end());
802 EXPECT_STREQ(iter->name(), "d");
803
804 iter = map.lower_bound(50);
805 ASSERT_NE(iter, map.end());
806 EXPECT_STREQ(iter->name(), "b");
807 }
808
TEST_F(IntrusiveMapTest,LowerBound_NoExactKey)809 TEST_F(IntrusiveMapTest, LowerBound_NoExactKey) {
810 const IntrusiveMap& map = map_;
811 auto iter = map.lower_bound(6);
812 ASSERT_NE(iter, map.end());
813 EXPECT_STREQ(iter->name(), "e");
814
815 iter = map.lower_bound(16);
816 ASSERT_NE(iter, map.end());
817 EXPECT_STREQ(iter->name(), "c");
818
819 iter = map.lower_bound(26);
820 ASSERT_NE(iter, map.end());
821 EXPECT_STREQ(iter->name(), "a");
822
823 iter = map.lower_bound(36);
824 ASSERT_NE(iter, map.end());
825 EXPECT_STREQ(iter->name(), "d");
826
827 iter = map.lower_bound(46);
828 ASSERT_NE(iter, map.end());
829 EXPECT_STREQ(iter->name(), "b");
830 }
831
TEST_F(IntrusiveMapTest,LowerBound_OutOfRange)832 TEST_F(IntrusiveMapTest, LowerBound_OutOfRange) {
833 const IntrusiveMap& map = map_;
834 EXPECT_EQ(map.lower_bound(56), map.end());
835 }
836
TEST_F(IntrusiveMapTest,UpperBound)837 TEST_F(IntrusiveMapTest, UpperBound) {
838 const IntrusiveMap& map = map_;
839 auto iter = map.upper_bound(15);
840 ASSERT_NE(iter, map.end());
841 EXPECT_STREQ(iter->name(), "c");
842
843 iter = map.upper_bound(25);
844 ASSERT_NE(iter, map.end());
845 EXPECT_STREQ(iter->name(), "a");
846
847 iter = map.upper_bound(35);
848 ASSERT_NE(iter, map.end());
849 EXPECT_STREQ(iter->name(), "d");
850
851 iter = map.upper_bound(45);
852 ASSERT_NE(iter, map.end());
853 EXPECT_STREQ(iter->name(), "b");
854
855 EXPECT_EQ(map.upper_bound(55), map.end());
856 }
857
TEST_F(IntrusiveMapTest,UpperBound_NoExactKey)858 TEST_F(IntrusiveMapTest, UpperBound_NoExactKey) {
859 const IntrusiveMap& map = map_;
860 auto iter = map.upper_bound(5);
861 ASSERT_NE(iter, map.end());
862 EXPECT_STREQ(iter->name(), "e");
863
864 iter = map.upper_bound(15);
865 ASSERT_NE(iter, map.end());
866 EXPECT_STREQ(iter->name(), "c");
867
868 iter = map.upper_bound(25);
869 ASSERT_NE(iter, map.end());
870 EXPECT_STREQ(iter->name(), "a");
871
872 iter = map.upper_bound(35);
873 ASSERT_NE(iter, map.end());
874 EXPECT_STREQ(iter->name(), "d");
875
876 iter = map.upper_bound(45);
877 ASSERT_NE(iter, map.end());
878 EXPECT_STREQ(iter->name(), "b");
879 }
880
TEST_F(IntrusiveMapTest,UpperBound_OutOfRange)881 TEST_F(IntrusiveMapTest, UpperBound_OutOfRange) {
882 const IntrusiveMap& map = map_;
883 EXPECT_EQ(map.upper_bound(55), map.end());
884 }
885
TEST_F(IntrusiveMapTest,EqualRange)886 TEST_F(IntrusiveMapTest, EqualRange) {
887 const IntrusiveMap& map = map_;
888
889 auto pair = map.equal_range(10);
890 IntrusiveMap::const_iterator lower = pair.first;
891 IntrusiveMap::const_iterator upper = pair.second;
892 ASSERT_NE(lower, map.end());
893 EXPECT_STREQ(lower->name(), "e");
894 ASSERT_NE(upper, map.end());
895 EXPECT_STREQ(upper->name(), "E");
896
897 std::tie(lower, upper) = map.equal_range(20);
898 ASSERT_NE(lower, map.end());
899 EXPECT_STREQ(lower->name(), "c");
900 ASSERT_NE(upper, map.end());
901 EXPECT_STREQ(upper->name(), "C");
902
903 std::tie(lower, upper) = map.equal_range(30);
904 ASSERT_NE(lower, map.end());
905 EXPECT_STREQ(lower->name(), "a");
906 ASSERT_NE(upper, map.end());
907 EXPECT_STREQ(upper->name(), "A");
908
909 std::tie(lower, upper) = map.equal_range(40);
910 ASSERT_NE(lower, map.end());
911 EXPECT_STREQ(lower->name(), "d");
912 ASSERT_NE(upper, map.end());
913 EXPECT_STREQ(upper->name(), "D");
914
915 std::tie(lower, upper) = map.equal_range(50);
916 ASSERT_NE(lower, map.end());
917 EXPECT_STREQ(lower->name(), "b");
918 ASSERT_NE(upper, map.end());
919 EXPECT_STREQ(upper->name(), "B");
920 }
921
TEST_F(IntrusiveMapTest,EqualRange_NoExactKey)922 TEST_F(IntrusiveMapTest, EqualRange_NoExactKey) {
923 const IntrusiveMap& map = map_;
924
925 auto pair = map.equal_range(6);
926 IntrusiveMap::const_iterator lower = pair.first;
927 IntrusiveMap::const_iterator upper = pair.second;
928 ASSERT_NE(lower, map.end());
929 EXPECT_STREQ(lower->name(), "e");
930 ASSERT_NE(upper, map.end());
931 EXPECT_STREQ(upper->name(), "e");
932
933 std::tie(lower, upper) = map.equal_range(16);
934 ASSERT_NE(lower, map.end());
935 EXPECT_STREQ(lower->name(), "c");
936 ASSERT_NE(upper, map.end());
937 EXPECT_STREQ(upper->name(), "c");
938
939 std::tie(lower, upper) = map.equal_range(26);
940 ASSERT_NE(lower, map.end());
941 EXPECT_STREQ(lower->name(), "a");
942 ASSERT_NE(upper, map.end());
943 EXPECT_STREQ(upper->name(), "a");
944
945 std::tie(lower, upper) = map.equal_range(36);
946 ASSERT_NE(lower, map.end());
947 EXPECT_STREQ(lower->name(), "d");
948 ASSERT_NE(upper, map.end());
949 EXPECT_STREQ(upper->name(), "d");
950
951 std::tie(lower, upper) = map.equal_range(46);
952 ASSERT_NE(lower, map.end());
953 EXPECT_STREQ(lower->name(), "b");
954 ASSERT_NE(upper, map.end());
955 EXPECT_STREQ(upper->name(), "b");
956 }
957
TEST_F(IntrusiveMapTest,EqualRange_OutOfRange)958 TEST_F(IntrusiveMapTest, EqualRange_OutOfRange) {
959 const IntrusiveMap& map = map_;
960
961 auto pair = map.equal_range(56);
962 IntrusiveMap::const_iterator lower = pair.first;
963 IntrusiveMap::const_iterator upper = pair.second;
964 EXPECT_EQ(lower, map.end());
965 EXPECT_EQ(upper, map.end());
966 }
967
968 } // namespace
969