/** @file abox.hpp * * @author Roland Conybeare, Feb 2026 **/ #pragma once #include "Allocator.hpp" #include #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 { auto avail = alloc.available(); auto req = sizeof(DRepr); std::cout << "panic: unable to allocate for abox" << " :req " << req << " :avail " << avail << std::endl; std::terminate(); return abox(); } } // -------------------------------- /** explicit conversion to obj **/ obj to_op() const noexcept requires std::is_same_v { return obj(this->iface(), this->data()); } obj to_op() const noexcept requires (!std::is_same_v) { return obj(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 */