xref: /aosp_15_r20/external/pigweed/pw_containers/intrusive_map_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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