Coverage Report

Created: 2025-11-02 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibSQL/BTreeIterator.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibSQL/BTree.h>
8
9
namespace SQL {
10
11
BTreeIterator::BTreeIterator(TreeNode* node, int index)
12
0
    : m_current(node)
13
0
    , m_index(index)
14
0
{
15
0
    if (!node) {
16
0
        m_where = Where::End;
17
0
    } else {
18
0
        if (index < 0) {
19
0
            while (!node->is_leaf() && (node->size() != 0)) {
20
0
                node = node->down_node(0);
21
0
            }
22
0
            if (node->size() == 0) {
23
0
                m_where = Where::End;
24
0
                m_current = nullptr;
25
0
                m_index = -1;
26
0
            } else {
27
0
                m_where = Where::Valid;
28
0
                m_current = node;
29
0
                m_index = 0;
30
0
            }
31
0
        } else {
32
0
            VERIFY(m_index < (int)m_current->size());
33
0
        }
34
0
    }
35
0
}
36
37
int BTreeIterator::cmp(BTreeIterator const& other) const
38
0
{
39
0
    if (is_end())
40
0
        return (other.is_end()) ? 0 : 1;
41
0
    if (other.is_end())
42
0
        return -1;
43
0
    VERIFY(&other.m_current->tree() == &m_current->tree());
44
0
    VERIFY((m_current->size() > 0) && (other.m_current->size() > 0));
45
0
    if (&m_current != &other.m_current)
46
0
        return (*m_current)[m_current->size() - 1].compare((*(other.m_current))[0]);
47
0
    return (*m_current)[m_index].compare((*(other.m_current))[other.m_index]);
48
0
}
49
50
int BTreeIterator::cmp(Key const& other) const
51
0
{
52
0
    if (is_end())
53
0
        return 1;
54
0
    if (other.is_null())
55
0
        return -1;
56
0
    return key().compare(other);
57
0
}
58
59
BTreeIterator BTreeIterator::next() const
60
0
{
61
0
    if (is_end())
62
0
        return end();
63
64
0
    auto ix = m_index;
65
0
    auto node = m_current;
66
0
    if (ix < (int)(node->size() - 1)) {
67
0
        if (node->is_leaf()) {
68
            // We're in the middle of a leaf node. Next entry is
69
            // is the next entry of the node:
70
0
            return BTreeIterator(node, ix + 1);
71
0
        } else {
72
            /*
73
             * We're in the middle of a non-leaf node. The iterator's
74
             * next value is all the way down to the right, first entry.
75
             *
76
             *                  |
77
             *                  +--+--+--+--+
78
             *                  |  |##|  |  |
79
             *                  +--+--+--+--+
80
             *                 /   |  |  |   \
81
             *                        |
82
             *               +--+--+--+--+
83
             *               |  |  |  |  |
84
             *               +--+--+--+--+
85
             *              /
86
             * +--+--+--+--+
87
             * |++|  |  |  |
88
             * +--+--+--+--+
89
             */
90
0
            ix++;
91
0
            while (!node->is_leaf()) {
92
0
                node = node->down_node(ix);
93
0
                ix = 0;
94
0
            }
95
0
        }
96
0
        VERIFY(node->is_leaf() && (ix < (int)node->size()));
97
0
        return BTreeIterator(node, ix);
98
0
    }
99
100
0
    if (node->is_leaf()) {
101
        // We currently at the last entry of a leaf node. We need to check
102
        // one or more levels up until we end up in the "middle" of a node.
103
        // If one level up we're still at the end of the node, we need
104
        // to keep going up until we hit the root node. If we're at the
105
        // end of the root node, we reached the end of the btree.
106
0
        for (auto up = node->up(); up; up = node->up()) {
107
0
            for (size_t i = 0; i < up->size(); i++) {
108
                // One level up, try to find the entry with the current
109
                // node's pointer as the left pointer:
110
0
                if (up->down_pointer(i) == node->block_index())
111
                    // Found it. This is the iterator's next value:
112
0
                    return BTreeIterator(up, (int)i);
113
0
            }
114
            // We didn't find the m_current's pointer as a left node. So
115
            // it must be the right node all the way at the end and we need
116
            // to go one more level up:
117
0
            node = up;
118
0
        }
119
        // We reached the root node and we're still at the end of the node.
120
        // That means we're at the end of the btree.
121
0
        return end();
122
0
    }
123
124
    // If we're at the end of a non-leaf node, we need to follow the
125
    // right pointer down until we find a leaf:
126
0
    TreeNode* down;
127
0
    for (down = node->down_node(node->size()); !down->is_leaf(); down = down->down_node(0))
128
0
        ;
129
0
    return BTreeIterator(down, 0);
130
0
}
131
132
// FIXME Reverse iterating doesn't quite work; we don't recognize the
133
// end (which is really the beginning) of the tree.
134
BTreeIterator BTreeIterator::previous() const
135
0
{
136
0
    if (is_end())
137
0
        return end();
138
139
0
    auto node = m_current;
140
0
    auto ix = m_index;
141
0
    if (ix > 0) {
142
0
        if (node->is_leaf()) {
143
            // We're in the middle of a leaf node. Previous entry is
144
            // is the previous entry of the node:
145
0
            return BTreeIterator(node, ix - 1);
146
0
        } else {
147
            /*
148
             * We're in the middle of a non-leaf node. The iterator's
149
             * previous value is all the way down to the left, last entry.
150
             *
151
             *                  |
152
             *                  +--+--+--+--+
153
             *                  |  |  |##|  |
154
             *                  +--+--+--+--+
155
             *                 /   |  |  |   \
156
             *                        |
157
             *               +--+--+--+--+
158
             *               |  |  |  |  |
159
             *               +--+--+--+--+
160
             *                            \
161
             *                 +--+--+--+--+
162
             *                 |  |  |  |++|
163
             *                 +--+--+--+--+
164
             */
165
0
            while (!node->is_leaf()) {
166
0
                node = node->down_node(ix);
167
0
                ix = (int)node->size();
168
0
            }
169
0
        }
170
0
        VERIFY(node->is_leaf() && (ix <= (int)node->size()));
171
0
        return BTreeIterator(node, ix);
172
0
    }
173
174
0
    if (node->is_leaf()) {
175
        // We currently at the first entry of a leaf node. We need to check one
176
        // or more levels up until we end up in the "middle" of a node.
177
        // If one level up we're still at the start of the node, we need
178
        // to keep going up until we hit the root node. If we're at the
179
        // start of the root node, we reached the start of the btree.
180
0
        auto stash_current = node;
181
0
        for (auto up = node->up(); up; up = node->up()) {
182
0
            for (size_t i = up->size(); i > 0; i--) {
183
                // One level up, try to find the entry with the current
184
                // node's pointer as the right pointer:
185
0
                if (up->down_pointer(i) == node->block_index()) {
186
                    // Found it. This is the iterator's next value:
187
0
                    node = up;
188
0
                    ix = (int)i - 1;
189
0
                    return BTreeIterator(node, ix);
190
0
                }
191
0
            }
192
            // We didn't find the m_current's pointer as a right node. So
193
            // it must be the left node all the way at the start and we need
194
            // to go one more level up:
195
0
            node = up;
196
0
        }
197
        // We reached the root node and we're still at the start of the node.
198
        // That means we're at the start of the btree.
199
0
        return BTreeIterator(stash_current, 0);
200
0
    }
201
202
    // If we're at the start of a non-leaf node, we need to follow the
203
    // left pointer down until we find a leaf:
204
0
    TreeNode* down = node->down_node(0);
205
0
    while (!down->is_leaf())
206
0
        down = down->down_node(down->size());
207
0
    return BTreeIterator(down, down->size() - 1);
208
0
}
209
210
Key BTreeIterator::key() const
211
0
{
212
0
    if (is_end())
213
0
        return {};
214
0
    return (*m_current)[m_index];
215
0
}
216
217
bool BTreeIterator::update(Key const& new_value)
218
0
{
219
0
    if (is_end())
220
0
        return false;
221
0
    if ((cmp(new_value) == 0) && (key().block_index() == new_value.block_index()))
222
0
        return true;
223
0
    auto previous_iter = previous();
224
0
    auto next_iter = next();
225
0
    if (!m_current->tree().duplicates_allowed() && ((previous_iter == new_value) || (next_iter == new_value))) {
226
0
        return false;
227
0
    }
228
0
    if ((previous_iter > new_value) || (next_iter < new_value))
229
0
        return false;
230
231
    // We are friend of BTree and TreeNode. Don't know how I feel about that.
232
0
    m_current->m_entries[m_index] = new_value;
233
0
    m_current->tree().serializer().serialize_and_write(*m_current);
234
0
    return true;
235
0
}
236
237
BTreeIterator& BTreeIterator::operator=(BTreeIterator const& other)
238
0
{
239
0
    if (&other != this) {
240
0
        m_current = other.m_current;
241
0
        m_index = other.m_index;
242
0
        m_where = other.m_where;
243
0
    }
244
0
    return *this;
245
0
}
246
247
}