diff --git a/AK/IntrusiveList.h b/AK/IntrusiveList.h index dcc6b0948bf..d2346d4f1b5 100644 --- a/AK/IntrusiveList.h +++ b/AK/IntrusiveList.h @@ -54,6 +54,7 @@ public: [[nodiscard]] size_t size_slow() const; void append(T& n); void prepend(T& n); + void insert_before(T&, T&); void remove(T& n); [[nodiscard]] bool contains(const T&) const; [[nodiscard]] Container first() const; @@ -264,6 +265,28 @@ inline void IntrusiveList::prepend(T& n) m_storage.m_last = &nnode; } +template T::*member> +inline void IntrusiveList::insert_before(T& bn, T& n) +{ + remove(n); + + auto& new_node = n.*member; + auto& before_node = bn.*member; + new_node.m_storage = &m_storage; + new_node.m_next = &before_node; + new_node.m_prev = before_node.m_prev; + if (before_node.m_prev) + before_node.m_prev->m_next = &new_node; + before_node.m_prev = &new_node; + + if (m_storage.m_first == &before_node) { + m_storage.m_first = &new_node; + } + + if constexpr (!RemoveReference::IsRaw) + new_node.m_self.reference = &n; +} + template T::*member> inline void IntrusiveList::remove(T& n) { diff --git a/Tests/AK/TestIntrusiveList.cpp b/Tests/AK/TestIntrusiveList.cpp index 84f1d9f2c20..923de96f3e0 100644 --- a/Tests/AK/TestIntrusiveList.cpp +++ b/Tests/AK/TestIntrusiveList.cpp @@ -33,6 +33,32 @@ TEST_CASE(insert) delete list.take_last(); } +TEST_CASE(insert_before) +{ + IntrusiveTestList list; + auto two = new IntrusiveTestItem(); + list.append(*two); + auto zero = new IntrusiveTestItem(); + list.append(*zero); + auto one = new IntrusiveTestItem(); + list.insert_before(*zero, *one); + + EXPECT_EQ(list.first(), two); + EXPECT_EQ(list.last(), zero); + EXPECT(list.contains(*zero)); + EXPECT(list.contains(*one)); + EXPECT(list.contains(*two)); + + EXPECT(zero->m_list_node.is_in_list()); + EXPECT(one->m_list_node.is_in_list()); + EXPECT(two->m_list_node.is_in_list()); + EXPECT_EQ(list.size_slow(), 3u); + + while (auto elem = list.take_first()) { + delete elem; + } +} + TEST_CASE(enumeration) { constexpr size_t expected_size = 10;