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