Serenity Operating System
at master 193 lines 5.1 kB view raw
1/* 2 * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibTest/TestCase.h> 8 9#include <AK/IntrusiveRedBlackTree.h> 10#include <AK/NonnullOwnPtr.h> 11#include <AK/Random.h> 12#include <AK/Vector.h> 13 14class IntrusiveTest { 15public: 16 IntrusiveTest(int value) 17 : m_some_value(value) 18 { 19 } 20 21 IntrusiveRedBlackTreeNode<int, IntrusiveTest, RawPtr<IntrusiveTest>> m_tree_node; 22 int m_some_value; 23}; 24using IntrusiveRBTree = IntrusiveRedBlackTree<&IntrusiveTest::m_tree_node>; 25 26TEST_CASE(construct) 27{ 28 IntrusiveRBTree empty; 29 EXPECT(empty.is_empty()); 30 EXPECT(empty.size() == 0); 31} 32 33TEST_CASE(ints) 34{ 35 IntrusiveRBTree test; 36 IntrusiveTest first { 10 }; 37 test.insert(1, first); 38 IntrusiveTest second { 20 }; 39 test.insert(3, second); 40 IntrusiveTest third { 30 }; 41 test.insert(2, third); 42 EXPECT_EQ(test.size(), 3u); 43 EXPECT_EQ(test.find(3)->m_some_value, 20); 44 EXPECT_EQ(test.find(2)->m_some_value, 30); 45 EXPECT_EQ(test.find(1)->m_some_value, 10); 46 EXPECT(!test.remove(4)); 47 EXPECT(test.remove(2)); 48 EXPECT(test.remove(1)); 49 EXPECT(test.remove(3)); 50 EXPECT_EQ(test.size(), 0u); 51} 52 53TEST_CASE(largest_smaller_than) 54{ 55 IntrusiveRBTree test; 56 IntrusiveTest first { 10 }; 57 test.insert(1, first); 58 IntrusiveTest second { 20 }; 59 test.insert(11, second); 60 IntrusiveTest third { 30 }; 61 test.insert(21, third); 62 EXPECT_EQ(test.size(), 3u); 63 EXPECT_EQ(test.find_largest_not_above(3)->m_some_value, 10); 64 EXPECT_EQ(test.find_largest_not_above(17)->m_some_value, 20); 65 EXPECT_EQ(test.find_largest_not_above(22)->m_some_value, 30); 66 EXPECT_EQ(test.find_largest_not_above(-5), nullptr); 67 VERIFY(test.remove(1)); 68 VERIFY(test.remove(11)); 69 VERIFY(test.remove(21)); 70} 71 72TEST_CASE(key_ordered_iteration) 73{ 74 constexpr auto amount = 10000; 75 IntrusiveRBTree test; 76 Vector<NonnullOwnPtr<IntrusiveTest>> m_entries; 77 Array<int, amount> keys {}; 78 79 // generate random key order 80 for (int i = 0; i < amount; i++) { 81 keys[i] = i; 82 } 83 for (size_t i = 0; i < amount; i++) { 84 swap(keys[i], keys[get_random<size_t>() % amount]); 85 } 86 87 // insert random keys 88 for (size_t i = 0; i < amount; i++) { 89 auto entry = make<IntrusiveTest>(keys[i]); 90 test.insert(keys[i], *entry); 91 m_entries.append(move(entry)); 92 } 93 94 // check key-ordered iteration 95 int index = 0; 96 for (auto& value : test) { 97 EXPECT(value.m_some_value == index++); 98 } 99 100 // ensure we can remove all of them (aka, tree structure is not destroyed somehow) 101 for (size_t i = 0; i < amount; i++) { 102 EXPECT(test.remove(i)); 103 } 104} 105 106TEST_CASE(clear) 107{ 108 IntrusiveRBTree test; 109 Vector<NonnullOwnPtr<IntrusiveTest>> m_entries; 110 for (size_t i = 0; i < 1000; i++) { 111 auto entry = make<IntrusiveTest>(i); 112 test.insert(i, *entry); 113 m_entries.append(move(entry)); 114 } 115 test.clear(); 116 EXPECT_EQ(test.size(), 0u); 117} 118 119class IntrusiveRefPtrTest : public RefCounted<IntrusiveRefPtrTest> { 120public: 121 IntrusiveRefPtrTest() 122 { 123 } 124 125 IntrusiveRedBlackTreeNode<int, IntrusiveRefPtrTest, RefPtr<IntrusiveRefPtrTest>> m_tree_node; 126}; 127using IntrusiveRefPtrRBTree = IntrusiveRedBlackTree<&IntrusiveRefPtrTest::m_tree_node>; 128 129TEST_CASE(intrusive_ref_ptr_no_ref_leaks) 130{ 131 auto item = adopt_ref(*new IntrusiveRefPtrTest()); 132 EXPECT_EQ(1u, item->ref_count()); 133 IntrusiveRefPtrRBTree ref_tree; 134 135 ref_tree.insert(0, *item); 136 EXPECT_EQ(2u, item->ref_count()); 137 138 ref_tree.remove(0); 139 EXPECT_EQ(1u, item->ref_count()); 140} 141 142TEST_CASE(intrusive_ref_ptr_clear) 143{ 144 auto item = adopt_ref(*new IntrusiveRefPtrTest()); 145 EXPECT_EQ(1u, item->ref_count()); 146 IntrusiveRefPtrRBTree ref_tree; 147 148 ref_tree.insert(0, *item); 149 EXPECT_EQ(2u, item->ref_count()); 150 151 ref_tree.clear(); 152 EXPECT_EQ(1u, item->ref_count()); 153} 154 155TEST_CASE(intrusive_ref_ptr_destructor) 156{ 157 auto item = adopt_ref(*new IntrusiveRefPtrTest()); 158 EXPECT_EQ(1u, item->ref_count()); 159 160 { 161 IntrusiveRefPtrRBTree ref_tree; 162 ref_tree.insert(0, *item); 163 EXPECT_EQ(2u, item->ref_count()); 164 } 165 166 EXPECT_EQ(1u, item->ref_count()); 167} 168 169class IntrusiveNonnullRefPtrTest : public RefCounted<IntrusiveNonnullRefPtrTest> { 170public: 171 IntrusiveNonnullRefPtrTest() 172 { 173 } 174 175 IntrusiveRedBlackTreeNode<int, IntrusiveNonnullRefPtrTest, NonnullRefPtr<IntrusiveNonnullRefPtrTest>> m_tree_node; 176}; 177using IntrusiveNonnullRefPtrRBTree = IntrusiveRedBlackTree<&IntrusiveNonnullRefPtrTest::m_tree_node>; 178 179TEST_CASE(intrusive_nonnull_ref_ptr_intrusive) 180{ 181 auto item = adopt_ref(*new IntrusiveNonnullRefPtrTest()); 182 EXPECT_EQ(1u, item->ref_count()); 183 IntrusiveNonnullRefPtrRBTree nonnull_ref_tree; 184 185 nonnull_ref_tree.insert(0, *item); 186 EXPECT_EQ(2u, item->ref_count()); 187 EXPECT(!nonnull_ref_tree.is_empty()); 188 189 nonnull_ref_tree.remove(0); 190 EXPECT_EQ(1u, item->ref_count()); 191 192 EXPECT(nonnull_ref_tree.is_empty()); 193}