From 113869342cc3ca5d3b21b295457379bd55448a69 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 3 Dec 2025 17:13:11 -0500 Subject: [PATCH] xo-ordinaltree: RedBlackTree is gc-alloc-aware --- .../include/xo/ordinaltree/RedBlackTree.hpp | 59 +++++++++++++++++-- .../xo/ordinaltree/rbtree/NullReduce.hpp | 13 +++- .../xo/ordinaltree/rbtree/OrdinalReduce.hpp | 11 +++- .../xo/ordinaltree/rbtree/SumReduce.hpp | 14 ++++- 4 files changed, 88 insertions(+), 9 deletions(-) diff --git a/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp b/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp index 52f448ec..273b30fe 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp @@ -58,7 +58,7 @@ namespace xo { typename Value, typename Reduce, typename Allocator> - class RedBlackTree { + class RedBlackTree : public xo::gc::gc_allocator_traits::template object_interface { static_assert(ordered_key); static_assert(valid_rbtree_reduce_functor); @@ -87,6 +87,9 @@ namespace xo { using iterator = detail::Iterator; using const_iterator = detail::ConstIterator; + using Reflect = xo::reflect::Reflect; + using TaggedPtr = xo::reflect::TaggedPtr; + public: explicit RedBlackTree(const allocator_type & alloc = allocator_type{}, bool debug_flag = false) : @@ -115,6 +118,21 @@ namespace xo { {} #endif + static RedBlackTree * make(const allocator_type & alloc = allocator_type{}, + bool debug_flag = false) + { + RedBlackTree * tree = allocator_traits::allocate(alloc, 1); + try { + // placement new + allocator_traits::construct(alloc, tree, alloc, debug_flag); + return tree; + } catch(...) { + allocator_traits::deallocate(alloc, tree, 1); + } + + return nullptr; + } + bool empty() const { return size_ == 0; } size_type size() const { return size_; } size_type max_size() const { return std::numeric_limits::max(); } @@ -551,23 +569,52 @@ namespace xo { return true; } /*verify_ok*/ - void display() const { RbUtil::display(this->root_, 0); } /*display*/ + void display_to_log() const { RbUtil::display(this->root_, 0); } /*display*/ - private: + // ----- Inherited from GcObjectInterface ----- + virtual TaggedPtr self_tp() const { + return Reflect::make_tp(const_cast(this)); + } + virtual void display(std::ostream & os) const { + os << ""; + } + virtual std::size_t _shallow_size() const { return sizeof(*this); } + virtual IObject * _shallow_copy(gc::IAlloc * gc) const { + if constexpr (GcObjectInterface::_requires_gc_hooks) { + xo::Cpof cpof(gc, this); + return new (cpof) RedBlackTree(*this); + } else { + assert(false && "_shallow_copy assumes gc enabled"); + return nullptr; + } + } + virtual std::size_t _forward_children(gc::IAlloc * gc) { + if constexpr (GcObjectInterface::_requires_gc_hooks) { + using xo::gc::ObjectVisitor; + + ObjectVisitor::forward_children(reduce_fn_, gc); + gc->forward_inplace(reinterpret_cast(&root_)); + + return RedBlackTree::_shallow_size(); + } else { + assert(false && "_forward_children assumes gc enabled"); + return 0ul; + } + } private: /** allocator state **/ node_allocator_type node_alloc_; /** number of nodes in this tree. Each node holds one (key,value) pair **/ size_t size_ = 0; - /** root of red/black tree. Empty tree has null root. **/ - RbNode * root_ = nullptr; /** accumulates custom order statistics; * for example partial sums of @tparam Values * reduce_fn_:: (Accumulator x Key) -> Accumulator **/ Reduce reduce_fn_; + /** root of red/black tree. Empty tree has null root. **/ + RbNode * root_ = nullptr; /** true to enable debug logging **/ bool debug_flag_ = false; }; /*RedBlackTree*/ @@ -580,7 +627,7 @@ namespace xo { operator<<(std::ostream & os, RedBlackTree const & tree) { - tree.display(); + tree.display(os); return os; } /*operator<<*/ diff --git a/xo-ordinaltree/include/xo/ordinaltree/rbtree/NullReduce.hpp b/xo-ordinaltree/include/xo/ordinaltree/rbtree/NullReduce.hpp index 383359d3..c61c150e 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/rbtree/NullReduce.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/rbtree/NullReduce.hpp @@ -5,6 +5,7 @@ #pragma once +#include "xo/allocutil/ObjectVisitor.hpp" #include namespace xo { @@ -34,12 +35,22 @@ namespace xo { }; /*NullReduce*/ inline std::ostream & operator<<(std::ostream & os, - null_reduce_value /*x*/) + null_reduce_value /*x*/) { os << "{}"; return os; } /*operator<<*/ } /*namespace tree*/ + + namespace gc { + template + class ObjectVisitor> { + public: + static_assert(std::is_empty_v>); + + static void forward_children(xo::tree::NullReduce &, xo::gc::IAlloc *) {} + }; + } /*namespace gc*/ } /*namespace xo*/ /* end NullReduce.hpp */ diff --git a/xo-ordinaltree/include/xo/ordinaltree/rbtree/OrdinalReduce.hpp b/xo-ordinaltree/include/xo/ordinaltree/rbtree/OrdinalReduce.hpp index 920478ff..88d97d64 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/rbtree/OrdinalReduce.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/rbtree/OrdinalReduce.hpp @@ -37,8 +37,17 @@ namespace xo { value_type combine(value_type x, value_type y) const { return x + y; } bool is_equal(value_type x, value_type y) const { return x == y; } }; /*OrdinalReduce*/ - } /*namespace tree*/ + + namespace gc { + template + class ObjectVisitor> { + public: + static_assert(std::is_empty_v>); + + static void forward_children(xo::tree::OrdinalReduce &, xo::gc::IAlloc *) {} + }; + } /*namespace gc*/ } /*namespace xo*/ /* end OrdinalReduce.hpp */ diff --git a/xo-ordinaltree/include/xo/ordinaltree/rbtree/SumReduce.hpp b/xo-ordinaltree/include/xo/ordinaltree/rbtree/SumReduce.hpp index d58ea237..d4e21425 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/rbtree/SumReduce.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/rbtree/SumReduce.hpp @@ -6,6 +6,7 @@ #pragma once +#include "xo/allocutil/ObjectVisitor.hpp" #include namespace xo { @@ -48,7 +49,18 @@ namespace xo { bool is_equal(value_type const & x, value_type const & y) const { return x == y; } }; /*SumReduce*/ - } + } /*namespace tree*/ + + namespace gc { + template + class ObjectVisitor> { + public: + static_assert(std::is_empty_v>); + + /* trivial, since SumReduce is stateless */ + static void forward_children(xo::tree::SumReduce &, xo::gc::IAlloc *) {} + }; + } /*namespace gc*/ } /* end SumReduce.hpp */