1 /* Tests fpr intrusive double linked list for GDB, the GNU debugger.
2 Copyright (C) 2021-2023 Free Software Foundation, Inc.
4 This file is part of GDB.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "gdbsupport/intrusive_list.h"
22 #include "gdbsupport/selftest.h"
23 #include <unordered_set>
25 /* An item type using intrusive_list_node by inheriting from it and its
26 corresponding list type. Put another base before intrusive_list_node
27 so that a pointer to the node != a pointer to the item. */
34 struct item_with_base
: public other_base
,
35 public intrusive_list_node
<item_with_base
>
37 explicit item_with_base (const char *name
)
41 const char *const name
;
44 using item_with_base_list
= intrusive_list
<item_with_base
>;
46 /* An item type using intrusive_list_node as a field and its corresponding
47 list type. Put the other field before the node, so that a pointer to the
48 node != a pointer to the item. */
50 struct item_with_member
52 explicit item_with_member (const char *name
)
56 const char *const name
;
57 intrusive_list_node
<item_with_member
> node
;
60 using item_with_member_node
61 = intrusive_member_node
<item_with_member
, &item_with_member::node
>;
62 using item_with_member_list
63 = intrusive_list
<item_with_member
, item_with_member_node
>;
65 /* To run all tests using both the base and member methods, all tests are
66 declared in this templated class, which is instantiated once for each
69 template <typename ListType
>
70 struct intrusive_list_test
72 using item_type
= typename
ListType::value_type
;
74 /* Verify that LIST contains exactly the items in EXPECTED.
76 Traverse the list forward and backwards to exercise all links. */
79 verify_items (const ListType
&list
,
80 gdb::array_view
<const typename
ListType::value_type
*> expected
)
84 for (typename
ListType::iterator it
= list
.begin ();
88 const item_type
&item
= *it
;
90 gdb_assert (i
< expected
.size ());
91 gdb_assert (&item
== expected
[i
]);
96 gdb_assert (i
== expected
.size ());
98 for (typename
ListType::reverse_iterator it
= list
.rbegin ();
102 const item_type
&item
= *it
;
107 gdb_assert (&item
== expected
[i
]);
114 test_move_constructor ()
117 /* Other list is not empty. */
118 item_type
a ("a"), b ("b"), c ("c");
120 std::vector
<const item_type
*> expected
;
126 ListType
list2 (std::move (list1
));
129 verify_items (list1
, expected
);
131 expected
= {&a
, &b
, &c
};
132 verify_items (list2
, expected
);
136 /* Other list contains 1 element. */
139 std::vector
<const item_type
*> expected
;
143 ListType
list2 (std::move (list1
));
146 verify_items (list1
, expected
);
149 verify_items (list2
, expected
);
153 /* Other list is empty. */
155 std::vector
<const item_type
*> expected
;
157 ListType
list2 (std::move (list1
));
160 verify_items (list1
, expected
);
163 verify_items (list2
, expected
);
168 test_move_assignment ()
171 /* Both lists are not empty. */
172 item_type
a ("a"), b ("b"), c ("c"), d ("d"), e ("e");
175 std::vector
<const item_type
*> expected
;
184 list2
= std::move (list1
);
187 verify_items (list1
, expected
);
189 expected
= {&a
, &b
, &c
};
190 verify_items (list2
, expected
);
194 /* rhs list is empty. */
195 item_type
a ("a"), b ("b"), c ("c");
198 std::vector
<const item_type
*> expected
;
204 list2
= std::move (list1
);
207 verify_items (list1
, expected
);
210 verify_items (list2
, expected
);
214 /* lhs list is empty. */
215 item_type
a ("a"), b ("b"), c ("c");
218 std::vector
<const item_type
*> expected
;
224 list2
= std::move (list1
);
227 verify_items (list1
, expected
);
229 expected
= {&a
, &b
, &c
};
230 verify_items (list2
, expected
);
234 /* Both lists contain 1 item. */
235 item_type
a ("a"), b ("b");
238 std::vector
<const item_type
*> expected
;
243 list2
= std::move (list1
);
246 verify_items (list1
, expected
);
249 verify_items (list2
, expected
);
253 /* Both lists are empty. */
256 std::vector
<const item_type
*> expected
;
258 list2
= std::move (list1
);
261 verify_items (list1
, expected
);
264 verify_items (list2
, expected
);
272 /* Two non-empty lists. */
273 item_type
a ("a"), b ("b"), c ("c"), d ("d"), e ("e");
276 std::vector
<const item_type
*> expected
;
285 std::swap (list1
, list2
);
288 verify_items (list1
, expected
);
290 expected
= {&a
, &b
, &c
};
291 verify_items (list2
, expected
);
295 /* Other is empty. */
296 item_type
a ("a"), b ("b"), c ("c");
299 std::vector
<const item_type
*> expected
;
305 std::swap (list1
, list2
);
308 verify_items (list1
, expected
);
310 expected
= {&a
, &b
, &c
};
311 verify_items (list2
, expected
);
315 /* *this is empty. */
316 item_type
a ("a"), b ("b"), c ("c");
319 std::vector
<const item_type
*> expected
;
325 std::swap (list1
, list2
);
327 expected
= {&a
, &b
, &c
};
328 verify_items (list1
, expected
);
331 verify_items (list2
, expected
);
335 /* Both lists empty. */
338 std::vector
<const item_type
*> expected
;
340 std::swap (list1
, list2
);
343 verify_items (list1
, expected
);
346 verify_items (list2
, expected
);
350 /* Swap one element twice. */
354 std::vector
<const item_type
*> expected
;
358 std::swap (list1
, list2
);
361 verify_items (list1
, expected
);
364 verify_items (list2
, expected
);
366 std::swap (list1
, list2
);
369 verify_items (list1
, expected
);
372 verify_items (list2
, expected
);
379 item_type
a ("a"), b ("b"), c ("c");
381 const ListType
&clist
= list
;
387 gdb_assert (&list
.front () == &a
);
388 gdb_assert (&clist
.front () == &a
);
389 gdb_assert (&list
.back () == &c
);
390 gdb_assert (&clist
.back () == &c
);
396 item_type
a ("a"), b ("b"), c ("c");
398 std::vector
<const item_type
*> expected
;
401 verify_items (list
, expected
);
405 verify_items (list
, expected
);
409 verify_items (list
, expected
);
412 expected
= {&c
, &b
, &a
};
413 verify_items (list
, expected
);
419 item_type
a ("a"), b ("b"), c ("c");
421 std::vector
<const item_type
*> expected
;
424 verify_items (list
, expected
);
428 verify_items (list
, expected
);
432 verify_items (list
, expected
);
435 expected
= {&a
, &b
, &c
};
436 verify_items (list
, expected
);
442 std::vector
<const item_type
*> expected
;
445 /* Insert at beginning. */
446 item_type
a ("a"), b ("b"), c ("c");
450 list
.insert (list
.begin (), a
);
452 verify_items (list
, expected
);
454 list
.insert (list
.begin (), b
);
456 verify_items (list
, expected
);
458 list
.insert (list
.begin (), c
);
459 expected
= {&c
, &b
, &a
};
460 verify_items (list
, expected
);
465 item_type
a ("a"), b ("b"), c ("c");
469 list
.insert (list
.end (), a
);
471 verify_items (list
, expected
);
473 list
.insert (list
.end (), b
);
475 verify_items (list
, expected
);
477 list
.insert (list
.end (), c
);
478 expected
= {&a
, &b
, &c
};
479 verify_items (list
, expected
);
483 /* Insert in the middle. */
484 item_type
a ("a"), b ("b"), c ("c");
490 list
.insert (list
.iterator_to (b
), c
);
491 expected
= {&a
, &c
, &b
};
492 verify_items (list
, expected
);
496 /* Insert in empty list. */
500 list
.insert (list
.end (), a
);
502 verify_items (list
, expected
);
510 /* Two non-empty lists. */
511 item_type
a ("a"), b ("b"), c ("c"), d ("d"), e ("e");
514 std::vector
<const item_type
*> expected
;
523 list1
.splice (std::move (list2
));
525 expected
= {&a
, &b
, &c
, &d
, &e
};
526 verify_items (list1
, expected
);
529 verify_items (list2
, expected
);
533 /* Receiving list empty. */
534 item_type
a ("a"), b ("b"), c ("c");
537 std::vector
<const item_type
*> expected
;
543 list1
.splice (std::move (list2
));
545 expected
= {&a
, &b
, &c
};
546 verify_items (list1
, expected
);
549 verify_items (list2
, expected
);
553 /* Giving list empty. */
554 item_type
a ("a"), b ("b"), c ("c");
557 std::vector
<const item_type
*> expected
;
563 list1
.splice (std::move (list2
));
565 expected
= {&a
, &b
, &c
};
566 verify_items (list1
, expected
);
569 verify_items (list2
, expected
);
573 /* Both lists empty. */
574 item_type
a ("a"), b ("b"), c ("c");
577 std::vector
<const item_type
*> expected
;
579 list1
.splice (std::move (list2
));
582 verify_items (list1
, expected
);
585 verify_items (list2
, expected
);
592 item_type
a ("a"), b ("b"), c ("c");
594 std::vector
<const item_type
*> expected
;
602 verify_items (list
, expected
);
606 verify_items (list
, expected
);
610 verify_items (list
, expected
);
616 item_type
a ("a"), b ("b"), c ("c");
618 std::vector
<const item_type
*> expected
;
626 verify_items (list
, expected
);
630 verify_items (list
, expected
);
634 verify_items (list
, expected
);
640 item_type
a ("a"), b ("b"), c ("c");
642 std::vector
<const item_type
*> expected
;
648 list
.erase (list
.iterator_to (b
));
650 verify_items (list
, expected
);
652 list
.erase (list
.iterator_to (c
));
654 verify_items (list
, expected
);
656 list
.erase (list
.iterator_to (a
));
658 verify_items (list
, expected
);
664 item_type
a ("a"), b ("b"), c ("c");
666 std::vector
<const item_type
*> expected
;
674 verify_items (list
, expected
);
676 /* Verify idempotency. */
679 verify_items (list
, expected
);
683 test_clear_and_dispose ()
685 item_type
a ("a"), b ("b"), c ("c");
687 std::vector
<const item_type
*> expected
;
688 std::unordered_set
<const item_type
*> disposer_seen
;
689 int disposer_calls
= 0;
695 auto disposer
= [&] (const item_type
*item
)
697 disposer_seen
.insert (item
);
700 list
.clear_and_dispose (disposer
);
703 verify_items (list
, expected
);
704 gdb_assert (disposer_calls
== 3);
705 gdb_assert (disposer_seen
.find (&a
) != disposer_seen
.end ());
706 gdb_assert (disposer_seen
.find (&b
) != disposer_seen
.end ());
707 gdb_assert (disposer_seen
.find (&c
) != disposer_seen
.end ());
709 /* Verify idempotency. */
710 list
.clear_and_dispose (disposer
);
711 gdb_assert (disposer_calls
== 3);
720 gdb_assert (list
.empty ());
722 gdb_assert (!list
.empty ());
723 list
.erase (list
.iterator_to (a
));
724 gdb_assert (list
.empty ());
730 item_type
a ("a"), b ("b"), c ("c");
732 const ListType
&clist
= list
;
738 gdb_assert (&*list
.begin () == &a
);
739 gdb_assert (&*list
.cbegin () == &a
);
740 gdb_assert (&*clist
.begin () == &a
);
741 gdb_assert (&*list
.rbegin () == &c
);
742 gdb_assert (&*list
.crbegin () == &c
);
743 gdb_assert (&*clist
.rbegin () == &c
);
745 /* At least check that they compile. */
755 template <typename ListType
>
757 test_intrusive_list_1 ()
759 intrusive_list_test
<ListType
> tests
;
761 tests
.test_move_constructor ();
762 tests
.test_move_assignment ();
764 tests
.test_front_back ();
765 tests
.test_push_front ();
766 tests
.test_push_back ();
767 tests
.test_insert ();
768 tests
.test_splice ();
769 tests
.test_pop_front ();
770 tests
.test_pop_back ();
773 tests
.test_clear_and_dispose ();
775 tests
.test_begin_end ();
779 test_node_is_linked ()
782 item_with_base
a ("a");
783 item_with_base_list list
;
785 gdb_assert (!a
.is_linked ());
787 gdb_assert (a
.is_linked ());
789 gdb_assert (!a
.is_linked ());
793 item_with_member
a ("a");
794 item_with_member_list list
;
796 gdb_assert (!a
.node
.is_linked ());
798 gdb_assert (a
.node
.is_linked ());
800 gdb_assert (!a
.node
.is_linked ());
805 test_intrusive_list ()
807 test_intrusive_list_1
<item_with_base_list
> ();
808 test_intrusive_list_1
<item_with_member_list
> ();
809 test_node_is_linked ();
812 void _initialize_intrusive_list_selftests ();
814 _initialize_intrusive_list_selftests ()
816 selftests::register_test
817 ("intrusive_list", test_intrusive_list
);