mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
fdac8331cc
No functional changes.
247 lines
8.3 KiB
C++
247 lines
8.3 KiB
C++
/*
|
|
* Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibSQL/BTree.h>
|
|
|
|
namespace SQL {
|
|
|
|
BTreeIterator::BTreeIterator(TreeNode* node, int index)
|
|
: m_current(node)
|
|
, m_index(index)
|
|
{
|
|
if (!node) {
|
|
m_where = Where::End;
|
|
} else {
|
|
if (index < 0) {
|
|
while (!node->is_leaf() && (node->size() != 0)) {
|
|
node = node->down_node(0);
|
|
}
|
|
if (node->size() == 0) {
|
|
m_where = Where::End;
|
|
m_current = nullptr;
|
|
m_index = -1;
|
|
} else {
|
|
m_where = Where::Valid;
|
|
m_current = node;
|
|
m_index = 0;
|
|
}
|
|
} else {
|
|
VERIFY(m_index < (int)m_current->size());
|
|
}
|
|
}
|
|
}
|
|
|
|
int BTreeIterator::cmp(BTreeIterator const& other) const
|
|
{
|
|
if (is_end())
|
|
return (other.is_end()) ? 0 : 1;
|
|
if (other.is_end())
|
|
return -1;
|
|
VERIFY(&other.m_current->tree() == &m_current->tree());
|
|
VERIFY((m_current->size() > 0) && (other.m_current->size() > 0));
|
|
if (&m_current != &other.m_current)
|
|
return (*m_current)[m_current->size() - 1].compare((*(other.m_current))[0]);
|
|
return (*m_current)[m_index].compare((*(other.m_current))[other.m_index]);
|
|
}
|
|
|
|
int BTreeIterator::cmp(Key const& other) const
|
|
{
|
|
if (is_end())
|
|
return 1;
|
|
if (other.is_null())
|
|
return -1;
|
|
return key().compare(other);
|
|
}
|
|
|
|
BTreeIterator BTreeIterator::next() const
|
|
{
|
|
if (is_end())
|
|
return end();
|
|
|
|
auto ix = m_index;
|
|
auto node = m_current;
|
|
if (ix < (int)(node->size() - 1)) {
|
|
if (node->is_leaf()) {
|
|
// We're in the middle of a leaf node. Next entry is
|
|
// is the next entry of the node:
|
|
return BTreeIterator(node, ix + 1);
|
|
} else {
|
|
/*
|
|
* We're in the middle of a non-leaf node. The iterator's
|
|
* next value is all the way down to the right, first entry.
|
|
*
|
|
* |
|
|
* +--+--+--+--+
|
|
* | |##| | |
|
|
* +--+--+--+--+
|
|
* / | | | \
|
|
* |
|
|
* +--+--+--+--+
|
|
* | | | | |
|
|
* +--+--+--+--+
|
|
* /
|
|
* +--+--+--+--+
|
|
* |++| | | |
|
|
* +--+--+--+--+
|
|
*/
|
|
ix++;
|
|
while (!node->is_leaf()) {
|
|
node = node->down_node(ix);
|
|
ix = 0;
|
|
}
|
|
}
|
|
VERIFY(node->is_leaf() && (ix < (int)node->size()));
|
|
return BTreeIterator(node, ix);
|
|
}
|
|
|
|
if (node->is_leaf()) {
|
|
// We currently at the last entry of a leaf node. We need to check
|
|
// one or more levels up until we end up in the "middle" of a node.
|
|
// If one level up we're still at the end of the node, we need
|
|
// to keep going up until we hit the root node. If we're at the
|
|
// end of the root node, we reached the end of the btree.
|
|
for (auto up = node->up(); up; up = node->up()) {
|
|
for (size_t i = 0; i < up->size(); i++) {
|
|
// One level up, try to find the entry with the current
|
|
// node's pointer as the left pointer:
|
|
if (up->down_pointer(i) == node->block_index())
|
|
// Found it. This is the iterator's next value:
|
|
return BTreeIterator(up, (int)i);
|
|
}
|
|
// We didn't find the m_current's pointer as a left node. So
|
|
// it must be the right node all the way at the end and we need
|
|
// to go one more level up:
|
|
node = up;
|
|
}
|
|
// We reached the root node and we're still at the end of the node.
|
|
// That means we're at the end of the btree.
|
|
return end();
|
|
}
|
|
|
|
// If we're at the end of a non-leaf node, we need to follow the
|
|
// right pointer down until we find a leaf:
|
|
TreeNode* down;
|
|
for (down = node->down_node(node->size()); !down->is_leaf(); down = down->down_node(0))
|
|
;
|
|
return BTreeIterator(down, 0);
|
|
}
|
|
|
|
// FIXME Reverse iterating doesn't quite work; we don't recognize the
|
|
// end (which is really the beginning) of the tree.
|
|
BTreeIterator BTreeIterator::previous() const
|
|
{
|
|
if (is_end())
|
|
return end();
|
|
|
|
auto node = m_current;
|
|
auto ix = m_index;
|
|
if (ix > 0) {
|
|
if (node->is_leaf()) {
|
|
// We're in the middle of a leaf node. Previous entry is
|
|
// is the previous entry of the node:
|
|
return BTreeIterator(node, ix - 1);
|
|
} else {
|
|
/*
|
|
* We're in the middle of a non-leaf node. The iterator's
|
|
* previous value is all the way down to the left, last entry.
|
|
*
|
|
* |
|
|
* +--+--+--+--+
|
|
* | | |##| |
|
|
* +--+--+--+--+
|
|
* / | | | \
|
|
* |
|
|
* +--+--+--+--+
|
|
* | | | | |
|
|
* +--+--+--+--+
|
|
* \
|
|
* +--+--+--+--+
|
|
* | | | |++|
|
|
* +--+--+--+--+
|
|
*/
|
|
while (!node->is_leaf()) {
|
|
node = node->down_node(ix);
|
|
ix = (int)node->size();
|
|
}
|
|
}
|
|
VERIFY(node->is_leaf() && (ix <= (int)node->size()));
|
|
return BTreeIterator(node, ix);
|
|
}
|
|
|
|
if (node->is_leaf()) {
|
|
// We currently at the first entry of a leaf node. We need to check one
|
|
// or more levels up until we end up in the "middle" of a node.
|
|
// If one level up we're still at the start of the node, we need
|
|
// to keep going up until we hit the root node. If we're at the
|
|
// start of the root node, we reached the start of the btree.
|
|
auto stash_current = node;
|
|
for (auto up = node->up(); up; up = node->up()) {
|
|
for (size_t i = up->size(); i > 0; i--) {
|
|
// One level up, try to find the entry with the current
|
|
// node's pointer as the right pointer:
|
|
if (up->down_pointer(i) == node->block_index()) {
|
|
// Found it. This is the iterator's next value:
|
|
node = up;
|
|
ix = (int)i - 1;
|
|
return BTreeIterator(node, ix);
|
|
}
|
|
}
|
|
// We didn't find the m_current's pointer as a right node. So
|
|
// it must be the left node all the way at the start and we need
|
|
// to go one more level up:
|
|
node = up;
|
|
}
|
|
// We reached the root node and we're still at the start of the node.
|
|
// That means we're at the start of the btree.
|
|
return BTreeIterator(stash_current, 0);
|
|
}
|
|
|
|
// If we're at the start of a non-leaf node, we need to follow the
|
|
// left pointer down until we find a leaf:
|
|
TreeNode* down = node->down_node(0);
|
|
while (!down->is_leaf())
|
|
down = down->down_node(down->size());
|
|
return BTreeIterator(down, down->size() - 1);
|
|
}
|
|
|
|
Key BTreeIterator::key() const
|
|
{
|
|
if (is_end())
|
|
return {};
|
|
return (*m_current)[m_index];
|
|
}
|
|
|
|
bool BTreeIterator::update(Key const& new_value)
|
|
{
|
|
if (is_end())
|
|
return false;
|
|
if ((cmp(new_value) == 0) && (key().block_index() == new_value.block_index()))
|
|
return true;
|
|
auto previous_iter = previous();
|
|
auto next_iter = next();
|
|
if (!m_current->tree().duplicates_allowed() && ((previous_iter == new_value) || (next_iter == new_value))) {
|
|
return false;
|
|
}
|
|
if ((previous_iter > new_value) || (next_iter < new_value))
|
|
return false;
|
|
|
|
// We are friend of BTree and TreeNode. Don't know how I feel about that.
|
|
m_current->m_entries[m_index] = new_value;
|
|
m_current->tree().serializer().serialize_and_write(*m_current);
|
|
return true;
|
|
}
|
|
|
|
BTreeIterator& BTreeIterator::operator=(BTreeIterator const& other)
|
|
{
|
|
if (&other != this) {
|
|
m_current = other.m_current;
|
|
m_index = other.m_index;
|
|
m_where = other.m_where;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
}
|