mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-15 04:31:49 +08:00
4a94e36819
This commit brings all the changes made by running gdb/copyright.py as per GDB's Start of New Year Procedure. For the avoidance of doubt, all changes in this commits were performed by the script.
819 lines
17 KiB
C
819 lines
17 KiB
C
/* 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);
|
|
}
|