diff --git a/xo-facet/docs/implementation.rst b/xo-facet/docs/implementation.rst index ed24aece..759ac359 100644 --- a/xo-facet/docs/implementation.rst +++ b/xo-facet/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/xo-facet/docs/index.rst b/xo-facet/docs/index.rst index 68bba28a..27cff1f6 100644 --- a/xo-facet/docs/index.rst +++ b/xo-facet/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/xo-facet/include/xo/facet/FacetRegistry.hpp b/xo-facet/include/xo/facet/FacetRegistry.hpp index f57f4215..27db9d0f 100644 --- a/xo-facet/include/xo/facet/FacetRegistry.hpp +++ b/xo-facet/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/xo-facet/include/xo/facet/OObject.hpp b/xo-facet/include/xo/facet/OObject.hpp index 37298fef..e4ed5b06 100644 --- a/xo-facet/include/xo/facet/OObject.hpp +++ b/xo-facet/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/xo-facet/include/xo/facet/obj.hpp b/xo-facet/include/xo/facet/obj.hpp index 6a0aa577..b50bf65e 100644 --- a/xo-facet/include/xo/facet/obj.hpp +++ b/xo-facet/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. diff --git a/xo-object2/src/object2/DList.cpp b/xo-object2/src/object2/DList.cpp index 65b18a69..8d851e78 100644 --- a/xo-object2/src/object2/DList.cpp +++ b/xo-object2/src/object2/DList.cpp @@ -4,11 +4,15 @@ **/ #include "DList.hpp" +#include +#include #include #include namespace xo { + using xo::print::APrintable; using xo::mm::AGCObject; + using xo::facet::FacetRegistry; using xo::facet::typeseq; namespace scm { @@ -96,17 +100,28 @@ namespace xo { if (ppii.upto()) { /* perhaps print on one line */ - if (!pps->print_upto("(...)")) - return false; + pps->write("("); -#ifdef NOT_YET /* TODO: probably use iterators here, when available */ const DList * l = this; - while (!l->is_empty()) { - obj(l->head_.data()); + size_t i = 0; + while (!l->is_empty()) { + if (i > 0) + pps->write(" "); + + obj elt + = FacetRegistry::instance().variant(l->head_); + // what if no converter registered ? + + if (!pps->print_upto(elt)) + return false; + + l = l->rest_; + ++i; } -#endif + + pps->write(")"); return true; } else { pps->write("(...)"); diff --git a/xo-printable2/include/xo/printable2/detail/RPrintable.hpp b/xo-printable2/include/xo/printable2/detail/RPrintable.hpp index 6dafb4c7..78297814 100644 --- a/xo-printable2/include/xo/printable2/detail/RPrintable.hpp +++ b/xo-printable2/include/xo/printable2/detail/RPrintable.hpp @@ -37,6 +37,9 @@ public: ///@{ RPrintable() {} RPrintable(Object::DataPtr data) : Object{std::move(data)} {} + RPrintable(const APrintable * iface, void * data) + requires std::is_same_v + : Object(iface, data) {} ///@} /** @defgroup print-printable-router-methods **/ @@ -44,7 +47,7 @@ public: // const methods int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); } - bool pretty(const ppindentinfo & ppii) override { + bool pretty(const ppindentinfo & ppii) { return O::iface()->pretty(O::data(), ppii); } @@ -75,4 +78,4 @@ namespace xo { namespace facet { }; } } -/* end RPrintable.hpp */ \ No newline at end of file +/* end RPrintable.hpp */