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