xo-umbrella2/xo-facet/include/xo/facet/obj.hpp

100 lines
3.6 KiB
C++

/** @file obj.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include "RRouter.hpp"
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<DRectCoords> z1_in
* = std::make_unique<DRectCoords>(1.0, 0.0):
* ubox<AComplex> z1{z1_in.release()};
* z1.xcoord();
*
*
* +-----+ +-----------------+
* Interface | x-------------->| vtable for |
* +-----+ | some descendant |
* Data | x--------\ | of AInterface |
* +-----+ | | |
* | +-----------------+
* |
* | +--------------+
* \----->| data :: Repr |
* +--------------+
*
* Binary representation of unay<AInterface, Data>
* is compatible for different values of @tparam Data
* as long as vtable pointer moves along with data pointer.
*
* In particular binary representation for
* ubox<AInterface,D> is as if it inherited ubox<AInterface>
* (even though it does not as far as compiler is concerned)
*
* This is load-bearing for @ref move2any see below
**/
template <typename AFacet, typename DRepr = DVariantPlaceholder>
struct obj : public RoutingType<AFacet, OObject<AFacet, DRepr>> {
using Super = RoutingType<AFacet, OObject<AFacet, DRepr>>;
obj() {}
explicit obj(Super::DataPtr d) : Super(d) {}
/** copy constructor **/
template <typename DOther>
obj(const obj<AFacet, DOther> && other)
requires (std::is_convertible_v<DRepr, DOther>
|| std::is_same_v<DRepr, DVariantPlaceholder>)
: Super()
{
if constexpr (std::is_convertible_v<DRepr, DOther>) {
this->data_ = other.data_;
} else {
this->from_data(other.data_);
}
}
/** move constructor from a different representation.
* allowed given:
* - same abstract interface
* - same strategy for holding state (naked / unique / refcounted ...)
**/
template <typename DOther>
obj(const obj<AFacet, DOther> && other)
requires (std::is_same_v<DRepr, DVariantPlaceholder>
|| std::is_convertible_v<DOther*, DRepr>)
: Super()
{
static_assert(sizeof(obj<AFacet, DOther>)
== sizeof(obj<AFacet, DRepr>));
other.move2any(this);
assert(other.data_ = nullptr);
}
/** safe downcast from variant. null if downcast fails **/
static obj from(const OObject<AFacet> & other) {
return obj(other.template downcast<DRepr>());
}
};
template <typename AFacet, typename DRepr>
inline obj<AFacet, DRepr>
with_facet(DRepr * data) {
return obj<AFacet, DRepr>(data);
}
} /*namespace facet*/
} /*namespace xo*/
/* end obj.hpp */