refactor: + narrower interface for gc pointer forwarding

add AGCObjectVisitor, instead of requiring ACollector.
This commit is contained in:
Roland Conybeare 2026-04-05 23:53:02 -04:00
commit 90ab86f69c
9 changed files with 115 additions and 13 deletions

View file

@ -6,6 +6,7 @@
includes: [
"<xo/alloc2/Allocator.hpp>",
"<xo/alloc2/Collector.hpp>",
"<xo/alloc2/GCObjectVisitor.hpp>",
"<cstdint>",
"<cstddef>",
],
@ -42,6 +43,11 @@
doc: ["fomo collector type"],
definition: "xo::mm::ACollector",
},
{
name: "AGCObjectVisitor",
doc: ["fomo collector type"],
definition: "xo::mm::AGCObjectVisitor",
},
],
const_methods: [
// size_type shallow_size() const noexcept
@ -68,13 +74,17 @@
noexcept: true,
attributes: [],
},
// size_type forward_children(obj<ACollector>) noexcept
// size_type visit_gco_children(obj<AGCObjectVisitor>) noexcept
{
name: "forward_children",
doc: ["during GC: forward immdiate children"],
name: "visit_gco_children",
doc: [
"Invoke fn.visit_child(iface,data) for each child GCObject pointer.",
"Context: provides address of data pointer so it can be updated in place",
"when @p fn invokes garbage collector reentry point"
],
return_type: "void",
args: [
{type: "obj<ACollector>", name: "gc"},
{type: "obj<AGCObjectVisitor>", name: "fn"},
],
const: true,
noexcept: true,

View file

@ -71,5 +71,26 @@
attributes: [],
},
],
router_facet_explicit_content: []
router_facet_explicit_content: [
"",
"/** visit forward faceted object child pointer in place.",
" Defined in RGCObject.hpp to avoid #include cycle",
" **/",
"template <typename DRepr>",
"void visit_child(xo::facet::obj<AGCObject,DRepr> * p_obj);",
"",
"/** visit typed child data pointer in place.",
" Defined in RGCObject.hpp to avoid #include cycle",
" **/",
"template <typename DRepr>",
"void visit_child(DRepr ** pp_data);",
"",
"/** visit faceted object pointer stored using some facet",
" other than AGCObject",
" **/",
"template <typename AFacet, typename DRepr>",
"requires (!std::is_same_v<AFacet, AGCObject>)",
"void visit_poly_child(obj<AFacet,DRepr> * p_pivot);",
"",
]
}

View file

@ -16,6 +16,7 @@
// includes (via {facet_includes})
#include <xo/alloc2/Allocator.hpp>
#include <xo/alloc2/Collector.hpp>
#include <xo/alloc2/GCObjectVisitor.hpp>
#include <cstdint>
#include <cstddef>
#include <xo/facet/obj.hpp>
@ -48,6 +49,8 @@ public:
using AAllocator = xo::mm::AAllocator;
/** fomo collector type **/
using ACollector = xo::mm::ACollector;
/** fomo collector type **/
using AGCObjectVisitor = xo::mm::AGCObjectVisitor;
///@}
/** @defgroup mm-gcobject-methods **/
@ -66,8 +69,10 @@ public:
// nonconst methods
/** move instance using allocator **/
virtual Opaque shallow_move(Opaque data, obj<ACollector> gc) const noexcept = 0;
/** during GC: forward immdiate children **/
virtual void forward_children(Opaque data, obj<ACollector> gc) const noexcept = 0;
/** Invoke fn.visit_child(iface,data) for each child GCObject pointer.
Context: provides address of data pointer so it can be updated in place
when @p fn invokes garbage collector reentry point **/
virtual void visit_gco_children(Opaque data, obj<AGCObjectVisitor> fn) const noexcept = 0;
///@}
}; /*AGCObject*/

View file

@ -47,6 +47,7 @@ namespace mm {
using size_type = AGCObject::size_type;
using AAllocator = AGCObject::AAllocator;
using ACollector = AGCObject::ACollector;
using AGCObjectVisitor = AGCObject::AGCObjectVisitor;
///@}
/** @defgroup mm-gcobject-any-methods **/
@ -64,7 +65,7 @@ namespace mm {
// nonconst methods
[[noreturn]] Opaque shallow_move(Opaque, obj<ACollector>) const noexcept override;
[[noreturn]] void forward_children(Opaque, obj<ACollector>) const noexcept override;
[[noreturn]] void visit_gco_children(Opaque, obj<AGCObjectVisitor>) const noexcept override;
///@}

View file

@ -15,6 +15,7 @@
#include <xo/alloc2/Allocator.hpp>
#include <xo/alloc2/Collector.hpp>
#include <xo/alloc2/GCObjectVisitor.hpp>
#include <cstdint>
#include <cstddef>
@ -34,6 +35,7 @@ namespace mm {
using size_type = AGCObject::size_type;
using AAllocator = AGCObject::AAllocator;
using ACollector = AGCObject::ACollector;
using AGCObjectVisitor = AGCObject::AGCObjectVisitor;
///@}
/** @defgroup mm-gcobject-xfer-methods **/
@ -54,8 +56,8 @@ namespace mm {
Opaque shallow_move(Opaque data, obj<ACollector> gc) const noexcept override {
return I::shallow_move(_dcast(data), gc);
}
void forward_children(Opaque data, obj<ACollector> gc) const noexcept override {
return I::forward_children(_dcast(data), gc);
void visit_gco_children(Opaque data, obj<AGCObjectVisitor> fn) const noexcept override {
return I::visit_gco_children(_dcast(data), fn);
}
///@}

View file

@ -17,6 +17,46 @@ namespace xo {
class ACollector;
class AGCObject;
/** defined here to avoid #include cycle, since
* template obj<AGCObject,DRepr> awkward to make available
* in RCollector.hpp
**/
template <typename Object>
template <typename DRepr>
void
RGCObjectVisitor<Object>::visit_child(xo::facet::obj<AGCObject,DRepr> * p_obj)
{
this->visit_child(p_obj->iface(), (void **)&(p_obj->data_));
}
template <typename Object>
template <typename DRepr>
void
RGCObjectVisitor<Object>::visit_child(DRepr ** p_repr)
{
// fetch static interface for DRepr (strip const: FacetImplementation specializations use non-const DRepr)
auto iface = xo::facet::impl_for<AGCObject, std::remove_const_t<DRepr>>();
this->visit_child(&iface, (void **)p_repr);
}
template <typename Object>
template <typename AFacet, typename DRepr>
requires (!std::is_same_v<AFacet, AGCObject>)
void
RGCObjectVisitor<Object>::visit_poly_child(obj<AFacet, DRepr> * p_objs)
{
if (*p_objs) {
auto e = xo::facet::FacetRegistry::instance().variant<AGCObject,AFacet>(*p_objs);
this->visit_child(e.iface(), (void **)&(p_objs->data_));
}
}
// ----- DEPRECATED -----
//
// Moving these methods to RGCObjectVisitor
/** defined here to avoid #include cycle, since
* template obj<AGCObject,DRepr> awkward to make available
* in RCollector.hpp
@ -52,6 +92,8 @@ namespace xo {
}
}
// ----- mm_do_assign -----
/** gc-aware assignment; engage special book-keeping for cross-gen pointers **/
inline void mm_do_assign(obj<ACollector> & gc,
void * parent,

View file

@ -34,6 +34,7 @@ public:
using size_type = AGCObject::size_type;
using AAllocator = AGCObject::AAllocator;
using ACollector = AGCObject::ACollector;
using AGCObjectVisitor = AGCObject::AGCObjectVisitor;
///@}
/** @defgroup mm-gcobject-router-ctors **/
@ -60,8 +61,8 @@ public:
Opaque shallow_move(obj<ACollector> gc) noexcept {
return O::iface()->shallow_move(O::data(), gc);
}
void forward_children(obj<ACollector> gc) noexcept {
return O::iface()->forward_children(O::data(), gc);
void visit_gco_children(obj<AGCObjectVisitor> fn) noexcept {
return O::iface()->visit_gco_children(O::data(), fn);
}
///@}

View file

@ -46,6 +46,26 @@ public:
///@{
// explicit injected content
/** visit forward faceted object child pointer in place.
Defined in RGCObject.hpp to avoid #include cycle
**/
template <typename DRepr>
void visit_child(xo::facet::obj<AGCObject,DRepr> * p_obj);
/** visit typed child data pointer in place.
Defined in RGCObject.hpp to avoid #include cycle
**/
template <typename DRepr>
void visit_child(DRepr ** pp_data);
/** visit faceted object pointer stored using some facet
other than AGCObject
**/
template <typename AFacet, typename DRepr>
requires (!std::is_same_v<AFacet, AGCObject>)
void visit_poly_child(obj<AFacet,DRepr> * p_pivot);
// builtin methods
typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); }

View file

@ -42,7 +42,7 @@ IGCObject_Any::shallow_move(Opaque, obj<ACollector>) const noexcept -> Opaque
}
auto
IGCObject_Any::forward_children(Opaque, obj<ACollector>) const noexcept -> void
IGCObject_Any::visit_gco_children(Opaque, obj<AGCObjectVisitor>) const noexcept -> void
{
_fatal();
}