- 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()
value = self.tree[node]['value']
left = self.tree[node]['left']
right = self.tree[node]['right']
left = self.tree[node]['child'][0]
right = self.tree[node]['child'][1]
if right < self.capacity:
self.visit.appendleft((right, 1, depth + 1))

View File

@@ -63,31 +63,28 @@ public:
protected:
struct node {
value_t value;
size_t parent, left, right;
size_t depth;
size_t parent;
size_t child[2];
constexpr node()
: value(nullopt)
, parent(npos), left(npos), right(npos)
, depth(0) {
: value()
, parent(npos), child{ npos, npos } {
}
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)...)
, parent(p), left(l), right(r)
, depth(d) {
, parent(p), child{ l, r } {
}
constexpr ~node() {
parent = npos;
left = npos;
right = npos;
depth = npos;
parent = npos;
child[0] = npos;
child[1] = npos;
}
size_t& operator[](bool d) {
return d ? right : left;
return child[d];
}
};
@@ -204,7 +201,7 @@ public:
/// \param i The node id
/// \returns The left child of node `i`
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
/// \returns The right child of node `i`
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
/// \returns The child in the direction specified by `dir`
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
/// \returns The id of the sibling of `i`
constexpr size_t sibling(size_t i) const {
size_t p = parent(i);
size_t l = left(p);
size_t r = right(p);
return i == l ? r : l;
if (i == npos) {
return npos;
}
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
/// \returns The depth of node `i`
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()) {
return npos;
}
while (_table[i].left != npos) {
i = _table[i].left;
while (_table[i].child[false] != npos) {
i = _table[i].child[false];
}
return i;
}
@@ -273,8 +280,8 @@ public:
if (i >= _table.size()) {
return npos;
}
while (_table[i].right != npos) {
i = _table[i].right;
while (_table[i].right[false] != npos) {
i = _table[i].right[false];
}
return i;
}
@@ -375,71 +382,19 @@ public:
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
/// \param i The root node for the rotation
/// \param dir The direction to rotate, `true` for right, `false` for left
constexpr size_t rotate(size_t sub, bool dir) {
if (sub >=_table.size()) {
if (sub == npos) {
return npos;
}
size_t sub_parent = parent(sub);
size_t new_root = child(sub, not dir);
size_t new_child = child(new_root, dir);
size_t sub_parent = _parent(sub);
size_t new_root = _child(sub, not dir);
size_t new_child = _child(new_root, dir);
_child(sub, not dir) = new_child;
if (new_child != npos) {
@@ -457,6 +412,40 @@ public:
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
constexpr void clear() {
@@ -470,11 +459,11 @@ public:
size_t i = queue.front();
queue.pop_front();
if (_table[i].left != npos) {
queue.push_front(_table[i].left);
if (_right(i) != npos) {
queue.push_front(_right(i));
}
if (_table[i].right != npos) {
queue.push_front(_table[i].right);
if (_left(i) != npos) {
queue.push_front(_left(i));
}
fennec::destruct(&_table[i]);
@@ -761,16 +750,14 @@ protected:
if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
} else {
size_t d = 1;
i = _next_free();
if (p != npos) {
d = depth(p) + 1;
_table[p].left = i;
_left(p) = i;
}
if (_root == npos) {
_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;
}
@@ -780,24 +767,38 @@ protected:
size_t i = p == npos ? _root : _right(p);
if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
if (p == npos || _root == npos) {
_root = i;
}
} else {
size_t d = 1;
i = _next_free();
if (p != npos) {
d = depth(p) + 1;
_table[p].right = i;
_right(p) = i;
}
if (_root == npos) {
_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;
}
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) {
return _table[i].parent;
@@ -808,19 +809,19 @@ protected:
}
constexpr size_t& _left(size_t i) {
return _table[i].left;
return _table[i].child[false];
}
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) {
return dir ? _right(i) : _left(i);
return _table[i].child[dir];
}
constexpr size_t& _sibling(size_t i) {
size_t p = parent(i);
size_t p = _parent(i);
size_t& l = _left(p);
size_t& r = _right(p);
return i == l ? l : r;

View File

@@ -109,12 +109,10 @@ protected:
using base_t::left_most;
using base_t::right_most;
using base_t::insert_left;
using base_t::insert_right;
using base_t::emplace_left;
using base_t::emplace_right;
using base_t::rotate;
using base_t::rotate_left;
using base_t::rotate_right;
using base_t::_table;
using base_t::_freed;
@@ -159,9 +157,9 @@ public:
size_t node = _root;
while (node != npos) {
if (_compare(val, _value(node))) {
node = left(node);
node = _left(node);
} else if (_compare(_value(node), val)) {
node = right(node);
node = _right(node);
} else {
return sequence::iterator(this, _root, node);
}
@@ -325,8 +323,8 @@ protected:
if (n == _root) { // Only recolor if not the root node
_color(n) = c;
}
_color(left(n)) = !_color(left(n)) ;
_color(right(n)) = !_color(right(n));
_color(_left(n)) = !_color(_left(n)) ;
_color(_right(n)) = !_color(_right(n));
}
// run-of-the-mill bst insert
@@ -335,7 +333,7 @@ protected:
value_t val(fennec::forward<ArgsT>(args)...);
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;
@@ -344,49 +342,50 @@ protected:
p = i;
if (_compare(val, _value(i))) {
i = left(i);
i = _left(i);
} else if (_compare(_value(i), val)) {
i = right(i);
i = _right(i);
} else {
return i;
return npos;
}
}
if (_compare(val, _value(p))) {
return insert_left(p, node_t(fennec::move(val), red));
} else {
return insert_right(p, node_t(fennec::move(val), red));
}
bool d = _compare(val, _value(p));
return base_t::emplace(p, !d, fennec::move(val), red);
}
// 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
// Then we just need to handle splitting a 4-node
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) {
size_t g = parent(p);
bool d = n == right(p);
bool r = p == right(g);
size_t u = child(g, !r);
size_t g = _parent(p);
bool d = n == _right(p);
bool r = p == _right(g);
size_t u = _child(g, !r);
if (color(u) == red) {
_recolor(g);
n = g;
p = parent(n);
p = _parent(n);
continue;
}
if (d != r) {
rotate(p, r);
n = p;
p = parent(n);
p = _parent(n);
}
rotate(g, not r);
fennec::swap(_color(p), _color(g));
n = p;
p = parent(n);
p = _parent(n);
}
_color(_root) = black;
}
@@ -451,13 +450,13 @@ protected:
}
size_t o = n;
size_t p = parent(n);
size_t p = _parent(n);
if (p == npos) {
_root = npos;
return;
}
bool d = n == right(p);
bool d = n == _right(p);
size_t c = _red_child(n);
size_t s = npos;
if (_color(n) == red || c != npos) {