From 18c81718476e272a10a3476812b2685236ad3748 Mon Sep 17 00:00:00 2001 From: Medusa Slockbower Date: Thu, 18 Sep 2025 21:34:29 -0400 Subject: [PATCH] - 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. --- gdb/fennec/containers.py | 4 +- include/fennec/containers/bintree.h | 201 ++++++++++++++------------- include/fennec/containers/sequence.h | 53 ++++--- 3 files changed, 129 insertions(+), 129 deletions(-) diff --git a/gdb/fennec/containers.py b/gdb/fennec/containers.py index f398186..eac8f1f 100644 --- a/gdb/fennec/containers.py +++ b/gdb/fennec/containers.py @@ -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)) diff --git a/include/fennec/containers/bintree.h b/include/fennec/containers/bintree.h index 617ea62..d75546d 100644 --- a/include/fennec/containers/bintree.h +++ b/include/fennec/containers/bintree.h @@ -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 - 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(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(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(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 + constexpr size_t emplace(size_t p, bool d, ArgsT&&...args) { + return this->_insert(p, d, fennec::forward(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(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(args)...); + fennec::construct(&_table[i], p, npos, npos, fennec::forward(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(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(args)...); + fennec::construct(&_table[i], p, npos, npos, fennec::forward(args)...); } return i; } + template + 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(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(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; diff --git a/include/fennec/containers/sequence.h b/include/fennec/containers/sequence.h index 207f14c..93a6e5d 100644 --- a/include/fennec/containers/sequence.h +++ b/include/fennec/containers/sequence.h @@ -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(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) {