From 375492ef7b2489cda01ce3dfa065a473b2dd44ce Mon Sep 17 00:00:00 2001 From: Medusa Slockbower Date: Sun, 31 Aug 2025 14:38:05 -0400 Subject: [PATCH] - "Finished" sequence.h, there's more to do, but the basic functionality is there - bintree.h is implemented according to the needs of sequence.h at present --- gdb/fennec/containers.py | 64 +++++++++++++++- include/fennec/containers/bintree.h | 65 ++++++++++++++++ include/fennec/containers/sequence.h | 104 +++++++++++++++++++++++++- test/tests/containers/test_sequence.h | 3 + 4 files changed, 231 insertions(+), 5 deletions(-) diff --git a/gdb/fennec/containers.py b/gdb/fennec/containers.py index d716940..4b4abe4 100644 --- a/gdb/fennec/containers.py +++ b/gdb/fennec/containers.py @@ -371,7 +371,7 @@ class RDTreePrinter: index += '└' index += '─' - index += '[{}, {}]'.format(node, i) + index += '[{}]'.format(node) return index, value @@ -389,6 +389,66 @@ class RDTreePrinter: return self.Iterator(self.tree, 0, self.capacity) +# BINTREE ============================================================================================================== + +class BinTreePrinter: + """Print a fennec::bintree""" + + class Iterator: + def __init__(self, tree, node, capacity): + self.tree = tree + self.capacity = capacity + self.visit = deque() + + self.visit.append((node, 0, 0)) + + def __iter__(self): + return self + + def __next__(self): + if len(self.visit) == 0: + raise StopIteration + + node = self.visit[0][0] + i = self.visit[0][1] + depth = self.visit[0][2] + self.visit.popleft() + + value = self.tree[node]['value'] + left = self.tree[node]['left'] + right = self.tree[node]['right'] + + if right < self.capacity: + self.visit.appendleft((right, 1, depth + 1)) + if left < self.capacity: + self.visit.appendleft((left, 0, depth + 1)) + + index = '⠀' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers + if i == 0: + index += '├' + else: + index += '└' + + index += '─' + index += '[{}]'.format(node) + return index, value + + + def __init__(self, val): + self.tree = val['_table']['_data'] + self.size = val['_size'] + self.root = val['_root'] + self.capacity = val['_table']['_capacity'] + + def to_string(self): + if self.size == 0: + return "{ empty }" + return "{ size = " + str(self.size) + " }" + + def children(self): + return self.Iterator(self.tree, self.root, self.capacity) + + # Graph ================================================================================================================ class GraphPrinter: @@ -475,6 +535,8 @@ def register_printers(): pp.add_printer('fennec::pair', '^fennec::pair<.*>$', PairPrinter) pp.add_printer('fennec::set', '^fennec::set<.*>$', SetPrinter) pp.add_printer('fennec::rdtree', '^fennec::rdtree<.*>$', RDTreePrinter) + pp.add_printer('fennec::bintree', '^fennec::bintree<.*>$', BinTreePrinter) + pp.add_printer('fennec::sequence', '^fennec::sequence<.*>$', BinTreePrinter) pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter) return pp diff --git a/include/fennec/containers/bintree.h b/include/fennec/containers/bintree.h index 0ee28bc..58d2502 100644 --- a/include/fennec/containers/bintree.h +++ b/include/fennec/containers/bintree.h @@ -86,6 +86,10 @@ protected: right = npos; depth = npos; } + + size_t& operator[](bool d) { + return d ? right : left; + } }; using table_t = allocation; @@ -144,6 +148,12 @@ public: return _size; } + /// + /// \returns `true` when there are no elements in the tree, `false` otherwise. + constexpr bool empty() const { + return _size == 0; + } + /// /// \returns The capacity of the underlying allocation constexpr size_t capacity() const { @@ -206,6 +216,27 @@ public: return i >= _table.size() ? npos : _table[i].right; } + /// + /// \details \f$O(1)\f$ + /// \param i The node id + /// \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); + } + + /// + /// \details \f$O(1)\f$ + /// \param i The node id + /// \returns `true` if `i` is the right node of `parent(i)`, `false` otherwise + constexpr bool direction(size_t i) const { + size_t p = parent(i); + if (p >= _table.capacity()) { + return false; + } + return i == right(p); + } + /// /// \brief \f$O(1)\f$ /// \param i The id of the node @@ -415,6 +446,32 @@ public: _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()) { + return npos; + } + 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; + parent(new_child) = sub; + child(new_root, dir) = sub; + + parent(new_root) = sub_parent; + parent(sub) = new_root; + if (sub_parent != npos) { + child(sub_parent, sub == right(sub_parent)) = new_root; + } else { + _root = new_root; + } + return new_root; + } + /// /// \brief Clears the tree, destroying all elements constexpr void clear() { @@ -640,6 +697,10 @@ public: _order(*tree, root); } + size_t index() const { + return _n; + } + iterator& operator++() { return _n = _order[*_tree, _n, traversal_control_continue], *this; } @@ -745,6 +806,10 @@ protected: return i >= _table.size() ? sink : _table[i].right; } + constexpr size_t& child(size_t i, bool dir) { + return dir ? right(i) : left(i); + } + constexpr size_t& sibling(size_t i) { size_t p = parent(i); size_t& l = left(p); diff --git a/include/fennec/containers/sequence.h b/include/fennec/containers/sequence.h index 9c270fc..5e0d9b2 100644 --- a/include/fennec/containers/sequence.h +++ b/include/fennec/containers/sequence.h @@ -92,18 +92,25 @@ protected: using base_t::left; using base_t::right; + using base_t::child; + using base_t::direction; using base_t::parent; using base_t::grandparent; using base_t::sibling; using base_t::parsib; + using base_t::left_most; + using base_t::right_most; + using base_t::insert_left; using base_t::insert_right; + using base_t::rotate; using base_t::rotate_left; using base_t::rotate_right; using base_t::_table; + using base_t::_freed; using base_t::_root; using base_t::_size; @@ -179,6 +186,10 @@ public: /// \returns The capacity of the underlying allocation using base_t::capacity; + /// + /// \returns `true` when there are no elements in the sequence, `false` otherwise. + using base_t::empty; + /// @} // Modifiers =========================================================================================================== @@ -213,8 +224,7 @@ public: } constexpr void erase(const value_t& val) { - size_t i = find(val)._n; - + _erase_bst(val); } /// @@ -289,11 +299,11 @@ protected: } constexpr bool& _color(size_t i) { - return i >= _table.capacity() ? color_sink : _table[i].value.second; + return i >= _table.capacity() ? color_sink = false : _table[i].value.second; } constexpr bool _color(size_t i) const { - return i >= _table.capacity() ? color_sink : _table[i].value.second; + return i >= _table.capacity() ? color_sink = false : _table[i].value.second; } template @@ -352,6 +362,92 @@ protected: } _color(_root) = black; } + + constexpr void _shift(size_t u, size_t v) { + if (parent(u) == npos) { + _root = v; + } else { + child(parent(u), direction(u)) = v; + } + if (v != npos) { + parent(v) = parent(u); + } + } + + constexpr void _erase_bst(const value_t& val) { + size_t z = find(val).index(); + size_t y = z; + size_t x = npos; + bool c = _color(y); + size_t p = npos; + + if (left(z) == npos) { + x = right(z); + p = parent(z); + _shift(z, x); + } else if (right(z) == npos) { + x = left(z); + p = parent(z); + _shift(z, x); + } else { + y = left_most(right(z)); + c = _color(y); + x = right(y); + p = (parent(y) == z) ? y : parent(y); + if (parent(y) != z) { + _shift(y, right(y)); + right(y) = right(z); + parent(right(y)) = y; + } + _shift(z, y); + left(y) = left(z); + if (left(y)) + parent(left(y)) = y; + _color(y) = _color(z); + } + + fennec::destruct(&_table[z]); + --_size; + + if (c == black) { + _fix_erase(x, p); + } + } + + constexpr void _fix_erase(size_t x, size_t p) { + while (x != _root && _color(x) == black) { + bool dir = direction(x); + size_t w = child(p, not dir); + + if (_color(w) == red) { + _color(w) = black; + _color(p) = red; + w = rotate(p, dir); + } + + if (w == npos || (_color(left(w)) == black && _color(right(w)) == black)) { + _color(w) = red; + x = p; + p = parent(x); + } else { + if (_color(child(w, not dir)) == black) { + _color(child(w, dir)) = black; + _color(w) = red; + rotate(w, not dir); + w = child(p, not dir); + } + + _color(w) = _color(p); + _color(p) = black; + _color(child(w, not dir)) = black; + rotate(p, dir); + x = _root; + break; + } + } + + _color(x) = black; + } }; } diff --git a/test/tests/containers/test_sequence.h b/test/tests/containers/test_sequence.h index b2d1008..2a74c8a 100644 --- a/test/tests/containers/test_sequence.h +++ b/test/tests/containers/test_sequence.h @@ -51,7 +51,10 @@ inline void fennec_test_containers_sequence() { for (size_t v : ref) { assertf(test.contains(v), "Failed Sequence Test!"); + test.erase(v); } + + fennec_test_run(test.empty(), true); } }