From fe4fc4a28d61cf032babe8ff2a4871ec2dd1692a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 9 Jan 2026 10:07:20 -0500 Subject: [PATCH] xo-facet: runtime facet lookup [PROTO] --- docs/implementation.rst | 9 +++++++- docs/index.rst | 1 + include/xo/facet/FacetRegistry.hpp | 37 ++++++++++++++++++++++++++++-- include/xo/facet/OObject.hpp | 16 +++++++++++++ include/xo/facet/obj.hpp | 26 +++++++++++++++++++++ 5 files changed, 86 insertions(+), 3 deletions(-) diff --git a/docs/implementation.rst b/docs/implementation.rst index ed24aec..759ac35 100644 --- a/docs/implementation.rst +++ b/docs/implementation.rst @@ -10,6 +10,8 @@ Library dependency tower for *xo-facet*: +-----------------+ | xo_facet | +-----------------+ + | xo_arena | + +-----------------+ | xo_cmake | +-----------------+ @@ -18,6 +20,8 @@ Abstraction tower for *xo-facet* components. .. ditaa:: :--scale: 0.85 + +--------------------------------+ + | FacetRegistry | +--------------------------------+ | obj(A,D) | +--------------------------------+ @@ -37,9 +41,12 @@ Abstraction tower for *xo-facet* components. * - Component - Use - Description + * - ``FacetRegistry`` + - ``FacetRegistry::convert_to(obj)`` + - polymorphic conversion between facets * - ``obj`` - ``x.foo()`` - - convenience wrapper with interface A, with state D* + - convenience wrapper for interface A, with state D* * - ``RRouter`` - ``x.foo()`` - auto injects data pointer diff --git a/docs/index.rst b/docs/index.rst index 68bba28..27cff1f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -45,6 +45,7 @@ This gives us several benefits: simpler that the pathway for a data pointer. This increases scope for devirtualization. + .. toctree:: :maxdepth: 2 :caption: xo-facet contents diff --git a/include/xo/facet/FacetRegistry.hpp b/include/xo/facet/FacetRegistry.hpp index f57f421..27db9d0 100644 --- a/include/xo/facet/FacetRegistry.hpp +++ b/include/xo/facet/FacetRegistry.hpp @@ -9,6 +9,7 @@ #include "facet_implementation.hpp" #include "typeseq.hpp" +#include "obj.hpp" #include #include @@ -88,7 +89,8 @@ namespace xo { bool contains(typeseq facet_id, typeseq repr_id) const { - return registry_.find(key_type(facet_id, repr_id)) != registry_.end(); + return (registry_.find(key_type(facet_id, repr_id)) + != registry_.end()); } /** Type-safe lookup @@ -99,7 +101,37 @@ namespace xo { **/ template const AFacet * lookup(typeseq repr_id) const { - return static_cast(this->_lookup(typeseq::id(), repr_id)); + return static_cast + (this->_lookup(typeseq::id(), repr_id)); + } + + /** Runtime polymorphism: + * Switch @param from from interface @tp AFrom to interface @tp ATo. + * + * Use: + * obj foo + * = ...; // Foo instance with variant impl + * obj bar + * = FacetRegistry::variant(foo); + **/ + template + obj variant(obj from) { + return variant(from._typeseq(), from.data()); + } + + /** Runtime polymorphism: + * Create variant from representation @p data + * with actual type @p repr_id. + * + * Use: + * obj foo = ...; // Foo instance with variant impl + * obj bar + * = FacetRegistry::variant(foo._typeseq(), foo.opaque_data()); + **/ + template + obj variant(typeseq repr_id, void * data) { + const AFacet * iface = this->lookup(repr_id); + return obj::variant(iface, data);; } private: @@ -134,6 +166,7 @@ namespace xo { private: FacetRegistry() = default; + /** runtime lookup table (AFacet,DRepr) -> impl **/ std::unordered_map registry_; }; diff --git a/include/xo/facet/OObject.hpp b/include/xo/facet/OObject.hpp index 37298fe..e4ed5b0 100644 --- a/include/xo/facet/OObject.hpp +++ b/include/xo/facet/OObject.hpp @@ -78,6 +78,22 @@ namespace xo { memcpy(&(iface_[0]), (void*)&tmp, sizeof(ISpecific)); } + /** + * Runtime polymorphism: + * Create variant for specific interface @p impl + * with type-erased data @p data. + * + * Implements + * obj::variant(iface, data) + **/ + OObject(const AFacet * impl, void * data) + requires std::is_same_v + : data_{reinterpret_cast(data)} + { + static_assert(sizeof(ISpecific) == sizeof(impl)); + memcpy(&(iface_[0]), (void*)impl, sizeof(ISpecific)); + } + OObject(const OObject & oother) { _launder_from(oother); } diff --git a/include/xo/facet/obj.hpp b/include/xo/facet/obj.hpp index 6a0aa57..b50bf65 100644 --- a/include/xo/facet/obj.hpp +++ b/include/xo/facet/obj.hpp @@ -54,6 +54,18 @@ namespace xo { 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: @@ -96,6 +108,20 @@ namespace xo { 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.