From 3e6ab92bb3c825560763f6d0db57778040adc2ec Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Feb 2026 13:12:07 -0500 Subject: [PATCH] xo-alloc2: + abox convenience template: arena box --- xo-alloc2/include/xo/alloc2/abox.hpp | 116 +++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 xo-alloc2/include/xo/alloc2/abox.hpp diff --git a/xo-alloc2/include/xo/alloc2/abox.hpp b/xo-alloc2/include/xo/alloc2/abox.hpp new file mode 100644 index 00000000..d34271ae --- /dev/null +++ b/xo-alloc2/include/xo/alloc2/abox.hpp @@ -0,0 +1,116 @@ +/** @file abox.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "Allocator.hpp" +#include +#include + +namespace xo { + namespace mm { + + /** object with owned state + * - with default DRepr argument: + * type-erased container (runtime polymorphism). + * - with sepcific DRepr argument: + * typed container (comptime polymorphism). + * + * Similar to box (see box.hpp in xo-facet/): + * 1. inherits fat object pointer with AFacet*, DRepr* pair + * 2. automatically calls polymorphic DRepr::~DRepr when + * abox goes out of scope. + * Unlike box: + * 3. gets memory from explicit arena-like allocator + * 4. calls dtor DRepr::~DRepr(), but not delete. + * Does not retain allocator. + **/ + template + struct abox : public xo::facet::RoutingType> { + using DVariantPlaceholder = xo::facet::DVariantPlaceholder; + using Super = xo::facet::RoutingType>; + + abox() : Super() {} + + /** abox takes ownership of data @p *d; + * will destroy when abox goes out of scope. + * + * Note this is not useful when DRepr=DVariablePlaceholder + **/ + explicit abox(Super::DataPtr d) : Super(d) {} + + /** Adopt instance that has interface @p iface and (type-erased here) + * representation @p data + **/ + abox(const AFacet * iface, void * data) + requires std::is_same_v + : Super(iface, data) + {} + + /** (copy ctor not supported -- ownership is unique) **/ + abox(const abox & other) = delete; + + /** Move constructor **/ + template + abox(abox && other) + requires (std::is_same_v + || std::is_same_v) + : xo::facet::RoutingType>() + { + /* replacing .iface_ along w/ .data_ */ + this->from_obj(other); + + other.reset_opaque(nullptr); + } + + /** allocates for sizeof(DRepr), so DRepr must not use flexible array **/ + template + static abox make(obj alloc, Args&&... args) { + void * mem = alloc.alloc_for(); + if (mem) { + DRepr * data = ::new (mem) DRepr(std::forward(args)...); + + assert(data); + + return abox(data); + } else { + assert(false); + + return abox(); + } + } + + // -------------------------------- + + /** explicit conversion to obj **/ + obj to_op() const noexcept { + return obj(this->iface(), this->data()); + } + + /** Take ownership from unowned object **/ + template + abox & adopt(const obj & other) + requires (std::is_same_v + || std::is_same_v) + { + /* replace .iface_ along w/ .data_ */ + this->from_obj(other); + + return *this; + } + + ~abox() { + auto p = this->data(); + if (p) { + this->_drop(); + } + } + }; + } /*namespace mm*/ + + using mm::abox; +} /*namespace xo*/ + +/* end abox.hpp */