/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 | | } |