xo-facet: runtime facet lookup [PROTO]
This commit is contained in:
parent
2a3133b008
commit
9ce465e84f
7 changed files with 111 additions and 10 deletions
|
|
@ -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<ATo>(obj<AFrom>)``
|
||||
- polymorphic conversion between facets
|
||||
* - ``obj<A,D>``
|
||||
- ``x.foo()``
|
||||
- convenience wrapper with interface A, with state D*
|
||||
- convenience wrapper for interface A, with state D*
|
||||
* - ``RRouter<A,D>``
|
||||
- ``x.foo()``
|
||||
- auto injects data pointer
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "facet_implementation.hpp"
|
||||
#include "typeseq.hpp"
|
||||
#include "obj.hpp"
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
|
|
@ -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 <typename AFacet>
|
||||
const AFacet * lookup(typeseq repr_id) const {
|
||||
return static_cast<const AFacet *>(this->_lookup(typeseq::id<AFacet>(), repr_id));
|
||||
return static_cast<const AFacet *>
|
||||
(this->_lookup(typeseq::id<AFacet>(), repr_id));
|
||||
}
|
||||
|
||||
/** Runtime polymorphism:
|
||||
* Switch @param from from interface @tp AFrom to interface @tp ATo.
|
||||
*
|
||||
* Use:
|
||||
* obj<AFoo> foo
|
||||
* = ...; // Foo instance with variant impl
|
||||
* obj<ABar> bar
|
||||
* = FacetRegistry::variant<ABar,AFoo>(foo);
|
||||
**/
|
||||
template <typename ATo, typename AFrom>
|
||||
obj<ATo> variant(obj<AFrom> from) {
|
||||
return variant<ATo>(from._typeseq(), from.data());
|
||||
}
|
||||
|
||||
/** Runtime polymorphism:
|
||||
* Create variant from representation @p data
|
||||
* with actual type @p repr_id.
|
||||
*
|
||||
* Use:
|
||||
* obj<AFoo> foo = ...; // Foo instance with variant impl
|
||||
* obj<ABar> bar
|
||||
* = FacetRegistry::variant<ABar>(foo._typeseq(), foo.opaque_data());
|
||||
**/
|
||||
template <typename AFacet>
|
||||
obj<AFacet> variant(typeseq repr_id, void * data) {
|
||||
const AFacet * iface = this->lookup<AFacet>(repr_id);
|
||||
return obj<AFacet>::variant(iface, data);;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -134,6 +166,7 @@ namespace xo {
|
|||
private:
|
||||
FacetRegistry() = default;
|
||||
|
||||
/** runtime lookup table (AFacet,DRepr) -> impl **/
|
||||
std::unordered_map<key_type, const void *, KeyHash> registry_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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<AFacet>::variant(iface, data)
|
||||
**/
|
||||
OObject(const AFacet * impl, void * data)
|
||||
requires std::is_same_v<DRepr, DVariantPlaceholder>
|
||||
: data_{reinterpret_cast<DVariantPlaceholder*>(data)}
|
||||
{
|
||||
static_assert(sizeof(ISpecific) == sizeof(impl));
|
||||
memcpy(&(iface_[0]), (void*)impl, sizeof(ISpecific));
|
||||
}
|
||||
|
||||
OObject(const OObject & oother) {
|
||||
_launder_from(oother);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<AFacet>::variant(iface, data)
|
||||
**/
|
||||
obj(const AFacet * iface, void * data)
|
||||
requires std::is_same_v<DRepr, DVariantPlaceholder>
|
||||
: Super(iface, data)
|
||||
{}
|
||||
|
||||
/** pseudo copy constructor
|
||||
*
|
||||
* Intended for use cases:
|
||||
|
|
@ -96,6 +108,20 @@ namespace xo {
|
|||
return obj(other.template downcast<DRepr>());
|
||||
}
|
||||
|
||||
/** Runtime polymorphism.
|
||||
* Create variant given interface @p iface,
|
||||
* type-erased represention @p data
|
||||
*
|
||||
* Use:
|
||||
* AFoo * impl = ....;
|
||||
* auto x = obj<AFoo>::variant(impl, data)
|
||||
**/
|
||||
static obj variant(const AFacet * iface, void * data)
|
||||
requires std::is_same_v<DRepr, DVariantPlaceholder>
|
||||
{
|
||||
return obj(iface, data);
|
||||
}
|
||||
|
||||
/** enabled when RRouter<AFacet> provides _preincrement.
|
||||
* Note we don't need this trick for comparison operators,
|
||||
* since return type is fixed.
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@
|
|||
**/
|
||||
|
||||
#include "DList.hpp"
|
||||
#include <xo/printable2/Printable.hpp>
|
||||
#include <xo/facet/FacetRegistry.hpp>
|
||||
#include <xo/indentlog/print/pretty.hpp>
|
||||
#include <xo/indentlog/print/tag.hpp>
|
||||
|
||||
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<APrintable>(l->head_.data());
|
||||
|
||||
size_t i = 0;
|
||||
while (!l->is_empty()) {
|
||||
if (i > 0)
|
||||
pps->write(" ");
|
||||
|
||||
obj<APrintable> elt
|
||||
= FacetRegistry::instance().variant<APrintable, AGCObject>(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("(...)");
|
||||
|
|
|
|||
|
|
@ -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<typename Object::DataType, xo::facet::DVariantPlaceholder>
|
||||
: 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 */
|
||||
/* end RPrintable.hpp */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue