diff --git a/xo-alloc/include/xo/alloc/GC.hpp b/xo-alloc/include/xo/alloc/GC.hpp index 092f2f36..be2ff071 100644 --- a/xo-alloc/include/xo/alloc/GC.hpp +++ b/xo-alloc/include/xo/alloc/GC.hpp @@ -318,7 +318,8 @@ namespace xo { * @param rhs. new target for @p *lhs **/ virtual void assign_member(IObject * parent, IObject ** lhs, IObject* rhs) final override; - + /** evacuate @p *lhs and replace with forwarding pointer **/ + virtual void forward_inplace(IObject ** lhs) final override; /** during GC check for source objects owned by GC. * See Object::_shallow_move. **/ diff --git a/xo-alloc/src/alloc/GC.cpp b/xo-alloc/src/alloc/GC.cpp index ca2506d9..40234bf3 100644 --- a/xo-alloc/src/alloc/GC.cpp +++ b/xo-alloc/src/alloc/GC.cpp @@ -568,6 +568,12 @@ namespace xo { } } + void + GC::forward_inplace(IObject ** lhs) + { + Object::_forward_inplace(lhs, this); + } + bool GC::check_owned(IObject * src) const { diff --git a/xo-alloc/src/alloc/Object.cpp b/xo-alloc/src/alloc/Object.cpp index 82583a0a..75abec14 100644 --- a/xo-alloc/src/alloc/Object.cpp +++ b/xo-alloc/src/alloc/Object.cpp @@ -24,7 +24,8 @@ namespace xo { Object::mm = nullptr; IObject * - Object::_forward(IObject * src, gc::IAlloc * gc) + Object::_forward(IObject * src, + gc::IAlloc * gc) { if (!src) return src; diff --git a/xo-allocutil/include/xo/allocutil/IAlloc.hpp b/xo-allocutil/include/xo/allocutil/IAlloc.hpp index 4f9097f7..a322e1db 100644 --- a/xo-allocutil/include/xo/allocutil/IAlloc.hpp +++ b/xo-allocutil/include/xo/allocutil/IAlloc.hpp @@ -76,7 +76,7 @@ namespace xo { std::byte * allocate(std::size_t n) { return this->alloc(n); } - + /** std::allocator locality hint. Not used for now **/ std::byte * allocate(std::size_t n, const void * hint) { (void)hint; @@ -147,6 +147,8 @@ namespace xo { virtual void assign_member(IObject * /*parent*/, IObject ** lhs, IObject * rhs) { *lhs = rhs; } + /** if GC: evacuate @p *lhs and replace with forwarding pointer **/ + virtual void forward_inplace(IObject ** lhs) { (void)lhs; } /** allocate @p z bytes for copy of object at @p src. * Only used in @ref GC. Default implementation asserts and returns nullptr **/ @@ -170,7 +172,7 @@ namespace xo { using const_reference = const T &; using size_type = IAlloc::size_type; using difference_type = std::ptrdiff_t; - + using gc_object_interface = IAlloc::gc_object_interface; using has_incremental_gc_interface = IAlloc::has_incremental_gc_interface; diff --git a/xo-allocutil/include/xo/allocutil/IObject.hpp b/xo-allocutil/include/xo/allocutil/IObject.hpp index 87c60130..21048884 100644 --- a/xo-allocutil/include/xo/allocutil/IObject.hpp +++ b/xo-allocutil/include/xo/allocutil/IObject.hpp @@ -19,6 +19,9 @@ namespace xo { **/ class IObject { public: + /** impl inheriting this class must provide gc hooks **/ + static constexpr bool _requires_gc_hooks = true; + /** true iff this object represents a forwarding pointer. * Forwarding pointers are exclusively created by the garbage collector; * forwarding pointers (and only forwarding pointers) return true here. diff --git a/xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp b/xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp index dd1a6322..38e7f384 100644 --- a/xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp +++ b/xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp @@ -32,7 +32,7 @@ namespace xo { * provide garbage collection * - xo::gc::GC has a collection API and also provides * garbage collection - * + * * GC-allocated objects must: * 2a. inherit A::object_interface * 2b. implement A::object_interface::_shallow_size() @@ -40,7 +40,7 @@ namespace xo { * 2d. implement A::object_interface::_forward_children(alloc) * in multiple inheritance scenarios * 2e. implement A::object_interface::_offset_destination(src) - * + * * Design Notes: * - virtual-method choice requires vtable pointer per object; * but zero *marginal* space cost for types that would have @@ -82,12 +82,16 @@ namespace xo { // gc_allocator_traits::template object_interface // template - struct object_interface {}; + struct object_interface { + /** see also IObject::_requires_gc_hooks **/ + static constexpr bool _requires_gc_hooks = false; + }; // specialization when A provides gc_object_interface template struct object_interface> - : A::gc_object_interface {}; + : public A::gc_object_interface { + }; /** true iff this allocator advertises itself as an incremental collector * allocator will include: @@ -97,7 +101,6 @@ namespace xo { * }; **/ static inline constexpr bool has_incremental_gc_interface_v = has_incremental_gc_interface::value; - }; } /*namespace gc*/ } /*namespace xo*/ diff --git a/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp b/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp index c1cca7ec..453ae5d3 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp @@ -8,6 +8,7 @@ #include "RbTypes.hpp" #include "xo/reflect/Reflect.hpp" #include "xo/indentlog/scope.hpp" +#include "xo/allocutil/IAlloc.hpp" #include "xo/allocutil/IObject.hpp" #include "xo/allocutil/gc_allocator_traits.hpp" #include @@ -301,7 +302,7 @@ namespace xo { xtag("r2", this->reduced2())); } /*local_recalc_size*/ - private: + private: void assign_color(Color x) { this->color_ = x; } void assign_size(size_t z) { this->size_ = z; } @@ -344,20 +345,49 @@ namespace xo { } /*replace_child_reparent*/ // ----- (possibly) 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); } - /* note: only relevant when GcObjectInterface is xo::IObject */ - template - virtual IObject * _shallow_copy(gc::IAlloc * gc) const - -> std::enable_if_t(this)); + } + virtual void display(std::ostream & os) const { + os << ""; } + virtual std::size_t _shallow_size() const { return sizeof(*this); } + /* note: only relevant when GcObjectInterface is xo::IObject */ + virtual IObject * _shallow_copy(gc::IAlloc * gc) const { + if constexpr (GcObjectInterface::_requires_gc_hooks) { + xo::Cpof cpof(gc, this); + return new (cpof) Node(*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) { + static_assert(std::is_convertible_v, + "parent_ must be convertible to IObject*"); + static_assert(std::is_convertible_v, + "child_v_[0] must be convertible to IObject*"); + + gc->forward_inplace(reinterpret_cast(&parent_)); + gc->forward_inplace(reinterpret_cast(&child_v_[0])); + gc->forward_inplace(reinterpret_cast(&child_v_[1])); + + // how do we tell if any of + // {value_type, ReducedValue} + // also contain pointers that need forwarding? + + return Node::_shallow_size(); + } else { + assert(false && "_forward_children assumes gc enabled"); + return 0ul; + } + } + + private: friend class RbTreeUtil; template friend class xo::tree::RedBlackTree;