/** @file obj.hpp * * @author Roland Conybeare, Dec 2025 **/ #pragma once #include "RRouter.hpp" #include #include namespace xo { namespace facet { /** object with borrowed state pointer * - With default Data argument: * type-erased polymorphic container * - with specific Data argument: * typed container. Trivially de-virtualizable * * Example: * std::unique_ptr z1_in * = std::make_unique(1.0, 0.0): * ubox z1{z1_in.release()}; * z1.xcoord(); * * * +-----+ +-----------------+ * Interface | x-------------->| vtable for | * +-----+ | some descendant | * Data | x--------\ | of AInterface | * +-----+ | | | * | +-----------------+ * | * | +--------------+ * \----->| data :: Repr | * +--------------+ * * Binary representation of unay * is compatible for different values of @tparam Data * as long as vtable pointer moves along with data pointer. * * In particular binary representation for * ubox is as if it inherited ubox * (even though it does not as far as compiler is concerned) * * This is load-bearing for @ref move2any see below **/ template struct obj : public RoutingType> { using Super = RoutingType>; obj() : Super() {} explicit obj(Super::DataPtr d) : Super(d) {} obj(const obj & rhs) = default; /** Runtime polymorphism: * assemble variant from specific interface @p iface * and type-erased representation @p data. * * Implements * obj::variant(iface, data) **/ obj(const AFacet * iface, void * data) requires std::is_same_v : Super(iface, data) {} /** pseudo copy constructor * * Intended for use cases: * obj lhs = obj // same type on rhs * obj lhs = obj // variant lhs, typed rhs * obj lhs = obj // variant on both sides **/ template obj(const obj & other) requires (std::is_same_v || std::is_convertible_v) : Super() { this->from_obj(other); } /** move constructor from a different representation. * allowed given: * - same abstract interface * - same strategy for holding state (naked / unique / refcounted ...) **/ template obj(const obj && other) requires (std::is_same_v || std::is_convertible_v) : Super() { /* replacing .iface_ along w/ .data_ */ this->from_obj(other); } obj & operator=(const obj & rhs) { /* ensure we replace .iface_ along w/ .ata_ */ this->from_obj(rhs); return *this; } /** safe downcast from variant. null if downcast fails **/ static obj from(const OObject & other) { return obj(other.template downcast()); } /** Runtime polymorphism. * Create variant given interface @p iface, * type-erased represention @p data * * Use: * AFoo * impl = ....; * auto x = obj::variant(impl, data) **/ static obj variant(const AFacet * iface, void * data) requires std::is_same_v { return obj(iface, data); } /** enabled when RRouter provides _preincrement. * Note we don't need this trick for comparison operators, * since return type is fixed. * * For example see comparison overloads in RAllocIterator.hpp **/ obj & operator++() noexcept { this->_preincrement(); return *this; } }; template using vt = obj; /** Use: * auto o = with_facet::mkobj(&data); **/ template struct with_facet { template static obj mkobj(DRepr * data) { obj x(data); return x; } }; } /*namespace facet*/ using facet::obj; using facet::vt; } /*namespace xo*/ /* end obj.hpp */