| /* Tests fpr intrusive double linked list for GDB, the GNU debugger. | 
 |    Copyright (C) 2021-2022 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "defs.h" | 
 |  | 
 | #include "gdbsupport/intrusive_list.h" | 
 | #include "gdbsupport/selftest.h" | 
 | #include <unordered_set> | 
 |  | 
 | /* An item type using intrusive_list_node by inheriting from it and its | 
 |    corresponding list type.  Put another base before intrusive_list_node | 
 |    so that a pointer to the node != a pointer to the item.  */ | 
 |  | 
 | struct other_base | 
 | { | 
 |   int n = 1; | 
 | }; | 
 |  | 
 | struct item_with_base : public other_base, | 
 | 			public intrusive_list_node<item_with_base> | 
 | { | 
 |   explicit item_with_base (const char *name) | 
 |     : name (name) | 
 |   {} | 
 |  | 
 |   const char *const name; | 
 | }; | 
 |  | 
 | using item_with_base_list = intrusive_list<item_with_base>; | 
 |  | 
 | /* An item type using intrusive_list_node as a field and its corresponding | 
 |    list type.  Put the other field before the node, so that a pointer to the | 
 |    node != a pointer to the item.  */ | 
 |  | 
 | struct item_with_member | 
 | { | 
 |   explicit item_with_member (const char *name) | 
 |     : name (name) | 
 |   {} | 
 |  | 
 |   const char *const name; | 
 |   intrusive_list_node<item_with_member> node; | 
 | }; | 
 |  | 
 | using item_with_member_node | 
 |   = intrusive_member_node<item_with_member, &item_with_member::node>; | 
 | using item_with_member_list | 
 |   = intrusive_list<item_with_member, item_with_member_node>; | 
 |  | 
 | /* To run all tests using both the base and member methods, all tests are | 
 |    declared in this templated class, which is instantiated once for each | 
 |    list type.  */ | 
 |  | 
 | template <typename ListType> | 
 | struct intrusive_list_test | 
 | { | 
 |   using item_type = typename ListType::value_type; | 
 |  | 
 |   /* Verify that LIST contains exactly the items in EXPECTED. | 
 |  | 
 |      Traverse the list forward and backwards to exercise all links.  */ | 
 |  | 
 |   static void | 
 |   verify_items (const ListType &list, | 
 | 		gdb::array_view<const typename ListType::value_type *> expected) | 
 |   { | 
 |     int i = 0; | 
 |  | 
 |     for (typename ListType::iterator it = list.begin (); | 
 | 	 it != list.end (); | 
 | 	 ++it) | 
 |       { | 
 | 	const item_type &item = *it; | 
 |  | 
 | 	gdb_assert (i < expected.size ()); | 
 | 	gdb_assert (&item == expected[i]); | 
 |  | 
 | 	++i; | 
 |       } | 
 |  | 
 |     gdb_assert (i == expected.size ()); | 
 |  | 
 |     for (typename ListType::reverse_iterator it = list.rbegin (); | 
 | 	 it != list.rend (); | 
 | 	 ++it) | 
 |       { | 
 | 	const item_type &item = *it; | 
 |  | 
 | 	--i; | 
 |  | 
 | 	gdb_assert (i >= 0); | 
 | 	gdb_assert (&item == expected[i]); | 
 |       } | 
 |  | 
 |     gdb_assert (i == 0); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_move_constructor () | 
 |   { | 
 |     { | 
 |       /* Other list is not empty.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list1; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |       list1.push_back (b); | 
 |       list1.push_back (c); | 
 |  | 
 |       ListType list2 (std::move (list1)); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {&a, &b, &c}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Other list contains 1 element.  */ | 
 |       item_type a ("a"); | 
 |       ListType list1; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |  | 
 |       ListType list2 (std::move (list1)); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {&a}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Other list is empty.  */ | 
 |       ListType list1; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       ListType list2 (std::move (list1)); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |   } | 
 |  | 
 |   static void | 
 |   test_move_assignment () | 
 |   { | 
 |     { | 
 |       /* Both lists are not empty.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"), d ("d"), e ("e"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |       list1.push_back (b); | 
 |       list1.push_back (c); | 
 |  | 
 |       list2.push_back (d); | 
 |       list2.push_back (e); | 
 |  | 
 |       list2 = std::move (list1); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {&a, &b, &c}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* rhs list is empty.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list2.push_back (a); | 
 |       list2.push_back (b); | 
 |       list2.push_back (c); | 
 |  | 
 |       list2 = std::move (list1); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* lhs list is empty.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |       list1.push_back (b); | 
 |       list1.push_back (c); | 
 |  | 
 |       list2 = std::move (list1); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {&a, &b, &c}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Both lists contain 1 item.  */ | 
 |       item_type a ("a"), b ("b"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |       list2.push_back (b); | 
 |  | 
 |       list2 = std::move (list1); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {&a}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Both lists are empty.  */ | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list2 = std::move (list1); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |   } | 
 |  | 
 |   static void | 
 |   test_swap () | 
 |   { | 
 |     { | 
 |       /* Two non-empty lists.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"), d ("d"), e ("e"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |       list1.push_back (b); | 
 |       list1.push_back (c); | 
 |  | 
 |       list2.push_back (d); | 
 |       list2.push_back (e); | 
 |  | 
 |       std::swap (list1, list2); | 
 |  | 
 |       expected = {&d, &e}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {&a, &b, &c}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Other is empty.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |       list1.push_back (b); | 
 |       list1.push_back (c); | 
 |  | 
 |       std::swap (list1, list2); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {&a, &b, &c}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* *this is empty.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list2.push_back (a); | 
 |       list2.push_back (b); | 
 |       list2.push_back (c); | 
 |  | 
 |       std::swap (list1, list2); | 
 |  | 
 |       expected = {&a, &b, &c}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Both lists empty.  */ | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       std::swap (list1, list2); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Swap one element twice.  */ | 
 |       item_type a ("a"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |  | 
 |       std::swap (list1, list2); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {&a}; | 
 |       verify_items (list2, expected); | 
 |  | 
 |       std::swap (list1, list2); | 
 |  | 
 |       expected = {&a}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |   } | 
 |  | 
 |   static void | 
 |   test_front_back () | 
 |   { | 
 |     item_type a ("a"), b ("b"), c ("c"); | 
 |     ListType list; | 
 |     const ListType &clist = list; | 
 |  | 
 |     list.push_back (a); | 
 |     list.push_back (b); | 
 |     list.push_back (c); | 
 |  | 
 |     gdb_assert (&list.front () == &a); | 
 |     gdb_assert (&clist.front () == &a); | 
 |     gdb_assert (&list.back () == &c); | 
 |     gdb_assert (&clist.back () == &c); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_push_front () | 
 |   { | 
 |     item_type a ("a"), b ("b"), c ("c"); | 
 |     ListType list; | 
 |     std::vector<const item_type *> expected; | 
 |  | 
 |     expected = {}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.push_front (a); | 
 |     expected = {&a}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.push_front (b); | 
 |     expected = {&b, &a}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.push_front (c); | 
 |     expected = {&c, &b, &a}; | 
 |     verify_items (list, expected); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_push_back () | 
 |   { | 
 |     item_type a ("a"), b ("b"), c ("c"); | 
 |     ListType list; | 
 |     std::vector<const item_type *> expected; | 
 |  | 
 |     expected = {}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.push_back (a); | 
 |     expected = {&a}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.push_back (b); | 
 |     expected = {&a, &b}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.push_back (c); | 
 |     expected = {&a, &b, &c}; | 
 |     verify_items (list, expected); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_insert () | 
 |   { | 
 |     std::vector<const item_type *> expected; | 
 |  | 
 |     { | 
 |       /* Insert at beginning.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list; | 
 |  | 
 |  | 
 |       list.insert (list.begin (), a); | 
 |       expected = {&a}; | 
 |       verify_items (list, expected); | 
 |  | 
 |       list.insert (list.begin (), b); | 
 |       expected = {&b, &a}; | 
 |       verify_items (list, expected); | 
 |  | 
 |       list.insert (list.begin (), c); | 
 |       expected = {&c, &b, &a}; | 
 |       verify_items (list, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Insert at end.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list; | 
 |  | 
 |  | 
 |       list.insert (list.end (), a); | 
 |       expected = {&a}; | 
 |       verify_items (list, expected); | 
 |  | 
 |       list.insert (list.end (), b); | 
 |       expected = {&a, &b}; | 
 |       verify_items (list, expected); | 
 |  | 
 |       list.insert (list.end (), c); | 
 |       expected = {&a, &b, &c}; | 
 |       verify_items (list, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Insert in the middle.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list; | 
 |  | 
 |       list.push_back (a); | 
 |       list.push_back (b); | 
 |  | 
 |       list.insert (list.iterator_to (b), c); | 
 |       expected = {&a, &c, &b}; | 
 |       verify_items (list, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Insert in empty list. */ | 
 |       item_type a ("a"); | 
 |       ListType list; | 
 |  | 
 |       list.insert (list.end (), a); | 
 |       expected = {&a}; | 
 |       verify_items (list, expected); | 
 |     } | 
 |   } | 
 |  | 
 |   static void | 
 |   test_splice () | 
 |   { | 
 |     { | 
 |       /* Two non-empty lists.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"), d ("d"), e ("e"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |       list1.push_back (b); | 
 |       list1.push_back (c); | 
 |  | 
 |       list2.push_back (d); | 
 |       list2.push_back (e); | 
 |  | 
 |       list1.splice (std::move (list2)); | 
 |  | 
 |       expected = {&a, &b, &c, &d, &e}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Receiving list empty.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list2.push_back (a); | 
 |       list2.push_back (b); | 
 |       list2.push_back (c); | 
 |  | 
 |       list1.splice (std::move (list2)); | 
 |  | 
 |       expected = {&a, &b, &c}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Giving list empty.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.push_back (a); | 
 |       list1.push_back (b); | 
 |       list1.push_back (c); | 
 |  | 
 |       list1.splice (std::move (list2)); | 
 |  | 
 |       expected = {&a, &b, &c}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |  | 
 |     { | 
 |       /* Both lists empty.  */ | 
 |       item_type a ("a"), b ("b"), c ("c"); | 
 |       ListType list1; | 
 |       ListType list2; | 
 |       std::vector<const item_type *> expected; | 
 |  | 
 |       list1.splice (std::move (list2)); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list1, expected); | 
 |  | 
 |       expected = {}; | 
 |       verify_items (list2, expected); | 
 |     } | 
 |   } | 
 |  | 
 |   static void | 
 |   test_pop_front () | 
 |   { | 
 |     item_type a ("a"), b ("b"), c ("c"); | 
 |     ListType list; | 
 |     std::vector<const item_type *> expected; | 
 |  | 
 |     list.push_back (a); | 
 |     list.push_back (b); | 
 |     list.push_back (c); | 
 |  | 
 |     list.pop_front (); | 
 |     expected = {&b, &c}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.pop_front (); | 
 |     expected = {&c}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.pop_front (); | 
 |     expected = {}; | 
 |     verify_items (list, expected); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_pop_back () | 
 |   { | 
 |     item_type a ("a"), b ("b"), c ("c"); | 
 |     ListType list; | 
 |     std::vector<const item_type *> expected; | 
 |  | 
 |     list.push_back (a); | 
 |     list.push_back (b); | 
 |     list.push_back (c); | 
 |  | 
 |     list.pop_back(); | 
 |     expected = {&a, &b}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.pop_back (); | 
 |     expected = {&a}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.pop_back (); | 
 |     expected = {}; | 
 |     verify_items (list, expected); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_erase () | 
 |   { | 
 |     item_type a ("a"), b ("b"), c ("c"); | 
 |     ListType list; | 
 |     std::vector<const item_type *> expected; | 
 |  | 
 |     list.push_back (a); | 
 |     list.push_back (b); | 
 |     list.push_back (c); | 
 |  | 
 |     list.erase (list.iterator_to (b)); | 
 |     expected = {&a, &c}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.erase (list.iterator_to (c)); | 
 |     expected = {&a}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     list.erase (list.iterator_to (a)); | 
 |     expected = {}; | 
 |     verify_items (list, expected); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_clear () | 
 |   { | 
 |     item_type a ("a"), b ("b"), c ("c"); | 
 |     ListType list; | 
 |     std::vector<const item_type *> expected; | 
 |  | 
 |     list.push_back (a); | 
 |     list.push_back (b); | 
 |     list.push_back (c); | 
 |  | 
 |     list.clear (); | 
 |     expected = {}; | 
 |     verify_items (list, expected); | 
 |  | 
 |     /* Verify idempotency.  */ | 
 |     list.clear (); | 
 |     expected = {}; | 
 |     verify_items (list, expected); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_clear_and_dispose () | 
 |   { | 
 |     item_type a ("a"), b ("b"), c ("c"); | 
 |     ListType list; | 
 |     std::vector<const item_type *> expected; | 
 |     std::unordered_set<const item_type *> disposer_seen; | 
 |     int disposer_calls = 0; | 
 |  | 
 |     list.push_back (a); | 
 |     list.push_back (b); | 
 |     list.push_back (c); | 
 |  | 
 |     auto disposer = [&] (const item_type *item) | 
 |       { | 
 | 	disposer_seen.insert (item); | 
 | 	disposer_calls++; | 
 |       }; | 
 |     list.clear_and_dispose (disposer); | 
 |  | 
 |     expected = {}; | 
 |     verify_items (list, expected); | 
 |     gdb_assert (disposer_calls == 3); | 
 |     gdb_assert (disposer_seen.find (&a) != disposer_seen.end ()); | 
 |     gdb_assert (disposer_seen.find (&b) != disposer_seen.end ()); | 
 |     gdb_assert (disposer_seen.find (&c) != disposer_seen.end ()); | 
 |  | 
 |     /* Verify idempotency.  */ | 
 |     list.clear_and_dispose (disposer); | 
 |     gdb_assert (disposer_calls == 3); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_empty () | 
 |   { | 
 |     item_type a ("a"); | 
 |     ListType list; | 
 |  | 
 |     gdb_assert (list.empty ()); | 
 |     list.push_back (a); | 
 |     gdb_assert (!list.empty ()); | 
 |     list.erase (list.iterator_to (a)); | 
 |     gdb_assert (list.empty ()); | 
 |   } | 
 |  | 
 |   static void | 
 |   test_begin_end () | 
 |   { | 
 |     item_type a ("a"), b ("b"), c ("c"); | 
 |     ListType list; | 
 |     const ListType &clist = list; | 
 |  | 
 |     list.push_back (a); | 
 |     list.push_back (b); | 
 |     list.push_back (c); | 
 |  | 
 |     gdb_assert (&*list.begin () == &a); | 
 |     gdb_assert (&*list.cbegin () == &a); | 
 |     gdb_assert (&*clist.begin () == &a); | 
 |     gdb_assert (&*list.rbegin () == &c); | 
 |     gdb_assert (&*list.crbegin () == &c); | 
 |     gdb_assert (&*clist.rbegin () == &c); | 
 |  | 
 |     /* At least check that they compile.  */ | 
 |     list.end (); | 
 |     list.cend (); | 
 |     clist.end (); | 
 |     list.rend (); | 
 |     list.crend (); | 
 |     clist.end (); | 
 |   } | 
 | }; | 
 |  | 
 | template <typename ListType> | 
 | static void | 
 | test_intrusive_list_1 () | 
 | { | 
 |   intrusive_list_test<ListType> tests; | 
 |  | 
 |   tests.test_move_constructor (); | 
 |   tests.test_move_assignment (); | 
 |   tests.test_swap (); | 
 |   tests.test_front_back (); | 
 |   tests.test_push_front (); | 
 |   tests.test_push_back (); | 
 |   tests.test_insert (); | 
 |   tests.test_splice (); | 
 |   tests.test_pop_front (); | 
 |   tests.test_pop_back (); | 
 |   tests.test_erase (); | 
 |   tests.test_clear (); | 
 |   tests.test_clear_and_dispose (); | 
 |   tests.test_empty (); | 
 |   tests.test_begin_end (); | 
 | } | 
 |  | 
 | static void | 
 | test_node_is_linked () | 
 | { | 
 |   { | 
 |     item_with_base a ("a"); | 
 |     item_with_base_list list; | 
 |  | 
 |     gdb_assert (!a.is_linked ()); | 
 |     list.push_back (a); | 
 |     gdb_assert (a.is_linked ()); | 
 |     list.pop_back (); | 
 |     gdb_assert (!a.is_linked ()); | 
 |   } | 
 |  | 
 |   { | 
 |     item_with_member a ("a"); | 
 |     item_with_member_list list; | 
 |  | 
 |     gdb_assert (!a.node.is_linked ()); | 
 |     list.push_back (a); | 
 |     gdb_assert (a.node.is_linked ()); | 
 |     list.pop_back (); | 
 |     gdb_assert (!a.node.is_linked ()); | 
 |   } | 
 | } | 
 |  | 
 | static void | 
 | test_intrusive_list () | 
 | { | 
 |   test_intrusive_list_1<item_with_base_list> (); | 
 |   test_intrusive_list_1<item_with_member_list> (); | 
 |   test_node_is_linked (); | 
 | } | 
 |  | 
 | void _initialize_intrusive_list_selftests (); | 
 | void | 
 | _initialize_intrusive_list_selftests () | 
 | { | 
 |   selftests::register_test | 
 |     ("intrusive_list", test_intrusive_list); | 
 | } |