From 84fd401d2142513779e1625c55258b86b5541c21 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 10 Nov 2022 15:57:12 +0100 Subject: [PATCH] util/IntrusiveList: add method splice() --- src/util/IntrusiveList.hxx | 36 +++++++++++++++++++++ test/util/TestIntrusiveList.cxx | 56 ++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/util/IntrusiveList.hxx b/src/util/IntrusiveList.hxx index 3910dab09..3f969d4fe 100644 --- a/src/util/IntrusiveList.hxx +++ b/src/util/IntrusiveList.hxx @@ -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); + } }; diff --git a/test/util/TestIntrusiveList.cxx b/test/util/TestIntrusiveList.cxx index 0adc765a3..1d97df0ce 100644 --- a/test/util/TestIntrusiveList.cxx +++ b/test/util/TestIntrusiveList.cxx @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 Max Kellermann + * Copyright 2020-2022 Max Kellermann * All rights reserved. * * author: Max Kellermann @@ -89,6 +89,60 @@ TEST(IntrusiveList, Basic) ASSERT_EQ(i, list.begin()); --i; ASSERT_EQ(i, list.end()); + + IntrusiveList 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)