diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b2b026..9c10270 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,15 @@ xo_add_genfacet( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacet( + TARGET xo-alloc2-facet-gcobjectvisitor + FACET GCObjectVisitor + INPUT idl/GCObjectVisitor.json5 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacet( TARGET xo-alloc2-facet-resourcevisitor diff --git a/idl/GCObjectVisitor.json5 b/idl/GCObjectVisitor.json5 new file mode 100644 index 0000000..b465842 --- /dev/null +++ b/idl/GCObjectVisitor.json5 @@ -0,0 +1,75 @@ +{ + mode: "facet", + output_cpp_dir: "src/alloc2/facet", + output_hpp_dir: "include/xo/alloc2", + output_impl_subdir: "gc", + includes: [ +// "", +// "", +// "", +// "", + ], + // extra includes in GCObject.hpp, if any + user_hpp_includes: [ +// "\"gc/RCollector_aux.hpp\"", + ], + namespace1: "xo", + namespace2: "mm", + pretext: [ + "// see GCObject.hpp, also in xo-alloc2/", + "namespace xo { namespace mm { class AGCObject; }}", + ], + facet: "GCObjectVisitor", + detail_subdir: "gc", + brief: "gc-aware object visitor", + using_doxygen: true, + doc: [ + "Visit a gc-aware object. Visitor can traverse and update child pointers in-place." + ], + types: [ + // using size_type = std::size_t +// { +// name: "size_type", +// doc: ["type for an amount of memory"], +// definition: "std::size_t", +// }, +// { +// name: "AAllocator", +// doc: ["fomo allocator type"], +// definition: "xo::mm::AAllocator", +// }, +// { +// name: "ACollector", +// doc: ["fomo collector type"], +// definition: "xo::mm::ACollector", +// }, + ], + const_methods: [ + // size_type shallow_size() const noexcept +// { +// name: "shallow_size", +// doc: ["memory consumption for this instance"], +// return_type: "size_type", +// args: [], +// const: true, +// noexcept: true, +// attributes: [], +// }, + ], + nonconst_methods: [ + // void visit_child(AGCObject * iface, void ** pp_data) noexcept; + { + name: "visit_child", + doc: ["visit child of a gc-aware object. May update child in-place!"], + return_type: "void", + args:[ + {type: "AGCObject *", name: "iface"}, + {type: "void **", name: "pp_data"}, + ], + const: true, // technical const. I/face not modified + noexcept: true, + attributes: [], + }, + ], + router_facet_explicit_content: [] +} diff --git a/include/xo/alloc2/GCObjectVisitor.hpp b/include/xo/alloc2/GCObjectVisitor.hpp new file mode 100644 index 0000000..7805cc9 --- /dev/null +++ b/include/xo/alloc2/GCObjectVisitor.hpp @@ -0,0 +1,22 @@ +/** @file GCObjectVisitor.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/GCObjectVisitor.json5] + * 2. jinja2 template for facet .hpp file: + * [facet.hpp.j2] + * 3. idl for facet methods + * [idl/GCObjectVisitor.json5] + **/ + +#pragma once + +#include "gc/AGCObjectVisitor.hpp" +#include "gc/IGCObjectVisitor_Any.hpp" +#include "gc/IGCObjectVisitor_Xfer.hpp" +#include "gc/RGCObjectVisitor.hpp" + + +/* end GCObjectVisitor.hpp */ diff --git a/include/xo/alloc2/gc/AGCObjectVisitor.hpp b/include/xo/alloc2/gc/AGCObjectVisitor.hpp new file mode 100644 index 0000000..b533076 --- /dev/null +++ b/include/xo/alloc2/gc/AGCObjectVisitor.hpp @@ -0,0 +1,79 @@ +/** @file AGCObjectVisitor.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/GCObjectVisitor.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [abstract_facet.hpp.j2] + * 3. idl for facet methods + * [idl/GCObjectVisitor.json5] + **/ + +#pragma once + +// includes (via {facet_includes}) +#include +#include +#include + +// see GCObject.hpp, also in xo-alloc2/ +namespace xo { namespace mm { class AGCObject; }} + +namespace xo { +namespace mm { + +using Copaque = const void *; +using Opaque = void *; + +/** +Visit a gc-aware object. Visitor can traverse and update child pointers in-place. +**/ +class AGCObjectVisitor { +public: + /** @defgroup mm-gcobjectvisitor-type-traits **/ + ///@{ + // types + /** integer identifying a type **/ + using typeseq = xo::facet::typeseq; + using Copaque = const void *; + using Opaque = void *; + ///@} + + /** @defgroup mm-gcobjectvisitor-methods **/ + ///@{ + // const methods + /** An uninitialized AGCObjectVisitor instance will have zero vtable pointer (per {linux,osx} abi). + * Use case for this is narrow. We go to some lengths to avoid null vtable pointers. For example + * obj will have non-null vtable (via IFacet_Any) with all methods terminating. + **/ + bool _has_null_vptr() const noexcept { return *reinterpret_cast(this) == nullptr; } + /** RTTI: unique id# for actual runtime data representation **/ + virtual typeseq _typeseq() const noexcept = 0; + /** destroy instance @p d; calls c++ dtor only for actual runtime type; does not recover memory **/ + virtual void _drop(Opaque d) const noexcept = 0; + + // nonconst methods + /** visit child of a gc-aware object. May update child in-place! **/ + virtual void visit_child(Opaque data, AGCObject * iface, void ** pp_data) const noexcept = 0; + ///@} +}; /*AGCObjectVisitor*/ + +/** Implementation IGCObjectVisitor_DRepr of AGCObjectVisitor for state DRepr + * should provide a specialization: + * + * template <> + * struct xo::facet::FacetImplementation { + * using Impltype = IGCObjectVisitor_DRepr; + * }; + * + * then IGCObjectVisitor_ImplType --> IGCObjectVisitor_DRepr + **/ +template +using IGCObjectVisitor_ImplType = xo::facet::FacetImplType; + +} /*namespace mm*/ +} /*namespace xo*/ + +/* AGCObjectVisitor.hpp */ diff --git a/include/xo/alloc2/gc/IGCObjectVisitor_Any.hpp b/include/xo/alloc2/gc/IGCObjectVisitor_Any.hpp new file mode 100644 index 0000000..287252c --- /dev/null +++ b/include/xo/alloc2/gc/IGCObjectVisitor_Any.hpp @@ -0,0 +1,88 @@ +/** @file IGCObjectVisitor_Any.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/GCObjectVisitor.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/GCObjectVisitor.json5] + **/ + +#pragma once + +#include "AGCObjectVisitor.hpp" +#include + +namespace xo { namespace mm { class IGCObjectVisitor_Any; } } + +namespace xo { +namespace facet { + +template <> +struct FacetImplementation +{ + using ImplType = xo::mm::IGCObjectVisitor_Any; +}; + +} +} + +namespace xo { +namespace mm { + + /** @class IGCObjectVisitor_Any + * @brief AGCObjectVisitor implementation for empty variant instance + **/ + class IGCObjectVisitor_Any : public AGCObjectVisitor { + public: + /** @defgroup mm-gcobjectvisitor-any-type-traits **/ + ///@{ + + /** integer identifying a type **/ + using typeseq = xo::facet::typeseq; + + ///@} + /** @defgroup mm-gcobjectvisitor-any-methods **/ + ///@{ + + const AGCObjectVisitor * iface() const { return std::launder(this); } + + // from AGCObjectVisitor + + // builtin methods + typeseq _typeseq() const noexcept override { return s_typeseq; } + [[noreturn]] void _drop(Opaque) const noexcept override { _fatal(); } + + // const methods + + // nonconst methods + [[noreturn]] void visit_child(Opaque, AGCObject *, void **) const noexcept override; + + ///@} + + private: + /** @defgraoup mm-gcobjectvisitor-any-private-methods **/ + ///@{ + + [[noreturn]] static void _fatal(); + + ///@} + + public: + /** @defgroup mm-gcobjectvisitor-any-member-vars **/ + ///@{ + + static typeseq s_typeseq; + static bool _valid; + + ///@} + }; + +} /*namespace mm */ +} /*namespace xo */ + +/* IGCObjectVisitor_Any.hpp */ diff --git a/include/xo/alloc2/gc/IGCObjectVisitor_Xfer.hpp b/include/xo/alloc2/gc/IGCObjectVisitor_Xfer.hpp new file mode 100644 index 0000000..aa9b476 --- /dev/null +++ b/include/xo/alloc2/gc/IGCObjectVisitor_Xfer.hpp @@ -0,0 +1,82 @@ +/** @file IGCObjectVisitor_Xfer.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/GCObjectVisitor.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/GCObjectVisitor.json5] + **/ + +#pragma once + + +namespace xo { +namespace mm { + /** @class IGCObjectVisitor_Xfer + **/ + template + class IGCObjectVisitor_Xfer : public AGCObjectVisitor { + public: + /** @defgroup mm-gcobjectvisitor-xfer-type-traits **/ + ///@{ + /** actual implementation (not generated; often delegates to DRepr) **/ + using Impl = IGCObjectVisitor_DRepr; + /** integer identifying a type **/ + using typeseq = AGCObjectVisitor::typeseq; + ///@} + + /** @defgroup mm-gcobjectvisitor-xfer-methods **/ + ///@{ + + static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; } + static DRepr & _dcast(Opaque d) { return *(DRepr *)d; } + + // from AGCObjectVisitor + + // builtin methods + typeseq _typeseq() const noexcept override { return s_typeseq; } + void _drop(Opaque d) const noexcept override { _dcast(d).~DRepr(); } + + // const methods + + // non-const methods + void visit_child(Opaque data, AGCObject * iface, void ** pp_data) const noexcept override { + return I::visit_child(_dcast(data), iface, pp_data); + } + + ///@} + + private: + using I = Impl; + + public: + /** @defgroup mm-gcobjectvisitor-xfer-member-vars **/ + ///@{ + + /** typeseq for template parameter DRepr **/ + static typeseq s_typeseq; + /** true iff satisfies facet implementation **/ + static bool _valid; + + ///@} + }; + + template + xo::facet::typeseq + IGCObjectVisitor_Xfer::s_typeseq + = xo::facet::typeseq::id(); + + template + bool + IGCObjectVisitor_Xfer::_valid + = xo::facet::valid_facet_implementation(); + +} /*namespace mm */ +} /*namespace xo*/ + +/* end IGCObjectVisitor_Xfer.hpp */ diff --git a/include/xo/alloc2/gc/RGCObjectVisitor.hpp b/include/xo/alloc2/gc/RGCObjectVisitor.hpp new file mode 100644 index 0000000..800d197 --- /dev/null +++ b/include/xo/alloc2/gc/RGCObjectVisitor.hpp @@ -0,0 +1,84 @@ +/** @file RGCObjectVisitor.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/GCObjectVisitor.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/GCObjectVisitor.json5] + **/ + +#pragma once + +#include "AGCObjectVisitor.hpp" + +namespace xo { +namespace mm { + +/** @class RGCObjectVisitor + **/ +template +class RGCObjectVisitor : public Object { +private: + using O = Object; + +public: + /** @defgroup mm-gcobjectvisitor-router-type-traits **/ + ///@{ + using ObjectType = Object; + using DataPtr = Object::DataPtr; + using typeseq = xo::reflect::typeseq; + ///@} + + /** @defgroup mm-gcobjectvisitor-router-ctors **/ + ///@{ + RGCObjectVisitor() {} + RGCObjectVisitor(Object::DataPtr data) : Object{std::move(data)} {} + RGCObjectVisitor(const AGCObjectVisitor * iface, void * data) + requires std::is_same_v + : Object(iface, data) {} + + ///@} + /** @defgroup mm-gcobjectvisitor-router-methods **/ + ///@{ + + // explicit injected content + + // builtin methods + typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); } + void _drop() const noexcept { O::iface()->_drop(O::data()); } + + // const methods + + // non-const methods (still const in router!) + void visit_child(AGCObject * iface, void ** pp_data) noexcept { + return O::iface()->visit_child(O::data(), iface, pp_data); + } + + ///@} + /** @defgroup mm-gcobjectvisitor-member-vars **/ + ///@{ + + static bool _valid; + + ///@} +}; + +template +bool +RGCObjectVisitor::_valid = xo::facet::valid_object_router(); + +} /*namespace mm*/ +} /*namespace xo*/ + +namespace xo { namespace facet { + template + struct RoutingFor { + using RoutingType = xo::mm::RGCObjectVisitor; + }; +} } + +/* end RGCObjectVisitor.hpp */ diff --git a/src/alloc2/CMakeLists.txt b/src/alloc2/CMakeLists.txt index 8399d1b..7929371 100644 --- a/src/alloc2/CMakeLists.txt +++ b/src/alloc2/CMakeLists.txt @@ -9,7 +9,9 @@ set(SELF_SRCS CollectorTypeRegistry.cpp facet/ICollector_Any.cpp + IGCObject_Any.cpp + facet/IGCObjectVisitor_Any.cpp AAllocator.cpp IAllocator_Any.cpp diff --git a/src/alloc2/facet/IGCObjectVisitor_Any.cpp b/src/alloc2/facet/IGCObjectVisitor_Any.cpp new file mode 100644 index 0000000..53d13ca --- /dev/null +++ b/src/alloc2/facet/IGCObjectVisitor_Any.cpp @@ -0,0 +1,48 @@ +/** @file IGCObjectVisitor_Any.cpp + * + **/ + +#include "gc/IGCObjectVisitor_Any.hpp" +#include +#include + +namespace xo { +namespace mm { + +using xo::facet::DVariantPlaceholder; +using xo::facet::typeseq; +using xo::facet::valid_facet_implementation; + +void +IGCObjectVisitor_Any::_fatal() +{ + /* control here on uninitialized IAllocator_Any. + * Initialized instance will have specific implementation type + */ + std::cerr << "fatal" + << ": attempt to call uninitialized" + << " IGCObjectVisitor_Any method" + << std::endl; + std::terminate(); +} + +typeseq +IGCObjectVisitor_Any::s_typeseq = typeseq::id(); + +bool +IGCObjectVisitor_Any::_valid + = valid_facet_implementation(); + +// nonconst methods + +auto +IGCObjectVisitor_Any::visit_child(Opaque, AGCObject *, void **) const noexcept -> void +{ + _fatal(); +} + + +} /*namespace mm*/ +} /*namespace xo*/ + +/* end IGCObjectVisitor_Any.cpp */