123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- /*
- * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/Format.h>
- #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->pointer())
- // 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->pointer()) {
- // 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().pointer() == new_value.pointer()))
- 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().add_to_write_ahead_log(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;
- }
- }
|