From 12f40c8049a38fb4e780867060fa4352b778a170 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 4 Dec 2025 23:38:56 -0500 Subject: [PATCH] xo-ordinaltree: rbtree ops satisfy gc write barriers --- xo-alloc/include/xo/alloc/Object.hpp | 2 +- .../include/xo/ordinaltree/RedBlackTree.hpp | 11 +-- .../include/xo/ordinaltree/rbtree/Node.hpp | 62 +++++-------- .../xo/ordinaltree/rbtree/RbTreeUtil.hpp | 90 ++++++++++--------- 4 files changed, 77 insertions(+), 88 deletions(-) diff --git a/xo-alloc/include/xo/alloc/Object.hpp b/xo-alloc/include/xo/alloc/Object.hpp index 742fba4c..5f31356f 100644 --- a/xo-alloc/include/xo/alloc/Object.hpp +++ b/xo-alloc/include/xo/alloc/Object.hpp @@ -121,7 +121,7 @@ namespace xo { virtual TaggedPtr self_tp() const; /** print on stream @p os **/ - virtual void display(std::ostream & os) const = 0; + virtual void display(std::ostream & os) const; // Inherited from IObject.. diff --git a/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp b/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp index 9bf4146d..6e1fba07 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp @@ -466,10 +466,11 @@ namespace xo { RbNode * adj_root = this->root_; std::pair insert_result - = RbUtil::insert_aux(kv_pair, - true /*allow_replace_flag*/, - this->reduce_fn_, - &adj_root); + = RbUtil::template insert_aux(this->node_alloc_, + kv_pair, + true /*allow_replace_flag*/, + this->reduce_fn_, + &adj_root); if (insert_result.first) { ++(this->size_); @@ -623,10 +624,10 @@ namespace xo { virtual TaggedPtr self_tp() const { return Reflect::make_tp(const_cast(this)); } -#endif virtual void display(std::ostream & os) const final override { os << ""; } +#endif virtual std::size_t _shallow_size() const final override { return sizeof(*this); } virtual IObject * _shallow_copy(gc::IAlloc * gc) const final override { if constexpr (GcObjectInterface::_requires_gc_hooks) { diff --git a/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp b/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp index 167bdca2..27048041 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp @@ -82,14 +82,6 @@ namespace xo { } } /*make_leaf*/ -#ifdef OBSOLETE - static Node * make_leaf(value_type && kv_pair, - ReducedValue const & leaf_rv) { - return new Node(kv_pair, - std::pair(leaf_rv, leaf_rv)); - } /*make_leaf*/ -#endif - /* return #of key/vaue pairs in tree rooted at x. */ static size_t tree_size(Node *x) { if (x) @@ -146,7 +138,7 @@ namespace xo { /* replace root pointer *pp_root with x; * set x parent pointer to nil */ - static void replace_root_reparent(Node *x, Node **pp_root) { + static void replace_root_reparent(Node * x, Node ** pp_root) { *pp_root = x; if (x) x->parent_ = nullptr; @@ -155,7 +147,11 @@ namespace xo { /** swap values of all members except @ref contents_ * between @p *lhs and @p *rhs **/ - static void swap_locations(Node * lhs, Node * rhs, bool debug_flag) { + template + static void swap_locations(NodeAllocator & alloc, + Node * lhs, + Node * rhs, + bool debug_flag) { scope log(XO_DEBUG(debug_flag)); assert(lhs->parent() != rhs->parent()); @@ -179,7 +175,7 @@ namespace xo { assert(lhs != rhs->right_child() && "expected left-to-right key order"); if (lhs_parent) - lhs_parent->replace_child_reparent(lhs, rhs); + lhs_parent->replace_child_reparent(alloc, lhs, rhs); /* now have: * - rhs->parent() = lhs_parent @@ -187,7 +183,7 @@ namespace xo { */ if (rhs_parent) - rhs_parent->replace_child_reparent(rhs, lhs); + rhs_parent->replace_child_reparent(alloc, rhs, lhs); /* now have: * - lhs->parent() = rhs_parent @@ -211,10 +207,10 @@ namespace xo { Node * rhs_left = rhs->left_child(); Node * rhs_right = rhs->right_child(); - lhs->assign_child_reparent(D_Left, rhs_left); - lhs->assign_child_reparent(D_Right, rhs_right); - rhs->assign_child_reparent(D_Left, lhs_left); - rhs->assign_child_reparent(D_Right, lhs_right); + lhs->assign_child_reparent(alloc, D_Left, rhs_left); + lhs->assign_child_reparent(alloc, D_Right, rhs_right); + rhs->assign_child_reparent(alloc, D_Left, lhs_left); + rhs->assign_child_reparent(alloc, D_Right, lhs_right); //std::swap(lhs->child_v_, rhs->child_v_); @@ -318,10 +314,10 @@ namespace xo { virtual TaggedPtr self_tp() const { return Reflect::make_tp(const_cast(this)); } -#endif virtual void display(std::ostream & os) const final override { os << ""; } +#endif virtual std::size_t _shallow_size() const final override { return sizeof(*this); } /* note: only relevant when GcObjectInterface is xo::IObject */ @@ -372,27 +368,10 @@ namespace xo { void assign_color(Color x) { this->color_ = x; } void assign_size(size_t z) { this->size_ = z; } - void assign_child_reparent(Direction d, Node *new_x) { - Node * old_x = this->child_v_[d]; - - // trying to fix old_x can be counterproductive, - // since old_x->parent_ may already have been corrected, - // - if (old_x && (old_x->parent_ == this)) { - old_x->parent_ = nullptr; - } - - this->child_v_[d] = new_x; - - if (new_x) { - new_x->parent_ = this; - } - } /*assign_child_reparent*/ - template - void assign_child_reparent_2(NodeAllocator & alloc, - Direction d, - Node * new_x) + void assign_child_reparent(NodeAllocator & alloc, + Direction d, + Node * new_x) { Node * old_x = this->child_v_[d]; @@ -429,11 +408,14 @@ namespace xo { * - x is nullptr or x.parent is nullptr * - x_new is nullptr or x_new.parent is this */ - Direction replace_child_reparent(Node *x, Node *x_new) { + template + Direction replace_child_reparent(NodeAllocator & alloc, + Node * x, + Node * x_new) { Direction d = this->child_direction(x); - if (d == D_Left || d == D_Right) { - this->assign_child_reparent(d, x_new); + if ((d == D_Left) || (d == D_Right)) { + this->assign_child_reparent(alloc, d, x_new); return d; } else { return D_Invalid; diff --git a/xo-ordinaltree/include/xo/ordinaltree/rbtree/RbTreeUtil.hpp b/xo-ordinaltree/include/xo/ordinaltree/rbtree/RbTreeUtil.hpp index 22539ff3..0545965a 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/rbtree/RbTreeUtil.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/rbtree/RbTreeUtil.hpp @@ -355,8 +355,10 @@ namespace xo { * (so any key k' in x satisfies k' > h->key) * */ - static RbNode *find_glb_aux(RbNode *x, RbNode *h, Key const &k, - bool is_closed) { + static RbNode * find_glb_aux(RbNode * x, + RbNode * h, + Key const & k, + bool is_closed) { for (;;) { if (!x) return h; @@ -458,24 +460,25 @@ namespace xo { * / \ / \ * T S S R */ - static RbNode *rotate(Direction d, RbNode *A, - Reduce const & reduce_fn, - RbNode **pp_root) { + template + static RbNode * rotate(NodeAllocator & alloc, + Direction d, + RbNode * A, + Reduce const & reduce_fn, + bool debug_flag, + RbNode ** pp_root) { using xo::scope; using xo::xtag; - //constexpr char const *c_self = "RbTreeUtil::rotate"; - constexpr bool c_logging_enabled = false; - - scope log(XO_DEBUG(c_logging_enabled)); + scope log(XO_DEBUG(debug_flag)); Direction other_d = other(d); - RbNode *G = A->parent(); - RbNode *B = A->child(other_d); - //RbNode *R = A->child(d); // not using - RbNode *S = B->child(d); - //RbNode *T = B->child(other_d); // not using + RbNode * G = A->parent(); + RbNode * B = A->child(other_d); + //RbNode * R = A->child(d); // not using + RbNode * S = B->child(d); + //RbNode * T = B->child(other_d); // not using if (log.enabled()) { log("rotate-", (d == D_Left) ? "left" : "right", @@ -493,14 +496,14 @@ namespace xo { } /* note: this will set A's old child B to have null parent ptr */ - A->assign_child_reparent(other_d, S); + A->assign_child_reparent(alloc, other_d, S); A->local_recalc_size(reduce_fn); - B->assign_child_reparent(d, A); + B->assign_child_reparent(alloc, d, A); B->local_recalc_size(reduce_fn); if (G) { - G->replace_child_reparent(A, B); + G->replace_child_reparent(alloc, A, B); assert(B->parent() == G); /* note: G.size not affected by rotation */ @@ -550,18 +553,20 @@ namespace xo { * Promise: * - tree is in RB-shape */ - static void fixup_red_shape(Direction d, RbNode *G, + template + static void fixup_red_shape(NodeAllocator & alloc, + Direction d, + RbNode * G, Reduce const & reduce_fn, - RbNode **pp_root) { + bool debug_flag, + RbNode ** pp_root) { using xo::scope; using xo::xtag; using xo::print::ccs; - //constexpr char const *c_self = "RbTreeUtil::fixup_red_shape"; - constexpr bool c_logging_enabled = false; constexpr bool c_excessive_verify_enabled = false; - scope log(XO_DEBUG(c_logging_enabled)); + scope log(XO_DEBUG(debug_flag)); RbNode *P = G->child(d); @@ -712,7 +717,7 @@ namespace xo { * / \ * R */ - RbTreeUtil::rotate(d, P, reduce_fn, pp_root); + RbTreeUtil::rotate(alloc, d, P, reduce_fn, debug_flag, pp_root); if (c_excessive_verify_enabled) RbTreeUtil::verify_subtree_ok(reduce_fn, S, nullptr /*&black_height*/); @@ -739,7 +744,7 @@ namespace xo { (other_d == D_Left) ? "left" : "right", " at G", xtag("G", G), xtag("G.key", G->key())); - RbTreeUtil::rotate(other_d, G, reduce_fn, pp_root); + RbTreeUtil::rotate(alloc, other_d, G, reduce_fn, debug_flag, pp_root); if (c_excessive_verify_enabled) { RbNode *GG = G ? G->parent() : G; @@ -759,7 +764,7 @@ namespace xo { return; } /*walk toward root until red violation fixed*/ - } /*fixup_red_shape*/ + } /*fixup_red_shape*/ /* insert key-value pair (key, value) into *pp_root. * on exit *pp_root contains new tree with (key, value) inserted. @@ -837,16 +842,16 @@ namespace xo { kv_pair, reduce_fn.leaf(kv_pair.second)); - N->assign_child_reparent_2(alloc, - d, - new_node); + N->assign_child_reparent(alloc, + d, + new_node); assert(is_red(N->child(d))); /* recalculate Node sizes on path [root .. N] */ RbTreeUtil::fixup_ancestor_size(reduce_fn, N, debug_flag); /* after adding a node, must rebalance to restore RB-shape */ - RbTreeUtil::fixup_red_shape(d, N, reduce_fn, pp_root); + RbTreeUtil::fixup_red_shape(alloc, d, N, reduce_fn, debug_flag, pp_root); //log && log(xtag("path", (char const *)"B")); @@ -918,7 +923,7 @@ namespace xo { /* d: direction in P to immediate child N; * also sets N.parent to nil */ - Direction d = P->replace_child_reparent(N, nullptr); + Direction d = P->replace_child_reparent(alloc, N, nullptr); traits::deallocate(alloc, N, 1); @@ -1100,7 +1105,7 @@ namespace xo { assert(is_black(P)); assert(is_black(N)); - RbTreeUtil::rotate(d, P, reduce_fn, pp_root); + RbTreeUtil::rotate(alloc, d, P, reduce_fn, debug_flag, pp_root); /* after rotation d at P: * @@ -1217,7 +1222,8 @@ namespace xo { * - D at h */ - RbTreeUtil::rotate(other_d, S, reduce_fn, pp_root); + RbTreeUtil::rotate(alloc, + other_d, S, reduce_fn, debug_flag, pp_root); assert(P->child(other_d) == C); @@ -1292,7 +1298,7 @@ namespace xo { * - S (+also C,D) at h */ - RbTreeUtil::rotate(d, P, reduce_fn, pp_root); + RbTreeUtil::rotate(alloc, d, P, reduce_fn, debug_flag, pp_root); /* after rotate at P toward d: * * @@ -1438,7 +1444,7 @@ namespace xo { * W */ if (P) - P->replace_child_reparent(N, R); + P->replace_child_reparent(alloc, N, R); /* * here the triangle ascii art indicates a tree structure, @@ -1452,8 +1458,8 @@ namespace xo { * / . R Y * W */ - R->assign_child_reparent(D_Left, N); - R->assign_child_reparent(D_Right, Y); + R->assign_child_reparent(alloc, D_Left, N); + R->assign_child_reparent(alloc, D_Right, Y); /* * here the triangle ascii art indicates a tree structure, * of arbitrary size @@ -1468,8 +1474,8 @@ namespace xo { * / \ * R Y */ - N->assign_child_reparent(D_Left, W); - N->assign_child_reparent(D_Right, nullptr); + N->assign_child_reparent(alloc, D_Left, W); + N->assign_child_reparent(alloc, D_Right, nullptr); /* * here the triangle ascii art indicates a tree structure, * of arbitrary size @@ -1519,7 +1525,7 @@ namespace xo { * everything except RbNode.contents_. * Annoying but necessary to have stable Node memory locations */ - RbNode::swap_locations(R, N, debug_flag); + RbNode::swap_locations(alloc, R, N, debug_flag); /* swapping locations invalidates RbNode.reduced_. * But correctness will be restored in erase_1child_aux() @@ -1592,7 +1598,7 @@ namespace xo { /* replace pointer to N with nil in N's parent. */ if (P) { - P->replace_child_reparent(N, nullptr); + P->replace_child_reparent(alloc, N, nullptr); log && log("fixup_ancestor_size starting at P"); RbTreeUtil::fixup_ancestor_size(reduce_fn, P, debug_flag); @@ -1613,7 +1619,7 @@ namespace xo { */ } } else /*N->is_black()*/ { - RbNode *R = N->left_child(); + RbNode * R = N->left_child(); if (!R) R = N->right_child(); @@ -1628,7 +1634,7 @@ namespace xo { R->assign_color(C_Black); if (P) { - P->replace_child_reparent(N, R); + P->replace_child_reparent(alloc, N, R); log && log("fixup_ancestor_size starting at P"); RbTreeUtil::fixup_ancestor_size(reduce_fn, P, debug_flag); } else {