Serenity Operating System
at master 248 lines 8.5 kB view raw
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 9namespace SQL { 10 11BTreeIterator::BTreeIterator(TreeNode* node, int index) 12 : m_current(node) 13 , m_index(index) 14{ 15 if (!node) { 16 m_where = Where::End; 17 } else { 18 if (index < 0) { 19 while (!node->is_leaf() && (node->size() != 0)) { 20 node = node->down_node(0); 21 } 22 if (node->size() == 0) { 23 m_where = Where::End; 24 m_current = nullptr; 25 m_index = -1; 26 } else { 27 m_where = Where::Valid; 28 m_current = node; 29 m_index = 0; 30 } 31 } else { 32 VERIFY(m_index < (int)m_current->size()); 33 } 34 } 35} 36 37int BTreeIterator::cmp(BTreeIterator const& other) const 38{ 39 if (is_end()) 40 return (other.is_end()) ? 0 : 1; 41 if (other.is_end()) 42 return -1; 43 VERIFY(&other.m_current->tree() == &m_current->tree()); 44 VERIFY((m_current->size() > 0) && (other.m_current->size() > 0)); 45 if (&m_current != &other.m_current) 46 return (*m_current)[m_current->size() - 1].compare((*(other.m_current))[0]); 47 return (*m_current)[m_index].compare((*(other.m_current))[other.m_index]); 48} 49 50int BTreeIterator::cmp(Key const& other) const 51{ 52 if (is_end()) 53 return 1; 54 if (other.is_null()) 55 return -1; 56 return key().compare(other); 57} 58 59BTreeIterator BTreeIterator::next() const 60{ 61 if (is_end()) 62 return end(); 63 64 auto ix = m_index; 65 auto node = m_current; 66 if (ix < (int)(node->size() - 1)) { 67 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 return BTreeIterator(node, ix + 1); 71 } 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 ix++; 91 while (!node->is_leaf()) { 92 node = node->down_node(ix); 93 ix = 0; 94 } 95 } 96 VERIFY(node->is_leaf() && (ix < (int)node->size())); 97 return BTreeIterator(node, ix); 98 } 99 100 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 for (auto up = node->up(); up; up = node->up()) { 107 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 if (up->down_pointer(i) == node->pointer()) 111 // Found it. This is the iterator's next value: 112 return BTreeIterator(up, (int)i); 113 } 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 node = up; 118 } 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 return end(); 122 } 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 TreeNode* down; 127 for (down = node->down_node(node->size()); !down->is_leaf(); down = down->down_node(0)) 128 ; 129 return BTreeIterator(down, 0); 130} 131 132// FIXME Reverse iterating doesn't quite work; we don't recognize the 133// end (which is really the beginning) of the tree. 134BTreeIterator BTreeIterator::previous() const 135{ 136 if (is_end()) { 137 return end(); 138 } 139 140 auto node = m_current; 141 auto ix = m_index; 142 if (ix > 0) { 143 if (node->is_leaf()) { 144 // We're in the middle of a leaf node. Previous entry is 145 // is the previous entry of the node: 146 return BTreeIterator(node, ix - 1); 147 } else { 148 /* 149 * We're in the middle of a non-leaf node. The iterator's 150 * previous value is all the way down to the left, last entry. 151 * 152 * | 153 * +--+--+--+--+ 154 * | | |##| | 155 * +--+--+--+--+ 156 * / | | | \ 157 * | 158 * +--+--+--+--+ 159 * | | | | | 160 * +--+--+--+--+ 161 * \ 162 * +--+--+--+--+ 163 * | | | |++| 164 * +--+--+--+--+ 165 */ 166 while (!node->is_leaf()) { 167 node = node->down_node(ix); 168 ix = (int)node->size(); 169 } 170 } 171 VERIFY(node->is_leaf() && (ix <= (int)node->size())); 172 return BTreeIterator(node, ix); 173 } 174 175 if (node->is_leaf()) { 176 // We currently at the first entry of a leaf node. We need to check one 177 // or more levels up until we end up in the "middle" of a node. 178 // If one level up we're still at the start of the node, we need 179 // to keep going up until we hit the root node. If we're at the 180 // start of the root node, we reached the start of the btree. 181 auto stash_current = node; 182 for (auto up = node->up(); up; up = node->up()) { 183 for (size_t i = up->size(); i > 0; i--) { 184 // One level up, try to find the entry with the current 185 // node's pointer as the right pointer: 186 if (up->down_pointer(i) == node->pointer()) { 187 // Found it. This is the iterator's next value: 188 node = up; 189 ix = (int)i - 1; 190 return BTreeIterator(node, ix); 191 } 192 } 193 // We didn't find the m_current's pointer as a right node. So 194 // it must be the left node all the way at the start and we need 195 // to go one more level up: 196 node = up; 197 } 198 // We reached the root node and we're still at the start of the node. 199 // That means we're at the start of the btree. 200 return BTreeIterator(stash_current, 0); 201 } 202 203 // If we're at the start of a non-leaf node, we need to follow the 204 // left pointer down until we find a leaf: 205 TreeNode* down = node->down_node(0); 206 while (!down->is_leaf()) 207 down = down->down_node(down->size()); 208 return BTreeIterator(down, down->size() - 1); 209} 210 211Key BTreeIterator::key() const 212{ 213 if (is_end()) 214 return {}; 215 return (*m_current)[m_index]; 216} 217 218bool BTreeIterator::update(Key const& new_value) 219{ 220 if (is_end()) 221 return false; 222 if ((cmp(new_value) == 0) && (key().pointer() == new_value.pointer())) 223 return true; 224 auto previous_iter = previous(); 225 auto next_iter = next(); 226 if (!m_current->tree().duplicates_allowed() && ((previous_iter == new_value) || (next_iter == new_value))) { 227 return false; 228 } 229 if ((previous_iter > new_value) || (next_iter < new_value)) 230 return false; 231 232 // We are friend of BTree and TreeNode. Don't know how I feel about that. 233 m_current->m_entries[m_index] = new_value; 234 m_current->tree().serializer().serialize_and_write(*m_current); 235 return true; 236} 237 238BTreeIterator& BTreeIterator::operator=(BTreeIterator const& other) 239{ 240 if (&other != this) { 241 m_current = other.m_current; 242 m_index = other.m_index; 243 m_where = other.m_where; 244 } 245 return *this; 246} 247 248}