1 // Copyright 2020 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_list.h"
16
17 #include <array>
18 #include <cstddef>
19 #include <cstdint>
20
21 #include "pw_compilation_testing/negative_compilation.h"
22 #include "pw_containers/vector.h"
23 #include "pw_preprocessor/util.h"
24 #include "pw_unit_test/framework.h"
25
26 namespace {
27
28 // Test fixtures
29
30 using ::pw::containers::future::IntrusiveList;
31
32 class Item : public IntrusiveList<Item>::Item {
33 public:
34 constexpr Item() = default;
Item(int number)35 constexpr Item(int number) : number_(number) {}
36
Item(Item && other)37 Item(Item&& other) { *this = std::move(other); }
operator =(Item && other)38 Item& operator=(Item&& other) {
39 number_ = other.number_;
40 return *this;
41 }
42
GetNumber() const43 int GetNumber() const { return number_; }
SetNumber(int num)44 void SetNumber(int num) { number_ = num; }
45
46 // This operator ensures comparisons are done by identity rather than equality
47 // for `remove`, and allows using the zero-parameter overload of `unique`.
operator ==(const Item & other) const48 bool operator==(const Item& other) const { return number_ == other.number_; }
49
50 // This operator allows using the zero-parameter overloads of `merge` and
51 // `sort`.
operator <(const Item & other) const52 bool operator<(const Item& other) const { return number_ < other.number_; }
53
54 private:
55 int number_ = 0;
56 };
57
58 using List = IntrusiveList<Item>;
59
60 // Test that a list of items derived from a different Item class can be created.
61 class DerivedItem : public Item {};
62
63 // TODO: b/235289499 - Tests guarded by this definition should trigger CHECK
64 // failures. These require using a testing version of pw_assert.
65 #ifndef TESTING_CHECK_FAILURES_IS_SUPPORTED
66 #define TESTING_CHECK_FAILURES_IS_SUPPORTED 0
67 #endif // TESTING_CHECK_FAILURES_IS_SUPPORTED
68
69 // Unit tests.
70
TEST(IntrusiveListTest,Construct_InitializerList_Empty)71 TEST(IntrusiveListTest, Construct_InitializerList_Empty) {
72 List list({});
73 EXPECT_TRUE(list.empty());
74 }
75
TEST(IntrusiveListTest,Construct_InitializerList_One)76 TEST(IntrusiveListTest, Construct_InitializerList_One) {
77 Item one(1);
78 List list({&one});
79
80 EXPECT_EQ(&one, &list.front());
81 list.clear();
82 }
83
TEST(IntrusiveListTest,Construct_InitializerList_Multiple)84 TEST(IntrusiveListTest, Construct_InitializerList_Multiple) {
85 Item one(1);
86 Item two(2);
87 Item thr(3);
88
89 List list({&one, &two, &thr});
90 auto it = list.begin();
91 EXPECT_EQ(&one, &(*it++));
92 EXPECT_EQ(&two, &(*it++));
93 EXPECT_EQ(&thr, &(*it++));
94 EXPECT_EQ(list.end(), it);
95 list.clear();
96 }
97
TEST(IntrusiveListTest,Construct_ObjectIterator_Empty)98 TEST(IntrusiveListTest, Construct_ObjectIterator_Empty) {
99 std::array<Item, 0> array;
100 List list(array.begin(), array.end());
101
102 EXPECT_TRUE(list.empty());
103 }
104
TEST(IntrusiveListTest,Construct_ObjectIterator_One)105 TEST(IntrusiveListTest, Construct_ObjectIterator_One) {
106 std::array<Item, 1> array{{{1}}};
107 List list(array.begin(), array.end());
108
109 EXPECT_EQ(&array.front(), &list.front());
110 list.clear();
111 }
112
TEST(IntrusiveListTest,Construct_ObjectIterator_Multiple)113 TEST(IntrusiveListTest, Construct_ObjectIterator_Multiple) {
114 std::array<Item, 3> array{{{1}, {2}, {3}}};
115
116 List list(array.begin(), array.end());
117 auto it = list.begin();
118 EXPECT_EQ(&array[0], &(*it++));
119 EXPECT_EQ(&array[1], &(*it++));
120 EXPECT_EQ(&array[2], &(*it++));
121 EXPECT_EQ(list.end(), it);
122 list.clear();
123 }
124
TEST(IntrusiveListTest,Construct_PointerIterator_Empty)125 TEST(IntrusiveListTest, Construct_PointerIterator_Empty) {
126 std::array<Item*, 0> array;
127 List list(array.begin(), array.end());
128
129 EXPECT_TRUE(list.empty());
130 list.clear();
131 }
132
TEST(IntrusiveListTest,Construct_PointerIterator_One)133 TEST(IntrusiveListTest, Construct_PointerIterator_One) {
134 std::array<Item, 1> array{{{1}}};
135 std::array<Item*, 1> ptrs{{&array[0]}};
136
137 List list(ptrs.begin(), ptrs.end());
138
139 EXPECT_EQ(ptrs[0], &list.front());
140 list.clear();
141 }
142
TEST(IntrusiveListTest,Construct_PointerIterator_Multiple)143 TEST(IntrusiveListTest, Construct_PointerIterator_Multiple) {
144 std::array<Item, 3> array{{{1}, {2}, {3}}};
145 std::array<Item*, 3> ptrs{{&array[0], &array[1], &array[2]}};
146
147 List list(ptrs.begin(), ptrs.end());
148 auto it = list.begin();
149 EXPECT_EQ(ptrs[0], &(*it++));
150 EXPECT_EQ(ptrs[1], &(*it++));
151 EXPECT_EQ(ptrs[2], &(*it++));
152 EXPECT_EQ(list.end(), it);
153 list.clear();
154 }
155
156 #if TESTING_CHECK_FAILURES_IS_SUPPORTED
TEST(IntrusiveListTest,Construct_DuplicateItems)157 TEST(IntrusiveListTest, Construct_DuplicateItems) {
158 Item item(1);
159 List list({&item, &item});
160 }
161 #endif // TESTING_CHECK_FAILURES_IS_SUPPORTED
162
TEST(IntrusiveListTest,Assign_ReplacesPriorContents)163 TEST(IntrusiveListTest, Assign_ReplacesPriorContents) {
164 std::array<Item, 3> array{{{0}, {100}, {200}}};
165 List list(array.begin(), array.end());
166
167 list.assign(array.begin() + 1, array.begin() + 2);
168
169 auto it = list.begin();
170 EXPECT_EQ(&array[1], &(*it++));
171 EXPECT_EQ(list.end(), it);
172 list.clear();
173 }
174
TEST(IntrusiveListTest,Assign_EmptyRange)175 TEST(IntrusiveListTest, Assign_EmptyRange) {
176 std::array<Item, 3> array{{{0}, {100}, {200}}};
177 List list(array.begin(), array.end());
178
179 list.assign(array.begin() + 1, array.begin() + 1);
180
181 EXPECT_TRUE(list.empty());
182 }
183
184 // Element access unit tests
185
TEST(IntrusiveListTest,ListFront)186 TEST(IntrusiveListTest, ListFront) {
187 Item item1(1);
188 Item item2(0);
189 Item item3(0xffff);
190
191 List list;
192 list.push_back(item1);
193 list.push_back(item2);
194 list.push_back(item3);
195
196 EXPECT_EQ(&item1, &list.front());
197 EXPECT_EQ(&item1, &(*list.begin()));
198 list.clear();
199 }
200
TEST(IntrusiveListTest,ListBack)201 TEST(IntrusiveListTest, ListBack) {
202 Item item1(1);
203 Item item2(0);
204 Item item3(0xffff);
205
206 List list;
207 list.push_back(item1);
208 list.push_back(item2);
209 list.push_back(item3);
210
211 EXPECT_EQ(&item3, &list.back());
212 auto it = list.end();
213 --it;
214 EXPECT_EQ(&item3, &(*it));
215 list.clear();
216 }
217
218 // Iterator unit tests
219
TEST(IntrusiveListTest,IteratorIncrement)220 TEST(IntrusiveListTest, IteratorIncrement) {
221 Item item_array[20];
222 List list;
223 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array); ++i) {
224 item_array[i].SetNumber(static_cast<int>(i));
225 list.push_back(item_array[i]);
226 }
227
228 auto it = list.begin();
229 int i = 0;
230 while (it != list.end()) {
231 if (i == 0) {
232 // Test pre-incrementing on the first element.
233 EXPECT_EQ((++it)->GetNumber(), item_array[++i].GetNumber());
234 } else {
235 EXPECT_EQ((it++)->GetNumber(), item_array[i++].GetNumber());
236 }
237 }
238 list.clear();
239 }
240
TEST(IntrusiveListTest,IteratorDecrement)241 TEST(IntrusiveListTest, IteratorDecrement) {
242 Item item_array[20];
243 List list;
244 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array); ++i) {
245 item_array[i].SetNumber(static_cast<int>(i));
246 list.push_back(item_array[i]);
247 }
248
249 auto it = list.end();
250 int i = PW_ARRAY_SIZE(item_array);
251 do {
252 if (i == PW_ARRAY_SIZE(item_array)) {
253 // Test pre-incrementing on the last element.
254 EXPECT_EQ((--it)->GetNumber(), item_array[--i].GetNumber());
255 } else {
256 EXPECT_EQ((it--)->GetNumber(), item_array[i--].GetNumber());
257 }
258 } while (it != list.begin());
259 list.clear();
260 }
261
TEST(IntrusiveListTest,ConstIteratorRead)262 TEST(IntrusiveListTest, ConstIteratorRead) {
263 // For this test, items are checked to be non-zero.
264 Item item1(1);
265 Item item2(99);
266 List list;
267
268 const List* const_list = &list;
269
270 list.push_back(item1);
271 list.push_back(item2);
272
273 auto it = const_list->begin();
274 while (it != const_list->end()) {
275 EXPECT_NE(it->GetNumber(), 0);
276 it++;
277 }
278 list.clear();
279 }
280
TEST(IntrusiveListTest,CompareConstAndNonConstIterator)281 TEST(IntrusiveListTest, CompareConstAndNonConstIterator) {
282 List list;
283 EXPECT_EQ(list.end(), list.cend());
284 }
285
286 class OtherListItem : public IntrusiveList<OtherListItem>::Item {};
287
288 using OtherList = IntrusiveList<OtherListItem>;
289
TEST(IntrusiveListTest,CompareConstAndNonConstIterator_CompilationFails)290 TEST(IntrusiveListTest, CompareConstAndNonConstIterator_CompilationFails) {
291 List list;
292 OtherList list2;
293 #if PW_NC_TEST(CannotCompareIncompatibleIteratorsEqual)
294 PW_NC_EXPECT("list\.end\(\) == list2\.end\(\)");
295 static_cast<void>(list.end() == list2.end());
296 #elif PW_NC_TEST(CannotCompareIncompatibleIteratorsInequal)
297 PW_NC_EXPECT("list\.end\(\) != list2\.end\(\)");
298 static_cast<void>(list.end() != list2.end());
299 #endif // PW_NC_TEST
300 }
301
302 #if PW_NC_TEST(CannotModifyThroughConstIterator)
303 PW_NC_EXPECT("function is not marked const|discards qualifiers");
304
TEST(IntrusiveListTest,ConstIteratorModify)305 TEST(IntrusiveListTest, ConstIteratorModify) {
306 Item item1(1);
307 Item item2(99);
308 List list;
309
310 const List* const_list = &list;
311
312 list.push_back(item1);
313 list.push_back(item2);
314
315 auto it = const_list->begin();
316 while (it != const_list->end()) {
317 it->SetNumber(0);
318 it++;
319 }
320 }
321
322 #endif // PW_NC_TEST
323
324 // Capacity unit tests
325
TEST(IntrusiveListTest,IsEmpty)326 TEST(IntrusiveListTest, IsEmpty) {
327 Item item1(1);
328
329 List list;
330 EXPECT_TRUE(list.empty());
331
332 list.push_back(item1);
333 EXPECT_FALSE(list.empty());
334 list.clear();
335 }
336
TEST(IntrusiveListTest,SizeBasic)337 TEST(IntrusiveListTest, SizeBasic) {
338 List list;
339 EXPECT_EQ(list.size(), 0u);
340
341 Item one(55);
342 list.push_front(one);
343 EXPECT_EQ(list.size(), static_cast<size_t>(1));
344
345 Item two(66);
346 list.push_back(two);
347 EXPECT_EQ(list.size(), static_cast<size_t>(2));
348
349 Item thr(77);
350 list.push_back(thr);
351 EXPECT_EQ(list.size(), static_cast<size_t>(3));
352 list.clear();
353 }
354
TEST(IntrusiveListTest,MaxSize)355 TEST(IntrusiveListTest, MaxSize) {
356 List list;
357 EXPECT_EQ(list.max_size(), size_t(std::numeric_limits<ptrdiff_t>::max()));
358 }
359
360 // Modifier unit tests
361
TEST(IntrusiveListTest,Clear_Empty)362 TEST(IntrusiveListTest, Clear_Empty) {
363 List list;
364 EXPECT_TRUE(list.empty());
365 list.clear();
366 EXPECT_TRUE(list.empty());
367 }
368
TEST(IntrusiveListTest,Clear_OneItem)369 TEST(IntrusiveListTest, Clear_OneItem) {
370 Item item(42);
371 List list;
372 list.push_back(item);
373 EXPECT_FALSE(list.empty());
374 list.clear();
375 EXPECT_TRUE(list.empty());
376 }
377
TEST(IntrusiveListTest,Clear_TwoItems)378 TEST(IntrusiveListTest, Clear_TwoItems) {
379 Item item1(42);
380 Item item2(42);
381 List list;
382 list.push_back(item1);
383 list.push_back(item2);
384 EXPECT_FALSE(list.empty());
385 list.clear();
386 EXPECT_TRUE(list.empty());
387 }
388
TEST(IntrusiveListTest,Clear_ReinsertClearedItems)389 TEST(IntrusiveListTest, Clear_ReinsertClearedItems) {
390 std::array<Item, 20> item_array;
391 List list;
392 EXPECT_TRUE(list.empty());
393 list.clear();
394 EXPECT_TRUE(list.empty());
395
396 // Fill the list with Item objects.
397 for (size_t i = 0; i < item_array.size(); ++i) {
398 item_array[i].SetNumber(0);
399 list.push_back(item_array[i]);
400 }
401
402 // Remove everything.
403 list.clear();
404 EXPECT_TRUE(list.empty());
405
406 // Ensure all the removed elements can still be added back to a list.
407 for (size_t i = 0; i < item_array.size(); ++i) {
408 item_array[i].SetNumber(0);
409 list.push_back(item_array[i]);
410 }
411 list.clear();
412 }
413
TEST(IntrusiveListTest,Insert)414 TEST(IntrusiveListTest, Insert) {
415 // Create a test item to insert midway through the list.
416 constexpr int kMagicValue = 42;
417 Item inserted_item(kMagicValue);
418
419 // Create initial values to fill in the start/end.
420 Item item_array[20];
421
422 List list;
423 // Fill the list with Item objects that have a value of zero.
424 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array); ++i) {
425 item_array[i].SetNumber(0);
426 list.push_back(item_array[i]);
427 }
428
429 // Move an iterator to the middle of the list, and then insert the magic item.
430 auto it = list.begin();
431 size_t expected_index = 0; // Expected index is iterator index.
432 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array) / 2; ++i) {
433 it++;
434 expected_index++;
435 }
436 it = list.insert(it, inserted_item);
437
438 // Ensure the returned iterator from insert is the newly inserted
439 // element.
440 EXPECT_EQ(it->GetNumber(), kMagicValue);
441
442 // Ensure the value is in the expected location (index of the iterator + 1).
443 size_t i = 0;
444 for (Item& item : list) {
445 if (item.GetNumber() == kMagicValue) {
446 EXPECT_EQ(i, expected_index);
447 } else {
448 EXPECT_EQ(item.GetNumber(), 0);
449 }
450 i++;
451 }
452
453 // Ensure the list didn't break and change sizes.
454 EXPECT_EQ(i, PW_ARRAY_SIZE(item_array) + 1);
455 list.clear();
456 }
457
TEST(IntrusiveListTest,Insert_Range)458 TEST(IntrusiveListTest, Insert_Range) {
459 // Create an array of test items to insert into the middle of the list.
460 constexpr int kMagicValue = 42;
461 constexpr int kNumItems = 3;
462 std::array<Item, kNumItems> inserted_items;
463 int n = kMagicValue;
464 for (auto& item : inserted_items) {
465 item.SetNumber(n++);
466 }
467
468 // Create initial values to fill in the start/end.
469 Item item_array[20];
470
471 List list;
472 // Fill the list with Item objects that have a value of zero.
473 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array); ++i) {
474 item_array[i].SetNumber(0);
475 list.push_back(item_array[i]);
476 }
477
478 // Move an iterator to the middle of the list, and then insert the magic item.
479 auto it = list.begin();
480 size_t expected_index = 0; // Expected index is iterator index.
481 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array) / 2; ++i) {
482 it++;
483 expected_index++;
484 }
485 it = list.insert(it, inserted_items.begin(), inserted_items.end());
486
487 // Ensure the returned iterator from insert is the last newly inserted
488 // element.
489 EXPECT_EQ(it->GetNumber(), kMagicValue + kNumItems - 1);
490
491 // Ensure the value is in the expected location (index of the iterator + 1).
492 size_t i = 0;
493 for (Item& item : list) {
494 if (i < expected_index) {
495 EXPECT_EQ(item.GetNumber(), 0);
496 } else if (i < expected_index + inserted_items.size()) {
497 EXPECT_EQ(item.GetNumber(),
498 kMagicValue + static_cast<int>(i - expected_index));
499 } else {
500 EXPECT_EQ(item.GetNumber(), 0);
501 }
502 i++;
503 }
504
505 // Ensure the list didn't break and change sizes.
506 EXPECT_EQ(i, PW_ARRAY_SIZE(item_array) + inserted_items.size());
507 list.clear();
508 }
509
TEST(IntrusiveListTest,Insert_InitializerList)510 TEST(IntrusiveListTest, Insert_InitializerList) {
511 // Create an array of test items to insert into the middle of the list.
512 constexpr int kMagicValue = 42;
513 constexpr int kNumItems = 3;
514 std::array<Item, kNumItems> inserted_items;
515 int n = kMagicValue;
516 for (auto& item : inserted_items) {
517 item.SetNumber(n++);
518 }
519
520 // Create initial values to fill in the start/end.
521 Item item_array[20];
522
523 List list;
524 // Fill the list with Item objects that have a value of zero.
525 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array); ++i) {
526 item_array[i].SetNumber(0);
527 list.push_back(item_array[i]);
528 }
529
530 // Move an iterator to the middle of the list, and then insert the magic item.
531 auto it = list.begin();
532 size_t expected_index = 0; // Expected index is iterator index.
533 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array) / 2; ++i) {
534 it++;
535 expected_index++;
536 }
537 it = list.insert(it,
538 {
539 &inserted_items[0],
540 &inserted_items[1],
541 &inserted_items[2],
542 });
543
544 // Ensure the returned iterator from insert is the last newly inserted
545 // element.
546 EXPECT_EQ(it->GetNumber(), kMagicValue + kNumItems - 1);
547
548 // Ensure the value is in the expected location (index of the iterator + 1).
549 size_t i = 0;
550 for (Item& item : list) {
551 if (i < expected_index) {
552 EXPECT_EQ(item.GetNumber(), 0);
553 } else if (i < expected_index + inserted_items.size()) {
554 EXPECT_EQ(item.GetNumber(),
555 kMagicValue + static_cast<int>(i - expected_index));
556 } else {
557 EXPECT_EQ(item.GetNumber(), 0);
558 }
559 i++;
560 }
561
562 // Ensure the list didn't break and change sizes.
563 EXPECT_EQ(i, PW_ARRAY_SIZE(item_array) + inserted_items.size());
564 list.clear();
565 }
566
TEST(IntrusiveListTest,Insert_BeforeBegin)567 TEST(IntrusiveListTest, Insert_BeforeBegin) {
568 // Create a test item to insert at the beginning of the list.
569 constexpr int kMagicValue = 42;
570 Item inserted_item(kMagicValue);
571
572 // Create initial values to fill in the start/end.
573 Item item_array[20];
574
575 List list;
576 // Fill the list with Item objects that have a value of zero.
577 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array); ++i) {
578 item_array[i].SetNumber(0);
579 list.push_back(item_array[i]);
580 }
581
582 auto it = list.insert(list.begin(), inserted_item);
583
584 // Ensure the returned iterator from insert is the newly inserted
585 // element.
586 EXPECT_EQ(it->GetNumber(), kMagicValue);
587
588 // Ensure the value is at the beginning of the list.
589 size_t i = 0;
590 for (Item& item : list) {
591 if (item.GetNumber() == kMagicValue) {
592 EXPECT_EQ(i, static_cast<size_t>(0));
593 } else {
594 EXPECT_EQ(item.GetNumber(), 0);
595 }
596 i++;
597 }
598 list.clear();
599 }
600
TEST(IntrusiveListTest,Insert_BeforeBegin_Range)601 TEST(IntrusiveListTest, Insert_BeforeBegin_Range) {
602 // Create an array of test items to insert into the middle of the list.
603 constexpr int kMagicValue = 42;
604 constexpr int kNumItems = 3;
605 std::array<Item, kNumItems> inserted_items;
606 int n = kMagicValue;
607 for (auto& item : inserted_items) {
608 item.SetNumber(n++);
609 }
610
611 // Create initial values to fill in the start/end.
612 Item item_array[20];
613
614 List list;
615 // Fill the list with Item objects that have a value of zero.
616 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array); ++i) {
617 item_array[i].SetNumber(0);
618 list.push_back(item_array[i]);
619 }
620
621 auto it =
622 list.insert(list.begin(), inserted_items.begin(), inserted_items.end());
623
624 // Ensure the returned iterator from insert is the last newly inserted
625 // element.
626 EXPECT_EQ(it->GetNumber(), kMagicValue + kNumItems - 1);
627
628 // Ensure the values are at the beginning of the list.
629 size_t i = 0;
630 for (Item& item : list) {
631 if (i < inserted_items.size()) {
632 EXPECT_EQ(item.GetNumber(), kMagicValue + static_cast<int>(i));
633 } else {
634 EXPECT_EQ(item.GetNumber(), 0);
635 }
636 i++;
637 }
638 list.clear();
639 }
640
TEST(IntrusiveListTest,Insert_BeforeBegin_InitializerList)641 TEST(IntrusiveListTest, Insert_BeforeBegin_InitializerList) {
642 // Create an array of test items to insert into the middle of the list.
643 constexpr int kMagicValue = 42;
644 constexpr int kNumItems = 3;
645 std::array<Item, kNumItems> inserted_items;
646 int n = kMagicValue;
647 for (auto& item : inserted_items) {
648 item.SetNumber(n++);
649 }
650
651 // Create initial values to fill in the start/end.
652 Item item_array[20];
653
654 List list;
655 // Fill the list with Item objects that have a value of zero.
656 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array); ++i) {
657 item_array[i].SetNumber(0);
658 list.push_back(item_array[i]);
659 }
660
661 auto it = list.insert(list.begin(),
662 {
663 &inserted_items[0],
664 &inserted_items[1],
665 &inserted_items[2],
666 });
667
668 // Ensure the returned iterator from insert is the last newly inserted
669 // element.
670 EXPECT_EQ(it->GetNumber(), kMagicValue + kNumItems - 1);
671
672 // Ensure the values are at the beginning of the list.
673 size_t i = 0;
674 for (Item& item : list) {
675 if (i < inserted_items.size()) {
676 EXPECT_EQ(item.GetNumber(), kMagicValue + static_cast<int>(i));
677 } else {
678 EXPECT_EQ(item.GetNumber(), 0);
679 }
680 i++;
681 }
682 list.clear();
683 }
684
685 #if TESTING_CHECK_FAILURES_IS_SUPPORTED
TEST(IntrusiveListTest,Insert_SameItem)686 TEST(IntrusiveListTest, Insert_SameItem) {
687 Item item(1);
688 List list({&item});
689
690 list.insert(list.begin(), item);
691 }
692
TEST(IntrusiveListTest,Insert_SameItemAfterEnd)693 TEST(IntrusiveListTest, Insert_SameItemAfterEnd) {
694 Item item(1);
695 List list({&item});
696
697 list.insert(list.end(), item);
698 }
699 #endif // TESTING_CHECK_FAILURES_IS_SUPPORTED
700
TEST(IntrusiveListTest,Erase_First_ByIterator)701 TEST(IntrusiveListTest, Erase_First_ByIterator) {
702 std::array<Item, 3> items{{{0}, {1}, {2}}};
703 List list(items.begin(), items.end());
704
705 auto it = list.erase(list.begin());
706 EXPECT_EQ(list.begin(), it);
707 EXPECT_EQ(&items[1], &list.front());
708 list.clear();
709 }
710
TEST(IntrusiveListTest,Erase_First_ByItem)711 TEST(IntrusiveListTest, Erase_First_ByItem) {
712 std::array<Item, 3> items{{{0}, {1}, {2}}};
713 List list(items.begin(), items.end());
714
715 auto erased = list.erase(items[0]);
716 auto iter = list.begin();
717 EXPECT_EQ(erased, iter);
718 EXPECT_EQ(&items[1], &(*iter++));
719 EXPECT_EQ(&items[2], &(*iter++));
720 EXPECT_EQ(list.end(), iter);
721 list.clear();
722 }
723
TEST(IntrusiveListTest,Erase_Middle_ByItem)724 TEST(IntrusiveListTest, Erase_Middle_ByItem) {
725 std::array<Item, 3> items{{{0}, {1}, {2}}};
726 List list(items.begin(), items.end());
727
728 auto erased = list.erase(items[1]);
729 auto iter = list.begin();
730 EXPECT_EQ(&items[0], &(*iter++));
731 EXPECT_EQ(erased, iter);
732 EXPECT_EQ(&items[2], &(*iter++));
733 EXPECT_EQ(list.end(), iter);
734 list.clear();
735 }
736
TEST(IntrusiveListTest,Erase_Last_ByIterator)737 TEST(IntrusiveListTest, Erase_Last_ByIterator) {
738 std::array<Item, 3> items{{{0}, {1}, {2}}};
739 List list(items.begin(), items.end());
740
741 auto it = list.end();
742 --it;
743
744 it = list.erase(it);
745 EXPECT_EQ(list.end(), it);
746
747 it = list.begin();
748 ++it;
749
750 EXPECT_EQ(&items[1], &(*it));
751 list.clear();
752 }
753
TEST(IntrusiveListTest,Erase_Last_ByItem)754 TEST(IntrusiveListTest, Erase_Last_ByItem) {
755 std::array<Item, 3> items{{{0}, {1}, {2}}};
756 List list(items.begin(), items.end());
757
758 auto erased = list.erase(items[2]);
759 auto iter = list.begin();
760 EXPECT_EQ(&items[0], &(*iter++));
761 EXPECT_EQ(&items[1], &(*iter++));
762 EXPECT_EQ(erased, iter);
763 EXPECT_EQ(list.end(), iter);
764 list.clear();
765 }
766
TEST(IntrusiveListTest,Erase_AllItems)767 TEST(IntrusiveListTest, Erase_AllItems) {
768 std::array<Item, 3> items{{{0}, {1}, {2}}};
769 List list(items.begin(), items.end());
770
771 list.erase(list.begin());
772 list.erase(list.begin());
773 auto it = list.erase(list.begin());
774
775 EXPECT_EQ(list.end(), it);
776 EXPECT_TRUE(list.empty());
777 }
778
TEST(IntrusiveListTest,Erase_LeadingRange)779 TEST(IntrusiveListTest, Erase_LeadingRange) {
780 std::array<Item, 4> items{{{0}, {1}, {2}, {3}}};
781 List list(items.begin(), items.end());
782
783 auto it = list.begin();
784 it = list.erase(it, std::next(std::next(it)));
785 EXPECT_EQ(list.begin(), it);
786 EXPECT_EQ(&items[2], &(*it++));
787 EXPECT_EQ(&items[3], &(*it++));
788 EXPECT_EQ(list.end(), it);
789 list.clear();
790 }
791
TEST(IntrusiveListTest,Erase_TrailingRange)792 TEST(IntrusiveListTest, Erase_TrailingRange) {
793 std::array<Item, 4> items{{{0}, {1}, {2}, {3}}};
794 List list(items.begin(), items.end());
795
796 auto it = list.end();
797 it = list.erase(std::prev(std::prev(it)), it);
798 EXPECT_EQ(list.end(), it);
799
800 it = list.begin();
801 EXPECT_EQ(&items[0], &(*it++));
802 EXPECT_EQ(&items[1], &(*it++));
803 EXPECT_EQ(list.end(), it);
804 list.clear();
805 }
806
TEST(IntrusiveListTest,Erase_FullRange)807 TEST(IntrusiveListTest, Erase_FullRange) {
808 std::array<Item, 4> items{{{0}, {1}, {2}, {3}}};
809 List list(items.begin(), items.end());
810
811 auto it = list.erase(list.begin(), list.end());
812 EXPECT_EQ(list.end(), it);
813 EXPECT_TRUE(list.empty());
814 }
815
TEST(IntrusiveListTest,Erase_EmptyRange)816 TEST(IntrusiveListTest, Erase_EmptyRange) {
817 std::array<Item, 4> items{{{0}, {1}, {2}, {3}}};
818 List list(items.begin(), items.end());
819
820 auto it = list.erase(list.begin(), list.begin());
821 EXPECT_EQ(list.begin(), it);
822 EXPECT_EQ(&items[0], &list.front());
823 list.clear();
824 }
825
TEST(IntrusiveListTest,PushBackOne)826 TEST(IntrusiveListTest, PushBackOne) {
827 constexpr int kMagicValue = 31;
828 Item item1(kMagicValue);
829 List list;
830 list.push_back(item1);
831 EXPECT_FALSE(list.empty());
832 EXPECT_EQ(list.front().GetNumber(), kMagicValue);
833 list.clear();
834 }
835
TEST(IntrusiveListTest,PushBackThree)836 TEST(IntrusiveListTest, PushBackThree) {
837 Item item1(1);
838 Item item2(2);
839 Item item3(3);
840
841 List list;
842 list.push_back(item1);
843 list.push_back(item2);
844 list.push_back(item3);
845
846 int loop_count = 0;
847 for (auto& test_item : list) {
848 loop_count++;
849 EXPECT_EQ(loop_count, test_item.GetNumber());
850 }
851 EXPECT_EQ(loop_count, 3);
852 list.clear();
853 }
854
855 #if TESTING_CHECK_FAILURES_IS_SUPPORTED
TEST(IntrusiveListTest,PushBack_SameItem)856 TEST(IntrusiveListTest, PushBack_SameItem) {
857 Item item(1);
858 List list({&item});
859
860 list.push_back(item);
861 }
862 #endif // TESTING_CHECK_FAILURES_IS_SUPPORTED
863
TEST(IntrusiveListTest,PopBack)864 TEST(IntrusiveListTest, PopBack) {
865 constexpr int kValue1 = 32;
866 constexpr int kValue2 = 4083;
867
868 Item item1(kValue1);
869 Item item2(kValue2);
870
871 List list;
872 EXPECT_TRUE(list.empty());
873
874 list.push_back(item1);
875 list.push_back(item2);
876 list.pop_back();
877 EXPECT_EQ(list.back().GetNumber(), kValue1);
878 EXPECT_FALSE(list.empty());
879 list.pop_back();
880 EXPECT_TRUE(list.empty());
881 }
882
TEST(IntrusiveListTest,PopBackAndReinsert)883 TEST(IntrusiveListTest, PopBackAndReinsert) {
884 constexpr int kValue1 = 32;
885 constexpr int kValue2 = 4083;
886
887 Item item1(kValue1);
888 Item item2(kValue2);
889
890 List list;
891 EXPECT_TRUE(list.empty());
892
893 list.push_back(item1);
894 list.push_back(item2);
895 list.pop_back();
896 list.push_back(item2);
897 EXPECT_EQ(list.back().GetNumber(), kValue2);
898 list.clear();
899 }
900
TEST(IntrusiveListTest,PushFront)901 TEST(IntrusiveListTest, PushFront) {
902 constexpr int kMagicValue = 42;
903 Item pushed_item(kMagicValue);
904
905 Item item_array[20];
906 List list;
907 // Fill the list with Item objects that have a value of zero.
908 for (size_t i = 0; i < PW_ARRAY_SIZE(item_array); ++i) {
909 item_array[i].SetNumber(0);
910 list.push_back(item_array[i]);
911 }
912
913 // Create a test item to push to the front of the list.
914 list.push_front(pushed_item);
915 EXPECT_EQ(list.front().GetNumber(), kMagicValue);
916 list.clear();
917 }
918
TEST(IntrusiveListTest,PushFrontOne)919 TEST(IntrusiveListTest, PushFrontOne) {
920 constexpr int kMagicValue = 31;
921 Item item1(kMagicValue);
922 List list;
923 list.push_front(item1);
924 EXPECT_FALSE(list.empty());
925 EXPECT_EQ(list.front().GetNumber(), kMagicValue);
926 list.clear();
927 }
928
TEST(IntrusiveListTest,PushFrontThree)929 TEST(IntrusiveListTest, PushFrontThree) {
930 Item item1(1);
931 Item item2(2);
932 Item item3(3);
933
934 List list;
935 list.push_front(item3);
936 list.push_front(item2);
937 list.push_front(item1);
938
939 int loop_count = 0;
940 for (auto& test_item : list) {
941 loop_count++;
942 EXPECT_EQ(loop_count, test_item.GetNumber());
943 }
944 EXPECT_EQ(loop_count, 3);
945 list.clear();
946 }
947
948 #if TESTING_CHECK_FAILURES_IS_SUPPORTED
TEST(IntrusiveListTest,PushFront_SameItem)949 TEST(IntrusiveListTest, PushFront_SameItem) {
950 Item item(1);
951 List list({&item});
952
953 list.push_front(item);
954 }
955 #endif // TESTING_CHECK_FAILURES_IS_SUPPORTED
956
TEST(IntrusiveListTest,PopFront)957 TEST(IntrusiveListTest, PopFront) {
958 constexpr int kValue1 = 32;
959 constexpr int kValue2 = 4083;
960
961 Item item1(kValue1);
962 Item item2(kValue2);
963
964 List list;
965 EXPECT_TRUE(list.empty());
966
967 list.push_front(item2);
968 list.push_front(item1);
969 list.pop_front();
970 EXPECT_EQ(list.front().GetNumber(), kValue2);
971 EXPECT_FALSE(list.empty());
972 list.pop_front();
973 EXPECT_TRUE(list.empty());
974 }
975
TEST(IntrusiveListTest,PopFrontAndReinsert)976 TEST(IntrusiveListTest, PopFrontAndReinsert) {
977 constexpr int kValue1 = 32;
978 constexpr int kValue2 = 4083;
979
980 Item item1(kValue1);
981 Item item2(kValue2);
982
983 List list;
984 EXPECT_TRUE(list.empty());
985
986 list.push_front(item2);
987 list.push_front(item1);
988 list.pop_front();
989 list.push_front(item1);
990 EXPECT_EQ(list.front().GetNumber(), kValue1);
991 list.clear();
992 }
993
TEST(IntrusiveListTest,Swap)994 TEST(IntrusiveListTest, Swap) {
995 std::array<Item, 4> items1{{{0}, {1}, {2}, {3}}};
996 std::array<Item, 2> items2{{{4}, {5}}};
997 List list1(items1.begin(), items1.end());
998 List list2(items2.begin(), items2.end());
999
1000 list1.swap(list2);
1001
1002 auto it = list1.begin();
1003 EXPECT_EQ(&items2[0], &(*it++));
1004 EXPECT_EQ(&items2[1], &(*it++));
1005 EXPECT_EQ(it, list1.end());
1006
1007 it = list2.begin();
1008 EXPECT_EQ(&items1[0], &(*it++));
1009 EXPECT_EQ(&items1[1], &(*it++));
1010 EXPECT_EQ(&items1[2], &(*it++));
1011 EXPECT_EQ(&items1[3], &(*it++));
1012 EXPECT_EQ(it, list2.end());
1013
1014 list1.clear();
1015 list2.clear();
1016 }
1017
TEST(IntrusiveListTest,Swap_Empty)1018 TEST(IntrusiveListTest, Swap_Empty) {
1019 std::array<Item, 3> items1{{{0}, {1}, {2}}};
1020 List list1(items1.begin(), items1.end());
1021 List list2;
1022
1023 list1.swap(list2);
1024 EXPECT_TRUE(list1.empty());
1025
1026 auto it = list2.begin();
1027 EXPECT_EQ(&items1[0], &(*it++));
1028 EXPECT_EQ(&items1[1], &(*it++));
1029 EXPECT_EQ(&items1[2], &(*it++));
1030 EXPECT_EQ(it, list2.end());
1031
1032 list1.swap(list2);
1033 EXPECT_TRUE(list2.empty());
1034
1035 it = list1.begin();
1036 EXPECT_EQ(&items1[0], &(*it++));
1037 EXPECT_EQ(&items1[1], &(*it++));
1038 EXPECT_EQ(&items1[2], &(*it++));
1039 EXPECT_EQ(it, list1.end());
1040
1041 list1.clear();
1042 }
1043
1044 // Operation unit tests
1045
TEST(IntrusiveListTest,Merge)1046 TEST(IntrusiveListTest, Merge) {
1047 std::array<Item, 3> evens{{{0}, {2}, {4}}};
1048 std::array<Item, 3> odds{{{1}, {3}, {5}}};
1049
1050 List list(evens.begin(), evens.end());
1051 List other(odds.begin(), odds.end());
1052 list.merge(other);
1053 EXPECT_TRUE(other.empty());
1054
1055 int i = 0;
1056 for (const Item& item : list) {
1057 EXPECT_EQ(item.GetNumber(), i++);
1058 }
1059 EXPECT_EQ(i, 6);
1060 list.clear();
1061 }
1062
TEST(IntrusiveListTest,Merge_Compare)1063 TEST(IntrusiveListTest, Merge_Compare) {
1064 std::array<Item, 3> evens{{{4}, {2}, {0}}};
1065 std::array<Item, 3> odds{{{5}, {3}, {1}}};
1066 auto greater_than = [](const Item& a, const Item& b) {
1067 return a.GetNumber() > b.GetNumber();
1068 };
1069
1070 List list(evens.begin(), evens.end());
1071 List other(odds.begin(), odds.end());
1072 list.merge(other, greater_than);
1073 EXPECT_TRUE(other.empty());
1074
1075 int i = 6;
1076 for (const Item& item : list) {
1077 EXPECT_EQ(item.GetNumber(), --i);
1078 }
1079 EXPECT_EQ(i, 0);
1080 list.clear();
1081 }
1082
TEST(IntrusiveListTest,Merge_Empty)1083 TEST(IntrusiveListTest, Merge_Empty) {
1084 std::array<Item, 3> items{{{1}, {2}, {3}}};
1085
1086 List list;
1087 List other(items.begin(), items.end());
1088 list.merge(other);
1089
1090 EXPECT_TRUE(other.empty());
1091 list.merge(other);
1092
1093 int i = 1;
1094 for (const Item& item : list) {
1095 EXPECT_EQ(item.GetNumber(), i++);
1096 }
1097 EXPECT_EQ(i, 4);
1098 list.clear();
1099 }
1100
TEST(IntrusiveListTest,Merge_IsStable)1101 TEST(IntrusiveListTest, Merge_IsStable) {
1102 std::array<Item, 2> ends{{{0}, {2}}};
1103 std::array<Item, 3> mids{{{1}, {1}, {1}}};
1104
1105 List list(ends.begin(), ends.end());
1106 List other(mids.begin(), mids.end());
1107 list.merge(other);
1108 EXPECT_TRUE(other.empty());
1109
1110 auto it = list.begin();
1111 EXPECT_EQ(&ends[0], &(*it++));
1112 EXPECT_EQ(&mids[0], &(*it++));
1113 EXPECT_EQ(&mids[1], &(*it++));
1114 EXPECT_EQ(&mids[2], &(*it++));
1115 EXPECT_EQ(&ends[1], &(*it++));
1116 EXPECT_EQ(list.end(), it);
1117 list.clear();
1118 }
1119
TEST(IntrusiveListTest,Splice)1120 TEST(IntrusiveListTest, Splice) {
1121 std::array<Item, 2> items{{{1}, {5}}};
1122 std::array<Item, 3> other_items{{{2}, {3}, {4}}};
1123
1124 List list(items.begin(), items.end());
1125 List other(other_items.begin(), other_items.end());
1126 list.splice(std::next(list.begin()), other);
1127 EXPECT_TRUE(other.empty());
1128
1129 int i = 1;
1130 for (const Item& item : list) {
1131 EXPECT_EQ(item.GetNumber(), i++);
1132 }
1133 EXPECT_EQ(i, 6);
1134 list.clear();
1135 }
1136
TEST(IntrusiveListTest,Splice_BeforeBegin)1137 TEST(IntrusiveListTest, Splice_BeforeBegin) {
1138 std::array<Item, 2> items{{{4}, {5}}};
1139 std::array<Item, 3> other_items{{{1}, {2}, {3}}};
1140
1141 List list(items.begin(), items.end());
1142 List other(other_items.begin(), other_items.end());
1143 list.splice(list.begin(), other);
1144 EXPECT_TRUE(other.empty());
1145
1146 int i = 1;
1147 for (const Item& item : list) {
1148 EXPECT_EQ(item.GetNumber(), i++);
1149 }
1150 EXPECT_EQ(i, 6);
1151 list.clear();
1152 }
1153
TEST(IntrusiveListTest,Splice_BeforeEnd)1154 TEST(IntrusiveListTest, Splice_BeforeEnd) {
1155 std::array<Item, 2> items{{{1}, {2}}};
1156 std::array<Item, 3> other_items{{{3}, {4}, {5}}};
1157
1158 List list(items.begin(), items.end());
1159 List other(other_items.begin(), other_items.end());
1160 list.splice(list.end(), other);
1161 EXPECT_TRUE(other.empty());
1162
1163 int i = 1;
1164 for (const Item& item : list) {
1165 EXPECT_EQ(item.GetNumber(), i++);
1166 }
1167 EXPECT_EQ(i, 6);
1168 list.clear();
1169 }
1170
TEST(IntrusiveListTest,Splice_OneItem)1171 TEST(IntrusiveListTest, Splice_OneItem) {
1172 std::array<Item, 2> items{{{1}, {3}}};
1173 std::array<Item, 3> other_items{{{1}, {2}, {3}}};
1174
1175 List list(items.begin(), items.end());
1176 List other(other_items.begin(), other_items.end());
1177 list.splice(std::next(list.begin()), other, std::next(other.begin()));
1178 EXPECT_FALSE(other.empty());
1179
1180 int i = 1;
1181 for (const Item& item : list) {
1182 EXPECT_EQ(item.GetNumber(), i++);
1183 }
1184 EXPECT_EQ(i, 4);
1185 other.clear();
1186 list.clear();
1187 }
1188
TEST(IntrusiveListTest,Splice_Range)1189 TEST(IntrusiveListTest, Splice_Range) {
1190 std::array<Item, 2> items{{{1}, {5}}};
1191 std::array<Item, 5> other_items{{{1}, {2}, {3}, {4}, {5}}};
1192
1193 List list(items.begin(), items.end());
1194 List other(other_items.begin(), other_items.end());
1195 list.splice(std::next(list.begin()),
1196 other,
1197 std::next(other.begin()),
1198 std::prev(other.end()));
1199 EXPECT_FALSE(other.empty());
1200
1201 int i = 1;
1202 for (const Item& item : list) {
1203 EXPECT_EQ(item.GetNumber(), i++);
1204 }
1205 EXPECT_EQ(i, 6);
1206 other.clear();
1207 list.clear();
1208 }
1209
TEST(IntrusiveListTest,Splice_EmptyRange)1210 TEST(IntrusiveListTest, Splice_EmptyRange) {
1211 std::array<Item, 3> items{{{1}, {2}, {3}}};
1212 std::array<Item, 3> other_items{{{4}, {4}, {4}}};
1213
1214 List list(items.begin(), items.end());
1215 List other(other_items.begin(), other_items.end());
1216 list.splice(list.begin(), other, other.begin(), other.begin());
1217 EXPECT_FALSE(other.empty());
1218
1219 int i = 1;
1220 for (const Item& item : list) {
1221 EXPECT_EQ(item.GetNumber(), i++);
1222 }
1223 EXPECT_EQ(i, 4);
1224 other.clear();
1225 list.clear();
1226 }
1227
TEST(IntrusiveListTest,Remove_EmptyList)1228 TEST(IntrusiveListTest, Remove_EmptyList) {
1229 std::array<Item, 1> items{{{3}}};
1230 List list(items.begin(), items.begin()); // Add nothing!
1231
1232 EXPECT_TRUE(list.empty());
1233 EXPECT_FALSE(list.remove(items[0]));
1234 }
1235
TEST(IntrusiveListTest,Remove_SingleItem_NotPresent)1236 TEST(IntrusiveListTest, Remove_SingleItem_NotPresent) {
1237 std::array<Item, 1> items{{{1}}};
1238 List list(items.begin(), items.end());
1239
1240 EXPECT_FALSE(list.remove(Item(1)));
1241 EXPECT_EQ(&items.front(), &list.front());
1242 list.clear();
1243 }
1244
TEST(IntrusiveListTest,Remove_SingleItem_Removed)1245 TEST(IntrusiveListTest, Remove_SingleItem_Removed) {
1246 std::array<Item, 1> items{{{1}}};
1247 List list(items.begin(), items.end());
1248
1249 EXPECT_TRUE(list.remove(items[0]));
1250 EXPECT_TRUE(list.empty());
1251 }
1252
TEST(IntrusiveListTest,Remove_MultipleItems_NotPresent)1253 TEST(IntrusiveListTest, Remove_MultipleItems_NotPresent) {
1254 std::array<Item, 5> items{{{1}, {1}, {2}, {3}, {4}}};
1255 List list(items.begin(), items.end());
1256
1257 EXPECT_FALSE(list.remove(Item(1)));
1258 list.clear();
1259 }
1260
TEST(IntrusiveListTest,Remove_MultipleItems_RemoveAndPushBack)1261 TEST(IntrusiveListTest, Remove_MultipleItems_RemoveAndPushBack) {
1262 std::array<Item, 5> items{{{1}, {1}, {2}, {3}, {4}}};
1263 List list(items.begin(), items.end());
1264
1265 EXPECT_TRUE(list.remove(items[0]));
1266 EXPECT_TRUE(list.remove(items[3]));
1267 list.push_back(items[0]); // Make sure can add the item after removing it.
1268
1269 auto it = list.begin();
1270 EXPECT_EQ(&items[1], &(*it++));
1271 EXPECT_EQ(&items[2], &(*it++));
1272 EXPECT_EQ(&items[4], &(*it++));
1273 EXPECT_EQ(&items[0], &(*it++));
1274 EXPECT_EQ(list.end(), it);
1275 list.clear();
1276 }
1277
TEST(IntrusiveListTest,RemoveIf_MatchNone)1278 TEST(IntrusiveListTest, RemoveIf_MatchNone) {
1279 std::array<Item, 5> items{{{1}, {3}, {5}, {7}, {9}}};
1280 List list(items.begin(), items.end());
1281 auto equal_two = [](const Item& a) { return a.GetNumber() == 2; };
1282
1283 EXPECT_EQ(list.remove_if(equal_two), 0U);
1284
1285 auto it = list.begin();
1286 EXPECT_EQ(&items[0], &(*it++));
1287 EXPECT_EQ(&items[1], &(*it++));
1288 EXPECT_EQ(&items[2], &(*it++));
1289 EXPECT_EQ(&items[3], &(*it++));
1290 EXPECT_EQ(&items[4], &(*it++));
1291 EXPECT_EQ(list.end(), it);
1292 list.clear();
1293 }
1294
TEST(IntrusiveListTest,RemoveIf_MatchSome)1295 TEST(IntrusiveListTest, RemoveIf_MatchSome) {
1296 std::array<Item, 5> items{{{1}, {2}, {2}, {2}, {3}}};
1297 List list(items.begin(), items.end());
1298 auto equal_two = [](const Item& a) { return a.GetNumber() == 2; };
1299
1300 EXPECT_EQ(list.remove_if(equal_two), 3U);
1301
1302 auto it = list.begin();
1303 EXPECT_EQ(&items[0], &(*it++));
1304 EXPECT_EQ(&items[4], &(*it++));
1305 EXPECT_EQ(list.end(), it);
1306 list.clear();
1307 }
1308
TEST(IntrusiveListTest,RemoveIf_MatchAll)1309 TEST(IntrusiveListTest, RemoveIf_MatchAll) {
1310 std::array<Item, 5> items{{{2}, {2}, {2}, {2}, {2}}};
1311 List list(items.begin(), items.end());
1312 auto equal_two = [](const Item& a) { return a.GetNumber() == 2; };
1313
1314 EXPECT_EQ(list.remove_if(equal_two), 5U);
1315 EXPECT_TRUE(list.empty());
1316 }
1317
TEST(IntrusiveListTest,RemoveIf_Empty)1318 TEST(IntrusiveListTest, RemoveIf_Empty) {
1319 List list;
1320 auto equal_two = [](const Item& a) { return a.GetNumber() == 2; };
1321
1322 EXPECT_EQ(list.remove_if(equal_two), 0U);
1323 EXPECT_TRUE(list.empty());
1324 }
1325
TEST(IntrusiveListTest,Reverse)1326 TEST(IntrusiveListTest, Reverse) {
1327 std::array<Item, 5> items{{{0}, {1}, {2}, {3}, {4}}};
1328 List list(items.begin(), items.end());
1329
1330 list.reverse();
1331
1332 int i = 4;
1333 for (const Item& item : list) {
1334 EXPECT_EQ(item.GetNumber(), i--);
1335 }
1336 EXPECT_EQ(i, -1);
1337 list.clear();
1338 }
1339
TEST(IntrusiveListTest,Reverse_Empty)1340 TEST(IntrusiveListTest, Reverse_Empty) {
1341 List list;
1342 list.reverse();
1343 EXPECT_TRUE(list.empty());
1344 }
1345
TEST(IntrusiveListTest,Unique)1346 TEST(IntrusiveListTest, Unique) {
1347 std::array<Item, 10> items{
1348 {{0}, {0}, {0}, {1}, {2}, {2}, {3}, {3}, {3}, {3}}};
1349 List list(items.begin(), items.end());
1350
1351 EXPECT_EQ(list.unique(), 6U);
1352
1353 int i = 0;
1354 for (const Item& item : list) {
1355 EXPECT_EQ(item.GetNumber(), i++);
1356 }
1357 EXPECT_EQ(i, 4);
1358 list.clear();
1359 }
1360
TEST(IntrusiveListTest,Unique_Compare)1361 TEST(IntrusiveListTest, Unique_Compare) {
1362 std::array<Item, 10> items{
1363 {{0}, {2}, {1}, {3}, {1}, {0}, {1}, {0}, {2}, {4}}};
1364 List list(items.begin(), items.end());
1365 auto parity = [](const Item& a, const Item& b) {
1366 return (a.GetNumber() % 2) == (b.GetNumber() % 2);
1367 };
1368
1369 EXPECT_EQ(list.unique(parity), 5U);
1370
1371 int i = 0;
1372 for (const Item& item : list) {
1373 EXPECT_EQ(item.GetNumber(), i);
1374 i = (i + 1) % 2;
1375 }
1376 list.clear();
1377 }
1378
TEST(IntrusiveListTest,Unique_Empty)1379 TEST(IntrusiveListTest, Unique_Empty) {
1380 List list;
1381
1382 EXPECT_EQ(list.unique(), 0U);
1383
1384 EXPECT_TRUE(list.empty());
1385 }
1386
TEST(IntrusiveListTest,Unique_NoDuplicates)1387 TEST(IntrusiveListTest, Unique_NoDuplicates) {
1388 std::array<Item, 5> items{{{0}, {1}, {2}, {3}, {4}}};
1389 List list(items.begin(), items.end());
1390
1391 EXPECT_EQ(list.unique(), 0U);
1392
1393 int i = 0;
1394 for (const Item& item : list) {
1395 EXPECT_EQ(item.GetNumber(), i++);
1396 }
1397 EXPECT_EQ(i, 5);
1398 list.clear();
1399 }
1400
TEST(IntrusiveListTest,Sort)1401 TEST(IntrusiveListTest, Sort) {
1402 std::array<Item, 5> items{{{5}, {1}, {3}, {2}, {4}}};
1403 List list(items.begin(), items.end());
1404 list.sort();
1405
1406 int i = 1;
1407 for (const Item& item : list) {
1408 EXPECT_EQ(item.GetNumber(), i++);
1409 }
1410 EXPECT_EQ(i, 6);
1411 list.clear();
1412 }
1413
TEST(IntrusiveListTest,Sort_Compare)1414 TEST(IntrusiveListTest, Sort_Compare) {
1415 std::array<Item, 5> items{{{5}, {1}, {3}, {2}, {4}}};
1416 List list(items.begin(), items.end());
1417 auto greater_than = [](const Item& a, const Item& b) {
1418 return a.GetNumber() > b.GetNumber();
1419 };
1420 list.sort(greater_than);
1421
1422 int i = 5;
1423 for (const Item& item : list) {
1424 EXPECT_EQ(item.GetNumber(), i--);
1425 }
1426 EXPECT_EQ(i, 0);
1427 list.clear();
1428 }
1429
TEST(IntrusiveListTest,Sort_Empty)1430 TEST(IntrusiveListTest, Sort_Empty) {
1431 List list;
1432 list.sort();
1433 EXPECT_TRUE(list.empty());
1434 }
1435
TEST(IntrusiveListTest,Sort_Stable)1436 TEST(IntrusiveListTest, Sort_Stable) {
1437 std::array<Item, 5> items{{{0}, {1}, {1}, {1}, {2}}};
1438 List list(items.begin(), items.end());
1439 list.sort();
1440
1441 auto it = list.begin();
1442 EXPECT_EQ(&items[0], &(*it++));
1443 EXPECT_EQ(&items[1], &(*it++));
1444 EXPECT_EQ(&items[2], &(*it++));
1445 EXPECT_EQ(&items[3], &(*it++));
1446 EXPECT_EQ(&items[4], &(*it++));
1447 EXPECT_EQ(list.end(), it);
1448 list.clear();
1449 }
1450
1451 // Other type-related unit tests
1452
TEST(IntrusiveListTest,AddItemsOfDerivedClassToList)1453 TEST(IntrusiveListTest, AddItemsOfDerivedClassToList) {
1454 List list;
1455
1456 DerivedItem item1;
1457 list.push_front(item1);
1458
1459 Item item2;
1460 list.push_front(item2);
1461
1462 EXPECT_EQ(2u, list.size());
1463 list.clear();
1464 }
1465
TEST(IntrusiveListTest,ListOfDerivedClassItems)1466 TEST(IntrusiveListTest, ListOfDerivedClassItems) {
1467 IntrusiveList<DerivedItem> derived_from_compatible_item_type;
1468
1469 DerivedItem item1;
1470 derived_from_compatible_item_type.push_front(item1);
1471
1472 EXPECT_EQ(1u, derived_from_compatible_item_type.size());
1473
1474 #if PW_NC_TEST(CannotAddBaseClassToDerivedClassList)
1475 PW_NC_EXPECT_CLANG("cannot bind to a value of unrelated type");
1476 PW_NC_EXPECT_GCC("cannot convert");
1477
1478 Item item2;
1479 derived_from_compatible_item_type.push_front(item2);
1480 #endif
1481 derived_from_compatible_item_type.clear();
1482 }
1483
1484 #if PW_NC_TEST(IncompatibleItem)
1485 PW_NC_EXPECT("IntrusiveList items must be derived from IntrusiveList<T>::Item");
1486
1487 struct Foo {};
1488
1489 class BadItem : public IntrusiveList<Foo>::Item {};
1490
1491 [[maybe_unused]] IntrusiveList<BadItem> derived_from_incompatible_item_type;
1492
1493 #elif PW_NC_TEST(DoesNotInheritFromItem)
1494 PW_NC_EXPECT("IntrusiveList items must be derived from IntrusiveList<T>::Item");
1495
1496 struct NotAnItem {};
1497
1498 [[maybe_unused]] IntrusiveList<NotAnItem> list;
1499
1500 #endif // PW_NC_TEST
1501
TEST(IntrusiveListTest,MoveUnlistedItems)1502 TEST(IntrusiveListTest, MoveUnlistedItems) {
1503 Item item1(3);
1504 EXPECT_EQ(item1.GetNumber(), 3);
1505
1506 Item item2(std::move(item1));
1507 EXPECT_EQ(item2.GetNumber(), 3);
1508
1509 Item item3;
1510 item3 = std::move(item2);
1511 EXPECT_EQ(item3.GetNumber(), 3);
1512 }
1513
TEST(IntrusiveListTest,MoveItemsToVector)1514 TEST(IntrusiveListTest, MoveItemsToVector) {
1515 pw::Vector<Item, 3> vec;
1516 vec.emplace_back(Item(1));
1517 vec.emplace_back(Item(2));
1518 vec.emplace_back(Item(3));
1519 List list;
1520 list.assign(vec.begin(), vec.end());
1521
1522 auto iter = list.begin();
1523 for (const auto& item : vec) {
1524 EXPECT_NE(iter, list.end());
1525 if (iter == list.end()) {
1526 break;
1527 }
1528 EXPECT_EQ(item.GetNumber(), iter->GetNumber());
1529 ++iter;
1530 }
1531 list.clear();
1532
1533 // TODO(b/313899658): Vector has an MSAN bug in its destructor when clearing
1534 // items that reference themselves. Workaround it by manually clearing.
1535 vec.clear();
1536 }
1537
1538 } // namespace
1539