diff --git a/idl/Collector.json5 b/idl/Collector.json5 index d49e6ad..f7b8d3c 100644 --- a/idl/Collector.json5 +++ b/idl/Collector.json5 @@ -267,6 +267,22 @@ noexcept: false, attributes: [], }, + // void alloc_copy(void * src) + { + name: "alloc_copy", + doc: [ + "allocate copy of source object at address @p src.", + "Source must be owned by this collector.", + "Increments object age" + ], + return_type: "void *", + args: [ + {type: "std::byte *", name: "src"}, + ], + const: false, + noexcept: false, + attributes: [], + }, // void forward_inplace(AGCObject * lhs_iface, void ** lhs_data); { name: "forward_inplace", @@ -288,7 +304,23 @@ }, ], router_facet_explicit_content: [ - "/** forward op in place. Defined in GCObject.hpp to avoid #include cycle **/", + "/** convenience template for gc object copy **/", + "template ", + "void * alloc_copy_for(const T * src) noexcept {", + " return O::iface()->alloc_copy(O::data(), (std::byte *)const_cast(src));", + "}", + "", + "/** convenience template for move-constructible T (this is common) **/", + "template ", + "void * std_copy_for(const T * src) noexcept {", + " void * mem = this->alloc_copy_for(src);", + " if (mem) {", + " new (mem) T(std::move(*src));", + " }", + " return (T *)mem;", + "}", + "", + "/** forward faceted object pointer in place. Defined in GCObject.hpp to avoid #include cycle **/", "template ", "void forward_inplace(obj * p_obj);", "", diff --git a/include/xo/alloc2/gc/ACollector.hpp b/include/xo/alloc2/gc/ACollector.hpp index 93a4152..c4af249 100644 --- a/include/xo/alloc2/gc/ACollector.hpp +++ b/include/xo/alloc2/gc/ACollector.hpp @@ -119,6 +119,10 @@ Return false if installation fails (e.g. memory exhausted) **/ Require: gc not in progress **/ virtual void assign_member(Opaque data, void * parent, obj * p_lhs, obj & rhs) = 0; + /** allocate copy of source object at address @p src. +Source must be owned by this collector. +Increments object age **/ + virtual void * alloc_copy(Opaque data, std::byte * src) = 0; /** evacuate @p *lhs, that refers to state with interface @p lhs_iface, to collector @p d's to-space. Replace *lhs_data with forwarding pointer diff --git a/include/xo/alloc2/gc/ICollector_Any.hpp b/include/xo/alloc2/gc/ICollector_Any.hpp index 7d36415..831aad4 100644 --- a/include/xo/alloc2/gc/ICollector_Any.hpp +++ b/include/xo/alloc2/gc/ICollector_Any.hpp @@ -75,6 +75,7 @@ namespace mm { [[noreturn]] void remove_gc_root_poly(Opaque, obj *) override; [[noreturn]] void request_gc(Opaque, Generation) override; [[noreturn]] void assign_member(Opaque, void *, obj *, obj &) override; + [[noreturn]] void * alloc_copy(Opaque, std::byte *) override; [[noreturn]] void forward_inplace(Opaque, AGCObject *, void **) override; ///@} diff --git a/include/xo/alloc2/gc/ICollector_Xfer.hpp b/include/xo/alloc2/gc/ICollector_Xfer.hpp index 5bd9d9c..8475c4b 100644 --- a/include/xo/alloc2/gc/ICollector_Xfer.hpp +++ b/include/xo/alloc2/gc/ICollector_Xfer.hpp @@ -90,6 +90,9 @@ namespace mm { void assign_member(Opaque data, void * parent, obj * p_lhs, obj & rhs) override { return I::assign_member(_dcast(data), parent, p_lhs, rhs); } + void * alloc_copy(Opaque data, std::byte * src) override { + return I::alloc_copy(_dcast(data), src); + } void forward_inplace(Opaque data, AGCObject * lhs_iface, void ** lhs_data) override { return I::forward_inplace(_dcast(data), lhs_iface, lhs_data); } diff --git a/include/xo/alloc2/gc/RCollector.hpp b/include/xo/alloc2/gc/RCollector.hpp index 4580f05..4bf2ad1 100644 --- a/include/xo/alloc2/gc/RCollector.hpp +++ b/include/xo/alloc2/gc/RCollector.hpp @@ -47,7 +47,23 @@ public: ///@{ // explicit injected content - /** forward op in place. Defined in GCObject.hpp to avoid #include cycle **/ + /** convenience template for gc object copy **/ + template + void * alloc_copy_for(const T * src) noexcept { + return O::iface()->alloc_copy(O::data(), (std::byte *)const_cast(src)); + } + + /** convenience template for move-constructible T (this is common) **/ + template + void * std_copy_for(const T * src) noexcept { + void * mem = this->alloc_copy_for(src); + if (mem) { + new (mem) T(std::move(*src)); + } + return (T *)mem; + } + + /** forward faceted object pointer in place. Defined in GCObject.hpp to avoid #include cycle **/ template void forward_inplace(obj * p_obj); @@ -123,6 +139,9 @@ public: void assign_member(void * parent, obj * p_lhs, obj & rhs) { return O::iface()->assign_member(O::data(), parent, p_lhs, rhs); } + void * alloc_copy(std::byte * src) { + return O::iface()->alloc_copy(O::data(), src); + } void forward_inplace(AGCObject * lhs_iface, void ** lhs_data) { return O::iface()->forward_inplace(O::data(), lhs_iface, lhs_data); } diff --git a/src/alloc2/facet/ICollector_Any.cpp b/src/alloc2/facet/ICollector_Any.cpp index aa24409..269d95b 100644 --- a/src/alloc2/facet/ICollector_Any.cpp +++ b/src/alloc2/facet/ICollector_Any.cpp @@ -65,6 +65,12 @@ ICollector_Any::assign_member(Opaque, void *, obj *, obj & _fatal(); } +auto +ICollector_Any::alloc_copy(Opaque, std::byte *) -> void * +{ + _fatal(); +} + auto ICollector_Any::forward_inplace(Opaque, AGCObject *, void **) -> void {