- More optimization on fennec::sequence. There are areas that could be improved, but the running time is now within margin. It can be revisited later if this data-structure becomes the focus of a performance critical task.

This commit is contained in:
2025-09-18 21:34:29 -04:00
parent d546519180
commit 18c8171847
3 changed files with 129 additions and 129 deletions

View File

@@ -490,8 +490,8 @@ class BinTreePrinter:
self.visit.popleft() self.visit.popleft()
value = self.tree[node]['value'] value = self.tree[node]['value']
left = self.tree[node]['left'] left = self.tree[node]['child'][0]
right = self.tree[node]['right'] right = self.tree[node]['child'][1]
if right < self.capacity: if right < self.capacity:
self.visit.appendleft((right, 1, depth + 1)) self.visit.appendleft((right, 1, depth + 1))

View File

@@ -63,31 +63,28 @@ public:
protected: protected:
struct node { struct node {
value_t value; value_t value;
size_t parent, left, right; size_t parent;
size_t depth; size_t child[2];
constexpr node() constexpr node()
: value(nullopt) : value()
, parent(npos), left(npos), right(npos) , parent(npos), child{ npos, npos } {
, depth(0) {
} }
template<typename...ArgsT> template<typename...ArgsT>
constexpr node(size_t p, size_t l, size_t r, size_t d, ArgsT&&...args) constexpr node(size_t p, size_t l, size_t r, ArgsT&&...args)
: value(fennec::forward<ArgsT>(args)...) : value(fennec::forward<ArgsT>(args)...)
, parent(p), left(l), right(r) , parent(p), child{ l, r } {
, depth(d) {
} }
constexpr ~node() { constexpr ~node() {
parent = npos; parent = npos;
left = npos; child[0] = npos;
right = npos; child[1] = npos;
depth = npos;
} }
size_t& operator[](bool d) { size_t& operator[](bool d) {
return d ? right : left; return child[d];
} }
}; };
@@ -204,7 +201,7 @@ public:
/// \param i The node id /// \param i The node id
/// \returns The left child of node `i` /// \returns The left child of node `i`
constexpr size_t left(size_t i) const { constexpr size_t left(size_t i) const {
return i == npos ? npos : _table[i].left; return i == npos ? npos : _table[i].child[false];
} }
/// ///
@@ -212,7 +209,7 @@ public:
/// \param i The node id /// \param i The node id
/// \returns The right child of node `i` /// \returns The right child of node `i`
constexpr size_t right(size_t i) const { constexpr size_t right(size_t i) const {
return i == npos ? npos : _table[i].right; return i == npos ? npos : _table[i].child[true];
} }
/// ///
@@ -221,7 +218,7 @@ public:
/// \param dir The direction to go `true` for right, `false` for left /// \param dir The direction to go `true` for right, `false` for left
/// \returns The child in the direction specified by `dir` /// \returns The child in the direction specified by `dir`
constexpr size_t child(size_t i, bool dir) const { constexpr size_t child(size_t i, bool dir) const {
return dir ? right(i) : left(i); return i == npos ? npos : _table[i].child[dir];
} }
/// ///
@@ -237,10 +234,15 @@ public:
/// \param i The id of the node /// \param i The id of the node
/// \returns The id of the sibling of `i` /// \returns The id of the sibling of `i`
constexpr size_t sibling(size_t i) const { constexpr size_t sibling(size_t i) const {
size_t p = parent(i); if (i == npos) {
size_t l = left(p); return npos;
size_t r = right(p); }
return i == l ? r : l; if (i == _root) {
return npos;
}
size_t p = _parent(i);
bool d = i == _right(p);
return _child(p, d);
} }
/// ///
@@ -248,7 +250,12 @@ public:
/// \param i The node id /// \param i The node id
/// \returns The depth of node `i` /// \returns The depth of node `i`
constexpr size_t depth(size_t i) const { constexpr size_t depth(size_t i) const {
return i >= _table.size() ? npos : _table[i].depth; size_t d = 0;
while (i != npos) {
i = _parent(i);
++d;
}
return d;
} }
/// ///
@@ -259,8 +266,8 @@ public:
if (i >= _table.size()) { if (i >= _table.size()) {
return npos; return npos;
} }
while (_table[i].left != npos) { while (_table[i].child[false] != npos) {
i = _table[i].left; i = _table[i].child[false];
} }
return i; return i;
} }
@@ -273,8 +280,8 @@ public:
if (i >= _table.size()) { if (i >= _table.size()) {
return npos; return npos;
} }
while (_table[i].right != npos) { while (_table[i].right[false] != npos) {
i = _table[i].right; i = _table[i].right[false];
} }
return i; return i;
} }
@@ -375,71 +382,19 @@ public:
return this->_insert_right(p, fennec::forward<ArgsT>(args)...); return this->_insert_right(p, fennec::forward<ArgsT>(args)...);
} }
///
/// \brief Perform a Left Tree Rotation at `i`
/// \param i The root node for the rotation
constexpr void rotate_left(size_t i) {
if (i >=_table.size()) {
return;
}
size_t l = i;
size_t p = parent(l);
size_t r = right(l);
if (p == npos) {
_root = r;
} else if (l == _table[p].left) {
_table[p].left = r;
} else {
_table[p].right = r;
}
_table[l].parent = r;
_table[l].right = _table[r].left;
_table[r].parent = p;
_table[r].left = l;
}
///
/// \brief Perform a Right Tree Rotation at `i`
/// \param i The root node for the rotation
constexpr void rotate_right(size_t i) {
if (i >=_table.size()) {
return;
}
size_t r = i;
size_t p = parent(r);
size_t l = left(r);
if (p == npos) {
_root = l;
} else if (r == _table[p].left) {
_table[p].left = l;
} else {
_table[p].right = l;
}
_table[r].parent = l;
_table[r].left = _table[l].right;
_table[l].parent = p;
_table[l].right = r;
}
/// ///
/// \brief Perform a Tree Rotation at `i` in the specified direction /// \brief Perform a Tree Rotation at `i` in the specified direction
/// \param i The root node for the rotation /// \param i The root node for the rotation
/// \param dir The direction to rotate, `true` for right, `false` for left /// \param dir The direction to rotate, `true` for right, `false` for left
constexpr size_t rotate(size_t sub, bool dir) { constexpr size_t rotate(size_t sub, bool dir) {
if (sub >=_table.size()) { if (sub == npos) {
return npos; return npos;
} }
size_t sub_parent = parent(sub); size_t sub_parent = _parent(sub);
size_t new_root = child(sub, not dir); size_t new_root = _child(sub, not dir);
size_t new_child = child(new_root, dir); size_t new_child = _child(new_root, dir);
_child(sub, not dir) = new_child; _child(sub, not dir) = new_child;
if (new_child != npos) { if (new_child != npos) {
@@ -457,6 +412,40 @@ public:
return new_root; return new_root;
} }
///
/// \brief Move Insertion, bool d, constructs a new node as the child of `p`
/// \details If the child of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param d The direction to insert
/// \param val The object to move into the new node
/// \returns The id of the new node
constexpr size_t insert(size_t p, bool d, value_t&& val) {
return this->_insert(p, d, fennec::forward<value_t>(val));
}
///
/// \brief Copy Insertion, bool d, constructs a new node as the child of `p`
/// \details If the child of `p` already exists, the copy assignment operator is used instead
/// \param p The parent node
/// \param d The direction to insert
/// \param val The object to copy to the new node
/// \returns The id of the new node
constexpr size_t insert(size_t p, bool d, const value_t& val) {
return this->_insert(p, d, val);
}
///
/// \brief Emplace Insertion, constructs a new node as the child of `p`
/// \details If the child of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param d The direction to insert
/// \param args The arguments to construct the new node with
/// \returns The id of the new node
template<typename...ArgsT>
constexpr size_t emplace(size_t p, bool d, ArgsT&&...args) {
return this->_insert(p, d, fennec::forward<ArgsT>(args)...);
}
/// ///
/// \brief Clears the tree, destroying all elements /// \brief Clears the tree, destroying all elements
constexpr void clear() { constexpr void clear() {
@@ -470,11 +459,11 @@ public:
size_t i = queue.front(); size_t i = queue.front();
queue.pop_front(); queue.pop_front();
if (_table[i].left != npos) { if (_right(i) != npos) {
queue.push_front(_table[i].left); queue.push_front(_right(i));
} }
if (_table[i].right != npos) { if (_left(i) != npos) {
queue.push_front(_table[i].right); queue.push_front(_left(i));
} }
fennec::destruct(&_table[i]); fennec::destruct(&_table[i]);
@@ -761,16 +750,14 @@ protected:
if (i != npos) { if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...); _table[i].value = value_t(fennec::forward<ArgsT>(args)...);
} else { } else {
size_t d = 1;
i = _next_free(); i = _next_free();
if (p != npos) { if (p != npos) {
d = depth(p) + 1; _left(p) = i;
_table[p].left = i;
} }
if (_root == npos) { if (_root == npos) {
_root = i; _root = i;
} }
fennec::construct(&_table[i], p, npos, npos, d, fennec::forward<ArgsT>(args)...); fennec::construct(&_table[i], p, npos, npos, fennec::forward<ArgsT>(args)...);
} }
return i; return i;
} }
@@ -780,24 +767,38 @@ protected:
size_t i = p == npos ? _root : _right(p); size_t i = p == npos ? _root : _right(p);
if (i != npos) { if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...); _table[i].value = value_t(fennec::forward<ArgsT>(args)...);
if (p == npos || _root == npos) {
_root = i;
}
} else { } else {
size_t d = 1;
i = _next_free(); i = _next_free();
if (p != npos) { if (p != npos) {
d = depth(p) + 1; _right(p) = i;
_table[p].right = i;
} }
if (_root == npos) { if (_root == npos) {
_root = i; _root = i;
} }
fennec::construct(&_table[i], p, npos, npos, d, fennec::forward<ArgsT>(args)...); fennec::construct(&_table[i], p, npos, npos, fennec::forward<ArgsT>(args)...);
} }
return i; return i;
} }
template<typename...ArgsT>
constexpr size_t _insert(size_t p, bool d, ArgsT&&...args) {
size_t i = p == npos ? _root : _child(p, d);
if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
return i;
}
i = _next_free();
if (p != npos) {
_child(p, d) = i;
}
if (_root == npos) {
_root = i;
}
fennec::construct(&_table[i], p, npos, npos, fennec::forward<ArgsT>(args)...);
return i;
}
constexpr size_t& _parent(size_t i) { constexpr size_t& _parent(size_t i) {
return _table[i].parent; return _table[i].parent;
@@ -808,19 +809,19 @@ protected:
} }
constexpr size_t& _left(size_t i) { constexpr size_t& _left(size_t i) {
return _table[i].left; return _table[i].child[false];
} }
constexpr size_t& _right(size_t i) { constexpr size_t& _right(size_t i) {
return _table[i].right; return _table[i].child[true];
} }
constexpr size_t& _child(size_t i, bool dir) { constexpr size_t& _child(size_t i, bool dir) {
return dir ? _right(i) : _left(i); return _table[i].child[dir];
} }
constexpr size_t& _sibling(size_t i) { constexpr size_t& _sibling(size_t i) {
size_t p = parent(i); size_t p = _parent(i);
size_t& l = _left(p); size_t& l = _left(p);
size_t& r = _right(p); size_t& r = _right(p);
return i == l ? l : r; return i == l ? l : r;

View File

@@ -109,12 +109,10 @@ protected:
using base_t::left_most; using base_t::left_most;
using base_t::right_most; using base_t::right_most;
using base_t::insert_left; using base_t::emplace_left;
using base_t::insert_right; using base_t::emplace_right;
using base_t::rotate; using base_t::rotate;
using base_t::rotate_left;
using base_t::rotate_right;
using base_t::_table; using base_t::_table;
using base_t::_freed; using base_t::_freed;
@@ -159,9 +157,9 @@ public:
size_t node = _root; size_t node = _root;
while (node != npos) { while (node != npos) {
if (_compare(val, _value(node))) { if (_compare(val, _value(node))) {
node = left(node); node = _left(node);
} else if (_compare(_value(node), val)) { } else if (_compare(_value(node), val)) {
node = right(node); node = _right(node);
} else { } else {
return sequence::iterator(this, _root, node); return sequence::iterator(this, _root, node);
} }
@@ -325,8 +323,8 @@ protected:
if (n == _root) { // Only recolor if not the root node if (n == _root) { // Only recolor if not the root node
_color(n) = c; _color(n) = c;
} }
_color(left(n)) = !_color(left(n)) ; _color(_left(n)) = !_color(_left(n)) ;
_color(right(n)) = !_color(right(n)); _color(_right(n)) = !_color(_right(n));
} }
// run-of-the-mill bst insert // run-of-the-mill bst insert
@@ -335,7 +333,7 @@ protected:
value_t val(fennec::forward<ArgsT>(args)...); value_t val(fennec::forward<ArgsT>(args)...);
if (_root == npos) { if (_root == npos) {
return _root = insert_left(npos, node_t(fennec::move(val), red)); return _root = base_t::emplace(npos, false, fennec::move(val), red);
} }
size_t i = _root; size_t i = _root;
@@ -344,49 +342,50 @@ protected:
p = i; p = i;
if (_compare(val, _value(i))) { if (_compare(val, _value(i))) {
i = left(i); i = _left(i);
} else if (_compare(_value(i), val)) { } else if (_compare(_value(i), val)) {
i = right(i); i = _right(i);
} else { } else {
return i; return npos;
} }
} }
if (_compare(val, _value(p))) { bool d = _compare(val, _value(p));
return insert_left(p, node_t(fennec::move(val), red)); return base_t::emplace(p, !d, fennec::move(val), red);
} else {
return insert_right(p, node_t(fennec::move(val), red));
}
} }
// This makes some cheats given that the structure is modified only by internal functions // This makes some cheats given that the structure is modified only by internal functions
// If such is the case, ONLY LL, LR, RL, and RR will show up // If such is the case, ONLY LL, LR, RL, and RR will show up
// Then we just need to handle splitting a 4-node // Then we just need to handle splitting a 4-node
constexpr void _fix_insert(size_t n) { constexpr void _fix_insert(size_t n) {
size_t p = parent(n); if (n == npos) {
return;
}
size_t p = _parent(n);
while (n != _root && color(n) == red && color(p) == red) { while (n != _root && color(n) == red && color(p) == red) {
size_t g = parent(p); size_t g = _parent(p);
bool d = n == right(p); bool d = n == _right(p);
bool r = p == right(g); bool r = p == _right(g);
size_t u = child(g, !r); size_t u = _child(g, !r);
if (color(u) == red) { if (color(u) == red) {
_recolor(g); _recolor(g);
n = g; n = g;
p = parent(n); p = _parent(n);
continue; continue;
} }
if (d != r) { if (d != r) {
rotate(p, r); rotate(p, r);
n = p; n = p;
p = parent(n); p = _parent(n);
} }
rotate(g, not r); rotate(g, not r);
fennec::swap(_color(p), _color(g)); fennec::swap(_color(p), _color(g));
n = p; n = p;
p = parent(n); p = _parent(n);
} }
_color(_root) = black; _color(_root) = black;
} }
@@ -451,13 +450,13 @@ protected:
} }
size_t o = n; size_t o = n;
size_t p = parent(n); size_t p = _parent(n);
if (p == npos) { if (p == npos) {
_root = npos; _root = npos;
return; return;
} }
bool d = n == right(p); bool d = n == _right(p);
size_t c = _red_child(n); size_t c = _red_child(n);
size_t s = npos; size_t s = npos;
if (_color(n) == red || c != npos) { if (_color(n) == red || c != npos) {