util/IntrusiveList: add method splice()

This commit is contained in:
Max Kellermann 2022-11-10 15:57:12 +01:00
parent b78d6c9dd7
commit 84fd401d21
2 changed files with 91 additions and 1 deletions

View File

@ -526,4 +526,40 @@ public:
++counter;
}
/**
* Move the given range of items of the given list to this one
* before the given position.
*/
void splice(iterator position, IntrusiveList &from,
iterator _begin, iterator _end, size_type n) noexcept {
if (_begin == _end)
return;
auto &next_node = ToNode(*position);
auto &prev_node = ToNode(*std::prev(position));
auto &first_node = ToNode(*_begin);
auto &before_first_node = ToNode(*std::prev(_begin));
auto &last_node = ToNode(*std::prev(_end));
auto &after_last_node = ToNode(*_end);
/* remove from the other list */
IntrusiveListNode::Connect(before_first_node, after_last_node);
from.counter -= n;
/* insert into this list */
IntrusiveListNode::Connect(prev_node, first_node);
IntrusiveListNode::Connect(last_node, next_node);
counter += n;
}
/**
* Move all items of the given list to this one before the
* given position.
*/
void splice(iterator position, IntrusiveList &from) noexcept {
spice(position, from, from.begin(), from.end(),
constant_time_size ? size() : 1);
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 Max Kellermann <max.kellermann@gmail.com>
* Copyright 2020-2022 Max Kellermann <max.kellermann@gmail.com>
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.com>
@ -89,6 +89,60 @@ TEST(IntrusiveList, Basic)
ASSERT_EQ(i, list.begin());
--i;
ASSERT_EQ(i, list.end());
IntrusiveList<Item> other_list;
Item d, e, f, g;
other_list.push_back(d);
other_list.push_back(e);
other_list.push_back(f);
other_list.push_back(g);
list.splice(std::next(list.begin()), other_list,
other_list.iterator_to(e),
other_list.iterator_to(g), 2);
i = other_list.begin();
ASSERT_EQ(&*i, &d);
++i;
ASSERT_EQ(&*i, &g);
++i;
ASSERT_EQ(i, other_list.end());
++i;
ASSERT_EQ(&*i, &d);
--i;
ASSERT_EQ(i, other_list.end());
--i;
ASSERT_EQ(&*i, &g);
--i;
ASSERT_EQ(&*i, &d);
ASSERT_EQ(i, other_list.begin());
i = list.begin();
ASSERT_EQ(&*i, &a);
++i;
ASSERT_EQ(&*i, &e);
++i;
ASSERT_EQ(&*i, &f);
++i;
ASSERT_EQ(&*i, &c);
++i;
ASSERT_EQ(i, list.end());
++i;
ASSERT_EQ(&*i, &a);
--i;
ASSERT_EQ(i, list.end());
--i;
ASSERT_EQ(&*i, &c);
--i;
ASSERT_EQ(&*i, &f);
--i;
ASSERT_EQ(&*i, &e);
--i;
ASSERT_EQ(&*i, &a);
ASSERT_EQ(i, list.begin());
--i;
ASSERT_EQ(i, list.end());
}
TEST(IntrusiveList, SafeLink)