summaryrefslogtreecommitdiff
path: root/Tests/AK/TestIntrusiveRedBlackTree.cpp
blob: 207b026cecaf2b8b7904ca509f29618cce0e634f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
 * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <LibTest/TestCase.h>

#include <AK/IntrusiveRedBlackTree.h>
#include <AK/NonnullOwnPtrVector.h>
#include <AK/Random.h>

class IntrusiveTest {
public:
    IntrusiveTest(int key, int value)
        : m_tree_node(key)
        , m_some_value(value)
    {
    }

    IntrusiveRedBlackTreeNode<int> m_tree_node;
    int m_some_value;
};

TEST_CASE(construct)
{
    IntrusiveRedBlackTree<int, IntrusiveTest, &IntrusiveTest::m_tree_node> empty;
    EXPECT(empty.is_empty());
    EXPECT(empty.size() == 0);
}

TEST_CASE(ints)
{
    IntrusiveRedBlackTree<int, IntrusiveTest, &IntrusiveTest::m_tree_node> test;
    IntrusiveTest first { 1, 10 };
    test.insert(first);
    IntrusiveTest second { 3, 20 };
    test.insert(second);
    IntrusiveTest third { 2, 30 };
    test.insert(third);
    EXPECT_EQ(test.size(), 3u);
    EXPECT_EQ(test.find(3)->m_some_value, 20);
    EXPECT_EQ(test.find(2)->m_some_value, 30);
    EXPECT_EQ(test.find(1)->m_some_value, 10);
    EXPECT(!test.remove(4));
    EXPECT(test.remove(2));
    EXPECT(test.remove(1));
    EXPECT(test.remove(3));
    EXPECT_EQ(test.size(), 0u);
}

TEST_CASE(largest_smaller_than)
{
    IntrusiveRedBlackTree<int, IntrusiveTest, &IntrusiveTest::m_tree_node> test;
    IntrusiveTest first { 1, 10 };
    test.insert(first);
    IntrusiveTest second { 11, 20 };
    test.insert(second);
    IntrusiveTest third { 21, 30 };
    test.insert(third);
    EXPECT_EQ(test.size(), 3u);
    EXPECT_EQ(test.find_largest_not_above(3)->m_some_value, 10);
    EXPECT_EQ(test.find_largest_not_above(17)->m_some_value, 20);
    EXPECT_EQ(test.find_largest_not_above(22)->m_some_value, 30);
    EXPECT_EQ(test.find_largest_not_above(-5), nullptr);
    VERIFY(test.remove(1));
    VERIFY(test.remove(11));
    VERIFY(test.remove(21));
}

TEST_CASE(key_ordered_iteration)
{
    constexpr auto amount = 10000;
    IntrusiveRedBlackTree<int, IntrusiveTest, &IntrusiveTest::m_tree_node> test;
    NonnullOwnPtrVector<IntrusiveTest> m_entries;
    Array<int, amount> keys {};

    // generate random key order
    for (int i = 0; i < amount; i++) {
        keys[i] = i;
    }
    for (size_t i = 0; i < amount; i++) {
        swap(keys[i], keys[get_random<size_t>() % amount]);
    }

    // insert random keys
    for (size_t i = 0; i < amount; i++) {
        auto entry = make<IntrusiveTest>(keys[i], keys[i]);
        test.insert(*entry);
        m_entries.append(move(entry));
    }

    // check key-ordered iteration
    int index = 0;
    for (auto& value : test) {
        EXPECT(value.m_some_value == index++);
    }

    // ensure we can remove all of them (aka, tree structure is not destroyed somehow)
    for (size_t i = 0; i < amount; i++) {
        EXPECT(test.remove(i));
    }
}

TEST_CASE(clear)
{
    IntrusiveRedBlackTree<int, IntrusiveTest, &IntrusiveTest::m_tree_node> test;
    NonnullOwnPtrVector<IntrusiveTest> m_entries;
    for (size_t i = 0; i < 1000; i++) {
        auto entry = make<IntrusiveTest>(i, i);
        test.insert(*entry);
        m_entries.append(move(entry));
    }
    test.clear();
    EXPECT_EQ(test.size(), 0u);
}