diff --git a/idl/GCObject.json5 b/idl/GCObject.json5 index 4374758..0bbb170 100644 --- a/idl/GCObject.json5 +++ b/idl/GCObject.json5 @@ -1,24 +1,26 @@ { mode: "facet", - output_cpp_dir: "src/gc", - output_hpp_dir: "include/xo/gc", - output_impl_subdir: "detail", + output_cpp_dir: "src/alloc2", + output_hpp_dir: "include/xo/alloc2", + output_impl_subdir: "gc", includes: [ "", - "", + "", "", "", ], // extra includes in GCObject.hpp, if any - user_hpp_includes: [], + user_hpp_includes: [ + "\"gc/RCollector_aux.hpp\"", + ], namespace1: "xo", namespace2: "mm", pretext: [ "namespace xo { namespace mm { class ACollector; }}", ], facet: "GCObject", - detail_subdir: "detail", - brief: "xxx", + detail_subdir: "gc", + brief: "gc-aware object, providing collector hooks", using_doxygen: true, doc: [ "GC hooks for collector-aware data" diff --git a/include/xo/alloc2/GCObject.hpp b/include/xo/alloc2/GCObject.hpp index b7758ac..4733b01 100644 --- a/include/xo/alloc2/GCObject.hpp +++ b/include/xo/alloc2/GCObject.hpp @@ -18,30 +18,6 @@ #include "gc/IGCObject_Xfer.hpp" #include "gc/RGCObject.hpp" -namespace xo { - namespace mm { - /** defined here to avoid #include cycle, since - * template obj awkward to make available there - **/ - template - template - void - RCollector::forward_inplace(xo::facet::obj * p_obj) - { - this->forward_inplace(p_obj->iface(), (void **)&(p_obj->data_)); - } - - template - template - void - RCollector::forward_inplace(DRepr ** p_repr) - { - // fetch static interface for DRepr - auto iface = xo::facet::impl_for(); - - this->forward_inplace(&iface, (void **)p_repr); - } - } -} +#include "gc/RCollector_aux.hpp" /* end GCObject.hpp */ diff --git a/include/xo/alloc2/GCObjectConversion.hpp b/include/xo/alloc2/GCObjectConversion.hpp new file mode 100644 index 0000000..59ec12f --- /dev/null +++ b/include/xo/alloc2/GCObjectConversion.hpp @@ -0,0 +1,117 @@ +/** @file GCObjectConversion.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace xo { + namespace scm { + /** @brief compile-time conversion obj <-> T + * + * Specialize for each T that participates in conversion. + * Methods here aren't implemented + **/ + template + struct GCObjectConversion { + using AGCObject = xo::mm::AGCObject; + using AAllocator = xo::mm::AAllocator; + + /** find gc-aware representation for @p x. + * If necessary allocate from @p mm, but may + * refer to @p x in-place + **/ + static obj to_gco(obj mm, const T & x); + /** convert to native representation @tparam T from gc-aware + * @p gco. If necessary allocate from @p mm, but + * may instead refer to @p x in-place + **/ + static T from_gco(obj mm, obj gco); + }; + + /** Motivating use-case for GCObjectConversion is to transform + * primitive function arguments and results to/from gc-aware + * representation. + * + * However: Schematika also supports runtime polymorphism + * which leads to primitives that expect obj arguments. + * + * Also, Schematika expression parser needs representation for + * expressions, before type unification. + * + * Consider a function like: + * def fact = lambda (n : i64) { if (n <= 0) then 1 else (n * fact(n - 1)); } + * During expression parsing the rhs argument to multiply has unknown type. + * To construct an expression for input to unification will use polymorphic + * binding for multiply primitive, relying on specialization here for + * its implementation. + **/ + template + struct GCObjectConversion> { + using AGCObject = xo::mm::AGCObject; + using AAllocator = xo::mm::AAllocator; + using FacetRegistry = xo::facet::FacetRegistry; + using DVariantPlaceholder = xo::facet::DVariantPlaceholder; + + static obj to_gco(obj, + obj gco) { + if constexpr (std::is_same_v) { + // trivial conversion! + return gco; + } else if constexpr (std::is_same_v) { + // runtime polymorphism + return FacetRegistry::instance().variant(gco); + } else /* DRepr != DVariantPlaceholder */ { + // known content w/ fat object pointer + return obj(gco.data()); + } + } + + static obj from_gco(obj, + obj gco) { + scope log(XO_DEBUG(false)); + + if constexpr (std::is_same_v) { + // Need accurate handling of DVariantPlaceholder. + // runtime type must be some concrete type. + // Only use obj::from when DRepr is a concrete type + + if constexpr (std::is_same_v) { + // At comptime gco has unknown repr. At runtime + // will have some known repr, which assignment here will transfer + return gco; + } else { + // Runtime conversion to concrete type DRepr + + auto retval = obj::from(gco); + + if (!retval) { + log.retroactively_enable(); + + log && log(xtag("gco.tseq", gco._typeseq())); + log && log(xtag("DRepr.tseq", reflect::typeseq::id())); + } + + assert(retval); + + return retval; + } + } else { + // both runtime and comptime polymorphism + // use same path here, since representation of @p gco + // is type-erased here + + return FacetRegistry::instance().variant(gco); + } + } + }; + } /*namespace scm */ +} /*namespace xo*/ + +/* end GCObjectConversion.hpp */ diff --git a/include/xo/alloc2/gc/AGCObject.hpp b/include/xo/alloc2/gc/AGCObject.hpp index 87fc666..c420f0f 100644 --- a/include/xo/alloc2/gc/AGCObject.hpp +++ b/include/xo/alloc2/gc/AGCObject.hpp @@ -31,7 +31,7 @@ using Copaque = const void *; using Opaque = void *; /** - GC hooks for collector-aware data +GC hooks for collector-aware data **/ class AGCObject { public: diff --git a/include/xo/alloc2/gc/RCollector_aux.hpp b/include/xo/alloc2/gc/RCollector_aux.hpp new file mode 100644 index 0000000..b85c73b --- /dev/null +++ b/include/xo/alloc2/gc/RCollector_aux.hpp @@ -0,0 +1,40 @@ +/** @file RCollector_aux.hpp + * + * Out-of-line definitions for RCollector template methods + * that depend on RGCObject (avoiding #include cycle in RCollector.hpp). + * + * Included via user_hpp_includes in GCObject.json5. + * + * @author Roland Conybeare + **/ + +#pragma once + +namespace xo { + namespace mm { + /** defined here to avoid #include cycle, since + * template obj awkward to make available + * in RCollector.hpp + **/ + template + template + void + RCollector::forward_inplace(xo::facet::obj * p_obj) + { + this->forward_inplace(p_obj->iface(), (void **)&(p_obj->data_)); + } + + template + template + void + RCollector::forward_inplace(DRepr ** p_repr) + { + // fetch static interface for DRepr + auto iface = xo::facet::impl_for(); + + this->forward_inplace(&iface, (void **)p_repr); + } + } +} + +/* end RCollector_aux.hpp */ diff --git a/include/xo/gc/GCObject.hpp b/include/xo/gc/GCObject.hpp deleted file mode 100644 index 759e937..0000000 --- a/include/xo/gc/GCObject.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/** @file GCObject.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/GCObject.json5] - * 2. jinja2 template for facet .hpp file: - * [facet.hpp.j2] - * 3. idl for facet methods - * [idl/GCObject.json5] - **/ - -#pragma once - -#include "detail/AGCObject.hpp" -#include "detail/IGCObject_Any.hpp" -#include "detail/IGCObject_Xfer.hpp" -#include "detail/RGCObject.hpp" - - -/* end GCObject.hpp */ diff --git a/include/xo/gc/detail/AGCObject.hpp b/include/xo/gc/detail/AGCObject.hpp deleted file mode 100644 index 6f6e7b9..0000000 --- a/include/xo/gc/detail/AGCObject.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/** @file AGCObject.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/GCObject.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [abstract_facet.hpp.j2] - * 3. idl for facet methods - * [idl/GCObject.json5] - **/ - -#pragma once - -// includes (via {facet_includes}) -#include -#include -#include -#include -#include -#include -#include - -namespace xo { namespace mm { class ACollector; }} - -namespace xo { -namespace mm { - -using Copaque = const void *; -using Opaque = void *; - -/** -GC hooks for collector-aware data -**/ -class AGCObject { -public: - /** @defgroup mm-gcobject-type-traits **/ - ///@{ - // types - /** integer identifying a type **/ - using typeseq = xo::facet::typeseq; - using Copaque = const void *; - using Opaque = void *; - /** type for an amount of memory **/ - using size_type = std::size_t; - /** fomo allocator type **/ - using AAllocator = xo::mm::AAllocator; - /** fomo collector type **/ - using ACollector = xo::mm::ACollector; - ///@} - - /** @defgroup mm-gcobject-methods **/ - ///@{ - // const methods - /** 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; - /** memory consumption for this instance **/ - virtual size_type shallow_size(Copaque data) const noexcept = 0; - /** copy instance using allocator **/ - virtual Opaque shallow_copy(Copaque data, obj mm) const noexcept = 0; - - // nonconst methods - /** during GC: forward immdiate children **/ - virtual size_type forward_children(Opaque data, obj gc) const noexcept = 0; - ///@} -}; /*AGCObject*/ - -/** Implementation IGCObject_DRepr of AGCObject for state DRepr - * should provide a specialization: - * - * template <> - * struct xo::facet::FacetImplementation { - * using Impltype = IGCObject_DRepr; - * }; - * - * then IGCObject_ImplType --> IGCObject_DRepr - **/ -template -using IGCObject_ImplType = xo::facet::FacetImplType; - -} /*namespace mm*/ -} /*namespace xo*/ - -/* AGCObject.hpp */ diff --git a/include/xo/gc/detail/IGCObject_Any.hpp b/include/xo/gc/detail/IGCObject_Any.hpp deleted file mode 100644 index 9ff7bb2..0000000 --- a/include/xo/gc/detail/IGCObject_Any.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/** @file IGCObject_Any.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/GCObject.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_any.hpp.j2] - * 3. idl for facet methods - * [idl/GCObject.json5] - **/ - -#pragma once - -#include "AGCObject.hpp" -#include - -namespace xo { namespace mm { class IGCObject_Any; } } - -namespace xo { -namespace facet { - -template <> -struct FacetImplementation -{ - using ImplType = xo::mm::IGCObject_Any; -}; - -} -} - -namespace xo { -namespace mm { - - /** @class IGCObject_Any - * @brief AGCObject implementation for empty variant instance - **/ - class IGCObject_Any : public AGCObject { - public: - /** @defgroup mm-gcobject-any-type-traits **/ - ///@{ - - /** integer identifying a type **/ - using typeseq = xo::facet::typeseq; - using size_type = AGCObject::size_type; - using AAllocator = AGCObject::AAllocator; - using ACollector = AGCObject::ACollector; - - ///@} - /** @defgroup mm-gcobject-any-methods **/ - ///@{ - - const AGCObject * iface() const { return std::launder(this); } - - // from AGCObject - - // builtin methods - typeseq _typeseq() const noexcept override { return s_typeseq; } - [[noreturn]] void _drop(Opaque) const noexcept override { _fatal(); } - - // const methods - [[noreturn]] size_type shallow_size(Copaque) const noexcept override { _fatal(); } - [[noreturn]] Opaque shallow_copy(Copaque, obj) const noexcept override { _fatal(); } - - // nonconst methods - [[noreturn]] size_type forward_children(Opaque, obj) const noexcept override; - - ///@} - - private: - /** @defgraoup mm-gcobject-any-private-methods **/ - ///@{ - - [[noreturn]] static void _fatal(); - - ///@} - - public: - /** @defgroup mm-gcobject-any-member-vars **/ - ///@{ - - static typeseq s_typeseq; - static bool _valid; - - ///@} - }; - -} /*namespace mm */ -} /*namespace xo */ - -/* IGCObject_Any.hpp */ diff --git a/include/xo/gc/detail/IGCObject_Xfer.hpp b/include/xo/gc/detail/IGCObject_Xfer.hpp deleted file mode 100644 index 7f094ab..0000000 --- a/include/xo/gc/detail/IGCObject_Xfer.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/** @file IGCObject_Xfer.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/GCObject.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_any.hpp.j2] - * 3. idl for facet methods - * [idl/GCObject.json5] - **/ - -#pragma once - -#include -#include -#include -#include - -namespace xo { -namespace mm { - /** @class IGCObject_Xfer - **/ - template - class IGCObject_Xfer : public AGCObject { - public: - /** @defgroup mm-gcobject-xfer-type-traits **/ - ///@{ - /** actual implementation (not generated; often delegates to DRepr) **/ - using Impl = IGCObject_DRepr; - /** integer identifying a type **/ - using typeseq = AGCObject::typeseq; - using size_type = AGCObject::size_type; - using AAllocator = AGCObject::AAllocator; - using ACollector = AGCObject::ACollector; - ///@} - - /** @defgroup mm-gcobject-xfer-methods **/ - ///@{ - - static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; } - static DRepr & _dcast(Opaque d) { return *(DRepr *)d; } - - // from AGCObject - - // builtin methods - typeseq _typeseq() const noexcept override { return s_typeseq; } - void _drop(Opaque d) const noexcept override { _dcast(d).~DRepr(); } - - // const methods - size_type shallow_size(Copaque data) const noexcept override { - return I::shallow_size(_dcast(data)); - } - Opaque shallow_copy(Copaque data, obj mm) const noexcept override { - return I::shallow_copy(_dcast(data), mm); - } - - // non-const methods - size_type forward_children(Opaque data, obj gc) const noexcept override { - return I::forward_children(_dcast(data), gc); - } - - ///@} - - private: - using I = Impl; - - public: - /** @defgroup mm-gcobject-xfer-member-vars **/ - ///@{ - - /** typeseq for template parameter DRepr **/ - static typeseq s_typeseq; - /** true iff satisfies facet implementation **/ - static bool _valid; - - ///@} - }; - - template - xo::facet::typeseq - IGCObject_Xfer::s_typeseq - = xo::facet::typeseq::id(); - - template - bool - IGCObject_Xfer::_valid - = xo::facet::valid_facet_implementation(); - -} /*namespace mm */ -} /*namespace xo*/ - -/* end IGCObject_Xfer.hpp */ diff --git a/include/xo/gc/detail/RGCObject.hpp b/include/xo/gc/detail/RGCObject.hpp deleted file mode 100644 index d24994a..0000000 --- a/include/xo/gc/detail/RGCObject.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/** @file RGCObject.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/GCObject.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_any.hpp.j2] - * 3. idl for facet methods - * [idl/GCObject.json5] - **/ - -#pragma once - -#include "AGCObject.hpp" - -namespace xo { -namespace mm { - -/** @class RGCObject - **/ -template -class RGCObject : public Object { -private: - using O = Object; - -public: - /** @defgroup mm-gcobject-router-type-traits **/ - ///@{ - using ObjectType = Object; - using DataPtr = Object::DataPtr; - using typeseq = xo::reflect::typeseq; - using size_type = AGCObject::size_type; - using AAllocator = AGCObject::AAllocator; - using ACollector = AGCObject::ACollector; - ///@} - - /** @defgroup mm-gcobject-router-ctors **/ - ///@{ - RGCObject() {} - RGCObject(Object::DataPtr data) : Object{std::move(data)} {} - RGCObject(const AGCObject * iface, void * data) - requires std::is_same_v - : Object(iface, data) {} - - ///@} - /** @defgroup mm-gcobject-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 - size_type shallow_size() const noexcept { - return O::iface()->shallow_size(O::data()); - } - Opaque shallow_copy(obj mm) const noexcept { - return O::iface()->shallow_copy(O::data(), mm); - } - - // non-const methods (still const in router!) - size_type forward_children(obj gc) noexcept { - return O::iface()->forward_children(O::data(), gc); - } - - ///@} - /** @defgroup mm-gcobject-member-vars **/ - ///@{ - - static bool _valid; - - ///@} -}; - -template -bool -RGCObject::_valid = xo::facet::valid_object_router(); - -} /*namespace mm*/ -} /*namespace xo*/ - -namespace xo { namespace facet { - template - struct RoutingFor { - using RoutingType = xo::mm::RGCObject; - }; -} } - -/* end RGCObject.hpp */