xo-reflect: multiple improvements -- kitchen sink
This commit is contained in:
parent
57a75e380f
commit
42331ce8ba
12 changed files with 527 additions and 427 deletions
|
|
@ -9,153 +9,154 @@
|
|||
#include <vector>
|
||||
|
||||
namespace xo {
|
||||
namespace reflect {
|
||||
template<typename StructT, bool IsSelfTaggingDescendant>
|
||||
class SelfTagger {};
|
||||
namespace reflect {
|
||||
template<typename StructT, bool IsSelfTaggingDescendant>
|
||||
class SelfTagger {};
|
||||
|
||||
template<typename StructT>
|
||||
struct SelfTagger<StructT, true> {
|
||||
static TaggedPtr self_tp(void * object) {
|
||||
return (reinterpret_cast<StructT *>(object))->self_tp();
|
||||
}
|
||||
};
|
||||
template<typename StructT>
|
||||
struct SelfTagger<StructT, true> {
|
||||
static TaggedPtr self_tp(void * object) {
|
||||
return (reinterpret_cast<StructT *>(object))->self_tp();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename StructT>
|
||||
struct SelfTagger<StructT, false> {
|
||||
static TaggedPtr self_tp(void * /*object*/) { assert(false); return TaggedPtr::universal_null(); }
|
||||
};
|
||||
template<typename StructT>
|
||||
struct SelfTagger<StructT, false> {
|
||||
static TaggedPtr self_tp(void * /*object*/) { assert(false); return TaggedPtr::universal_null(); }
|
||||
};
|
||||
|
||||
/* RAII pattern for reflecting a struct.
|
||||
/* RAII pattern for reflecting a struct.
|
||||
*
|
||||
* Use:
|
||||
* struct Foo { int x_; double y_; };
|
||||
*
|
||||
* StructReflector<Foo> sr;
|
||||
* REFLECT_LITERAL_MEMBER(sr, x_);
|
||||
* REFLECT_LITERAL_MEMBER(sr, y_);
|
||||
*
|
||||
* // optional: regardless, reflection will be completed when sr goes out of scope
|
||||
* sr.require_complete();
|
||||
*/
|
||||
template<typename StructT>
|
||||
class StructReflector {
|
||||
public:
|
||||
using struct_t = StructT;
|
||||
|
||||
public:
|
||||
StructReflector() : td_{EstablishTypeDescr::establish<StructT>()} {}
|
||||
~StructReflector() {
|
||||
this->require_complete();
|
||||
}
|
||||
|
||||
bool is_complete() const { return s_reflected_flag; }
|
||||
bool is_incomplete() const { return !s_reflected_flag; }
|
||||
TypeDescr td() const { return td_; }
|
||||
|
||||
template<typename OwnerT, typename MemberT>
|
||||
void reflect_member(std::string const & member_name,
|
||||
MemberT OwnerT::* member_addr) {
|
||||
|
||||
auto accessor
|
||||
(GeneralStructMemberAccessor<StructT, OwnerT, MemberT>::make(member_addr));
|
||||
|
||||
/* used to do this in GeneralStructMemberAccessor<> ctor,
|
||||
* but that introduces #include cycle
|
||||
*/
|
||||
Reflect::require<MemberT>();
|
||||
|
||||
this->member_v_.emplace_back(member_name, std::move(accessor));
|
||||
} /*reflect_member*/
|
||||
|
||||
void require_complete() {
|
||||
if(!s_reflected_flag) {
|
||||
s_reflected_flag = true;
|
||||
|
||||
constexpr bool have_to_self_tp = std::is_base_of_v<SelfTagging, StructT>;
|
||||
|
||||
/* if self-tagging, can use .self_tp() to get most-derived tagged pointer */
|
||||
auto to_self_tp_fn
|
||||
= ([](void * object)
|
||||
{
|
||||
return SelfTagger<StructT, have_to_self_tp>::self_tp(object);
|
||||
});
|
||||
|
||||
auto tdx = StructTdx::make(std::move(this->member_v_),
|
||||
have_to_self_tp,
|
||||
to_self_tp_fn);
|
||||
|
||||
this->td_->assign_tdextra(std::move(tdx));
|
||||
}
|
||||
} /*complete*/
|
||||
|
||||
template<typename AncestorT>
|
||||
void adopt_ancestors() {
|
||||
assert(Reflect::is_reflected<AncestorT>());
|
||||
|
||||
TypeDescr ancestor_td = Reflect::require<AncestorT>();
|
||||
|
||||
/* requires that reflection of AncestorT has completed */
|
||||
{
|
||||
assert(ancestor_td->is_struct());
|
||||
assert(ancestor_td->complete_flag());
|
||||
}
|
||||
|
||||
/* for structs,
|
||||
* we know that object argument to TypeDescr::n_child() is unused
|
||||
*/
|
||||
for (uint32_t i = 0, n = ancestor_td->n_child(nullptr); i < n; ++i) {
|
||||
StructMember const & member = ancestor_td->struct_member(i);
|
||||
|
||||
this->member_v_.push_back(member.for_descendant<StructT, AncestorT>());
|
||||
}
|
||||
} /*adopt_ancestors*/
|
||||
|
||||
private:
|
||||
/* set irrevocably to true when .complete() runs.
|
||||
*
|
||||
* want to reflect a particular type once;
|
||||
* short-circuit 2nd or later attempts on the same type
|
||||
*/
|
||||
static bool s_reflected_flag;
|
||||
|
||||
/* type description object for StructT */
|
||||
TypeDescrW td_;
|
||||
|
||||
/* members of StructT (at least those we're choosing to reflect) */
|
||||
std::vector<StructMember> member_v_;
|
||||
}; /*StructReflector*/
|
||||
|
||||
template<typename StructT>
|
||||
bool StructReflector<StructT>::s_reflected_flag = false;
|
||||
} /*namespace reflect*/
|
||||
|
||||
/* e.g.
|
||||
* struct Foo { int bar_; };
|
||||
* struct Bar : public Foo { .. };
|
||||
*
|
||||
* Use:
|
||||
* struct Foo { int x_; double y_; };
|
||||
*
|
||||
* StructReflector<Foo> sr;
|
||||
* REFLECT_LITERAL_MEMBER(sr, x_);
|
||||
* REFLECT_LITERAL_MEMBER(sr, y_);
|
||||
*
|
||||
* // optional: regardless, reflection will be completed when sr goes out of scope
|
||||
* sr.require_complete();
|
||||
* StructReflector<Bar> sr;
|
||||
* REFLECT_EXPLICIT_MEMBER(sr, "bar", &Foo::bar_);
|
||||
*/
|
||||
template<typename StructT>
|
||||
class StructReflector {
|
||||
public:
|
||||
using struct_t = StructT;
|
||||
|
||||
public:
|
||||
StructReflector() : td_{EstablishTypeDescr::establish<StructT>()} {}
|
||||
~StructReflector() {
|
||||
this->require_complete();
|
||||
}
|
||||
|
||||
bool is_complete() const { return s_reflected_flag; }
|
||||
bool is_incomplete() const { return !s_reflected_flag; }
|
||||
|
||||
template<typename OwnerT, typename MemberT>
|
||||
void reflect_member(std::string const & member_name,
|
||||
MemberT OwnerT::* member_addr) {
|
||||
|
||||
auto accessor
|
||||
(GeneralStructMemberAccessor<StructT, OwnerT, MemberT>::make(member_addr));
|
||||
|
||||
/* used to do this in GeneralStructMemberAccessor<> ctor,
|
||||
* but that introduces #include cycle
|
||||
*/
|
||||
Reflect::require<MemberT>();
|
||||
|
||||
this->member_v_.emplace_back(member_name, std::move(accessor));
|
||||
} /*reflect_member*/
|
||||
|
||||
void require_complete() {
|
||||
if(!s_reflected_flag) {
|
||||
s_reflected_flag = true;
|
||||
|
||||
constexpr bool have_to_self_tp = std::is_base_of_v<SelfTagging, StructT>;
|
||||
|
||||
/* if self-tagging, can use .self_tp() to get most-derived tagged pointer */
|
||||
auto to_self_tp_fn
|
||||
= ([](void * object)
|
||||
{
|
||||
return SelfTagger<StructT, have_to_self_tp>::self_tp(object);
|
||||
});
|
||||
|
||||
auto tdx = StructTdx::make(std::move(this->member_v_),
|
||||
have_to_self_tp,
|
||||
to_self_tp_fn);
|
||||
|
||||
this->td_->assign_tdextra(std::move(tdx));
|
||||
}
|
||||
} /*complete*/
|
||||
|
||||
template<typename AncestorT>
|
||||
void adopt_ancestors() {
|
||||
assert(Reflect::is_reflected<AncestorT>());
|
||||
|
||||
TypeDescr ancestor_td = Reflect::require<AncestorT>();
|
||||
|
||||
/* requires that reflection of AncestorT has completed */
|
||||
{
|
||||
assert(ancestor_td->is_struct());
|
||||
assert(ancestor_td->complete_flag());
|
||||
}
|
||||
|
||||
/* for structs,
|
||||
* we know that object argument to TypeDescr::n_child() is unused
|
||||
*/
|
||||
for (uint32_t i = 0, n = ancestor_td->n_child(nullptr); i < n; ++i) {
|
||||
StructMember const & member = ancestor_td->struct_member(i);
|
||||
|
||||
this->member_v_.push_back(member.for_descendant<StructT, AncestorT>());
|
||||
}
|
||||
} /*adopt_ancestors*/
|
||||
|
||||
private:
|
||||
/* set irrevocably to true when .complete() runs.
|
||||
*
|
||||
* want to reflect a particular type once;
|
||||
* short-circuit 2nd or later attempts on the same type
|
||||
*/
|
||||
static bool s_reflected_flag;
|
||||
|
||||
/* type description object for StructT */
|
||||
TypeDescrW td_;
|
||||
|
||||
/* members of StructT (at least those we're choosing to reflect) */
|
||||
std::vector<StructMember> member_v_;
|
||||
}; /*StructReflector*/
|
||||
|
||||
template<typename StructT>
|
||||
bool StructReflector<StructT>::s_reflected_flag = false;
|
||||
} /*namespace reflect*/
|
||||
|
||||
/* e.g.
|
||||
* struct Foo { int bar_; };
|
||||
* struct Bar : public Foo { .. };
|
||||
*
|
||||
* StructReflector<Bar> sr;
|
||||
* REFLECT_EXPLICIT_MEMBER(sr, "bar", &Foo::bar_);
|
||||
*/
|
||||
#define REFLECT_EXPLICIT_MEMBER(sr, member_name, member) sr.reflect_member(member_name, member)
|
||||
|
||||
/* e.g.
|
||||
* struct Foo { int bar_; };
|
||||
*
|
||||
* StructReflector<Foo> sr;
|
||||
* REFLECT_LITERAL_MEMBER(sr, bar_);
|
||||
*
|
||||
* then REFLECT_LITERAL_MEMBER() expands to something like:
|
||||
* sr.reflect_member("bar_", &StructReflector<Foo>::struct_t::bar_)
|
||||
*/
|
||||
/* e.g.
|
||||
* struct Foo { int bar_; };
|
||||
*
|
||||
* StructReflector<Foo> sr;
|
||||
* REFLECT_LITERAL_MEMBER(sr, bar_);
|
||||
*
|
||||
* then REFLECT_LITERAL_MEMBER() expands to something like:
|
||||
* sr.reflect_member("bar_", &StructReflector<Foo>::struct_t::bar_)
|
||||
*/
|
||||
#define REFLECT_LITERAL_MEMBER(sr, member_name) sr.reflect_member(#member_name, &decltype(sr)::struct_t::member_name)
|
||||
|
||||
/* like REFLECT_LITERAL_MEMBER(), but append trailing underscore
|
||||
*
|
||||
* minor convenience, so we can write
|
||||
* struct Foo { int bar_; };
|
||||
*
|
||||
* StructReflector<Foo> sr;
|
||||
* REFLECT_MEMBER(sr, bar); // reflects Foo::bar_ as "bar"
|
||||
*/
|
||||
/* like REFLECT_LITERAL_MEMBER(), but append trailing underscore
|
||||
*
|
||||
* minor convenience, so we can write
|
||||
* struct Foo { int bar_; };
|
||||
*
|
||||
* StructReflector<Foo> sr;
|
||||
* REFLECT_MEMBER(sr, bar); // reflects Foo::bar_ as "bar"
|
||||
*/
|
||||
#define REFLECT_MEMBER(sr, member_name) sr.reflect_member(#member_name, &decltype(sr)::struct_t::member_name##_)
|
||||
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
|
|
@ -305,6 +305,7 @@ namespace xo {
|
|||
* .n_child() reports #of instance variables (that have been reflected)
|
||||
*/
|
||||
uint32_t n_child(void * object) const { return this->tdextra_->n_child(object); }
|
||||
/** in some circumstances can use this with object=nullptr **/
|
||||
TaggedPtr child_tp(uint32_t i, void * object) const;
|
||||
|
||||
/* require:
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ namespace xo {
|
|||
*/
|
||||
virtual TaggedPtr most_derived_self_tp(TypeDescrBase const * object_td, void * object) const;
|
||||
virtual uint32_t n_child(void * object) const = 0;
|
||||
/** number of children, fixed at compile time.
|
||||
* Will return 0 for types like std::vector<..> (because number is unknown);
|
||||
* Will also return 0 for types like {bool, int, long} (because number is zero)
|
||||
**/
|
||||
virtual uint32_t n_child_fixed() const = 0;
|
||||
virtual TaggedPtr child_tp(uint32_t i, void * object) const = 0;
|
||||
/* require:
|
||||
* .is_struct()
|
||||
|
|
|
|||
|
|
@ -7,31 +7,32 @@
|
|||
#include <memory>
|
||||
|
||||
namespace xo {
|
||||
namespace reflect {
|
||||
class TaggedPtr;
|
||||
namespace reflect {
|
||||
class TaggedPtr;
|
||||
|
||||
/* Extra type-associated information for an atomic type.
|
||||
* We use this as degenerate catch-all case for types that aren't known
|
||||
* to have additional structure (std::vector, std::map, int*, etc.)
|
||||
*/
|
||||
class AtomicTdx : public TypeDescrExtra {
|
||||
public:
|
||||
virtual ~AtomicTdx() = default;
|
||||
/* Extra type-associated information for an atomic type.
|
||||
* We use this as degenerate catch-all case for types that aren't known
|
||||
* to have additional structure (std::vector, std::map, int*, etc.)
|
||||
*/
|
||||
class AtomicTdx : public TypeDescrExtra {
|
||||
public:
|
||||
virtual ~AtomicTdx() = default;
|
||||
|
||||
static std::unique_ptr<AtomicTdx> make();
|
||||
static std::unique_ptr<AtomicTdx> make();
|
||||
|
||||
// ----- Inherited from TypeDescrExtra -----
|
||||
// ----- Inherited from TypeDescrExtra -----
|
||||
|
||||
virtual Metatype metatype() const override { return Metatype::mt_atomic; }
|
||||
virtual uint32_t n_child(void * /*object*/) const override { return 0; }
|
||||
virtual TaggedPtr child_tp(uint32_t /*i*/, void * /*object*/) const override;
|
||||
virtual std::string const & struct_member_name(uint32_t i) const override;
|
||||
//virtual StructMember const * struct_member(uint32_t /*i*/) const override { return nullptr; }
|
||||
virtual Metatype metatype() const override { return Metatype::mt_atomic; }
|
||||
virtual uint32_t n_child(void * /*object*/) const override { return 0; }
|
||||
virtual uint32_t n_child_fixed() const override { return 0; }
|
||||
virtual TaggedPtr child_tp(uint32_t /*i*/, void * /*object*/) const override;
|
||||
virtual std::string const & struct_member_name(uint32_t i) const override;
|
||||
//virtual StructMember const * struct_member(uint32_t /*i*/) const override { return nullptr; }
|
||||
|
||||
private:
|
||||
AtomicTdx() = default;
|
||||
}; /*TypeDescrExtra*/
|
||||
} /*namespace reflect*/
|
||||
private:
|
||||
AtomicTdx() = default;
|
||||
}; /*TypeDescrExtra*/
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end AtomicTdx.hpp */
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace xo {
|
|||
|
||||
virtual Metatype metatype() const override { return Metatype::mt_function; }
|
||||
virtual uint32_t n_child(void * /*object*/) const override { return 0; }
|
||||
virtual uint32_t n_child_fixed() const override { return 0; }
|
||||
virtual TaggedPtr child_tp(uint32_t i, void * object) const override;
|
||||
const std::string & struct_member_name(uint32_t i) const override;
|
||||
|
||||
|
|
|
|||
71
include/xo/reflect/reflect_struct.hpp
Normal file
71
include/xo/reflect/reflect_struct.hpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/** @file reflect_struct.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StructReflector.hpp"
|
||||
#include "xo/reflectutil/reflect_struct_info.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace reflect {
|
||||
namespace detail {
|
||||
/**
|
||||
* @pre reflect_struct_member<T,MemberIx> will separately
|
||||
* have been specialized for T.
|
||||
* See discussion in [reflect_struct_info.hpp]
|
||||
*
|
||||
*
|
||||
**/
|
||||
template <typename T,
|
||||
std::size_t MemberIx,
|
||||
std::size_t N_Member>
|
||||
struct sr_member_helper {
|
||||
/** reflect members starting from member with index number @tparam MemberIx
|
||||
*
|
||||
* @pre Members [0,..,MemberIx-1] must be already represented in @p *p_sr
|
||||
**/
|
||||
static void add_members_from(StructReflector<T> * p_sr) {
|
||||
const auto & member_info
|
||||
= reflect_struct_member<T, MemberIx>().get();
|
||||
|
||||
p_sr->reflect_member(member_info.member_name_.c_str(),
|
||||
member_info.member_addr_);
|
||||
|
||||
/** reflect remaining members **/
|
||||
sr_member_helper<T, MemberIx+1, N_Member>::add_members_from(p_sr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t MemberIx>
|
||||
struct sr_member_helper<T, MemberIx, MemberIx /*N_Member*/> {
|
||||
/** base case -- all members have been refleccted **/
|
||||
static void add_members_from(StructReflector<T> *) {}
|
||||
};
|
||||
} /*namespace detail*/
|
||||
|
||||
|
||||
/** It's awkward to have Reflect::reflect<>() do the right thing,
|
||||
* because there's no way to specialize on whether a type T is a struct.
|
||||
*
|
||||
* Use
|
||||
* xo::reflect::Reflect::reflect_struct<T>() instead
|
||||
**/
|
||||
template <typename T>
|
||||
TypeDescr reflect_struct() {
|
||||
StructReflector<T> sr;
|
||||
|
||||
if (sr.is_incomplete())
|
||||
detail::sr_member_helper<T, 0, reflect_struct_traits<T>::n_members>::add_members_from(&sr);
|
||||
|
||||
/* TODO: handle composition: where T inherits another reflected type */
|
||||
/* TODO: handle multiple inheritance **/
|
||||
|
||||
return sr.td();
|
||||
}
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end reflect_struct.hpp **/
|
||||
|
|
@ -9,227 +9,227 @@
|
|||
#include <memory>
|
||||
|
||||
namespace xo {
|
||||
namespace reflect {
|
||||
class AbstractStructMemberAccessor {
|
||||
public:
|
||||
virtual ~AbstractStructMemberAccessor() = default;
|
||||
namespace reflect {
|
||||
class AbstractStructMemberAccessor {
|
||||
public:
|
||||
virtual ~AbstractStructMemberAccessor() = default;
|
||||
|
||||
/* get tagged pointer referring to this member of the object at *struct_addr */
|
||||
TaggedPtr member_tp(void * struct_addr) const;
|
||||
/* get tagged pointer referring to this member of the object at *struct_addr */
|
||||
TaggedPtr member_tp(void * struct_addr) const;
|
||||
|
||||
/* get type-description object for struct
|
||||
* containing this member. useful for consistency checking.
|
||||
*/
|
||||
virtual TypeDescr struct_td() const = 0;
|
||||
/* get type-description object for struct
|
||||
* containing this member. useful for consistency checking.
|
||||
*/
|
||||
virtual TypeDescr struct_td() const = 0;
|
||||
|
||||
/* get type-description object for this member
|
||||
* e.g. if this member represents Foo::bar_ in
|
||||
* struct Foo { int bar_; };
|
||||
* then
|
||||
* .member_td() => Reflect::require<int>();
|
||||
*/
|
||||
virtual TypeDescr member_td() const = 0;
|
||||
/* get type-description object for this member
|
||||
* e.g. if this member represents Foo::bar_ in
|
||||
* struct Foo { int bar_; };
|
||||
* then
|
||||
* .member_td() => Reflect::require<int>();
|
||||
*/
|
||||
virtual TypeDescr member_td() const = 0;
|
||||
|
||||
/* get address of a particular member, given parent address */
|
||||
virtual void * address(void * struct_addr) const = 0;
|
||||
/* get address of a particular member, given parent address */
|
||||
virtual void * address(void * struct_addr) const = 0;
|
||||
|
||||
virtual std::unique_ptr<AbstractStructMemberAccessor> clone() const = 0;
|
||||
}; /*AbstractStructMemberAccessor*/
|
||||
virtual std::unique_ptr<AbstractStructMemberAccessor> clone() const = 0;
|
||||
}; /*AbstractStructMemberAccessor*/
|
||||
|
||||
/* GeneralStructMemberAccessor
|
||||
*
|
||||
* Use this to handle access to possibly-inherited struct members:
|
||||
*
|
||||
* struct Foo { int x_; }
|
||||
* struct Bar { char * y_; }
|
||||
* struct Quux : public Foo, public Bar { bool z_; }
|
||||
*
|
||||
* want to be able to access Bar::y from a Quux instance.
|
||||
* in example, would use GenericStructMemberAccessor<>
|
||||
* with:
|
||||
* StructT = Quux,
|
||||
* OwnerT = Bar,
|
||||
* MemberT = char*
|
||||
*
|
||||
* Require:
|
||||
* StructT* is assignable to OwnerT* (because StructT --isa--> OwnerT)
|
||||
*/
|
||||
template <typename StructT, typename OwnerT, typename MemberT>
|
||||
class GeneralStructMemberAccessor : public AbstractStructMemberAccessor {
|
||||
public:
|
||||
/* pointer to a OwnerT member of type MemberT */
|
||||
using Memptr = MemberT OwnerT::*;
|
||||
/* GeneralStructMemberAccessor
|
||||
*
|
||||
* Use this to handle access to possibly-inherited struct members:
|
||||
*
|
||||
* struct Foo { int x_; }
|
||||
* struct Bar { char * y_; }
|
||||
* struct Quux : public Foo, public Bar { bool z_; }
|
||||
*
|
||||
* want to be able to access Bar::y from a Quux instance.
|
||||
* in example, would use GenericStructMemberAccessor<>
|
||||
* with:
|
||||
* StructT = Quux,
|
||||
* OwnerT = Bar,
|
||||
* MemberT = char*
|
||||
*
|
||||
* Require:
|
||||
* StructT* is assignable to OwnerT* (because StructT --isa--> OwnerT)
|
||||
*/
|
||||
template <typename StructT, typename OwnerT, typename MemberT>
|
||||
class GeneralStructMemberAccessor : public AbstractStructMemberAccessor {
|
||||
public:
|
||||
/* pointer to a OwnerT member of type MemberT */
|
||||
using Memptr = MemberT OwnerT::*;
|
||||
|
||||
public:
|
||||
GeneralStructMemberAccessor(Memptr memptr) : member_td_{EstablishTypeDescr::establish<MemberT>()},
|
||||
memptr_{memptr} {}
|
||||
GeneralStructMemberAccessor(GeneralStructMemberAccessor const & x) = default;
|
||||
virtual ~GeneralStructMemberAccessor() = default;
|
||||
public:
|
||||
GeneralStructMemberAccessor(Memptr memptr) : member_td_{EstablishTypeDescr::establish<MemberT>()},
|
||||
memptr_{memptr} {}
|
||||
GeneralStructMemberAccessor(GeneralStructMemberAccessor const & x) = default;
|
||||
virtual ~GeneralStructMemberAccessor() = default;
|
||||
|
||||
static std::unique_ptr<GeneralStructMemberAccessor> make(Memptr memptr) {
|
||||
return std::unique_ptr<GeneralStructMemberAccessor>(new GeneralStructMemberAccessor(memptr)); }
|
||||
static std::unique_ptr<GeneralStructMemberAccessor> make(Memptr memptr) {
|
||||
return std::unique_ptr<GeneralStructMemberAccessor>(new GeneralStructMemberAccessor(memptr)); }
|
||||
|
||||
/* get member address given address of parent struct
|
||||
* (i.e. from Struct*, not from OwnerT*)
|
||||
*/
|
||||
MemberT * address_impl(StructT * self_addr) const {
|
||||
OwnerT * owner_addr = self_addr;
|
||||
/* get member address given address of parent struct
|
||||
* (i.e. from Struct*, not from OwnerT*)
|
||||
*/
|
||||
MemberT * address_impl(StructT * self_addr) const {
|
||||
OwnerT * owner_addr = self_addr;
|
||||
|
||||
return &(owner_addr->*memptr_);
|
||||
} /*address_impl*/
|
||||
return &(owner_addr->*memptr_);
|
||||
} /*address_impl*/
|
||||
|
||||
// ----- Inherited from AbstractStructMemberAccessor -----
|
||||
// ----- Inherited from AbstractStructMemberAccessor -----
|
||||
|
||||
#ifdef OBSOLETE
|
||||
virtual TaggedPtr member_tp(void * struct_addr) const override {
|
||||
/* FIXME: this reports declared type of member, instead of
|
||||
* (possibly narrower) actual type of member
|
||||
*/
|
||||
virtual TaggedPtr member_tp(void * struct_addr) const override {
|
||||
/* FIXME: this reports declared type of member, instead of
|
||||
* (possibly narrower) actual type of member
|
||||
*/
|
||||
|
||||
return this->member_td_->most_derived_self_tp(this->address(struct_addr));
|
||||
//return TaggedPtr(this->member_td_, this->address(struct_addr));
|
||||
} /*member_tp*/
|
||||
return this->member_td_->most_derived_self_tp(this->address(struct_addr));
|
||||
//return TaggedPtr(this->member_td_, this->address(struct_addr));
|
||||
} /*member_tp*/
|
||||
#endif
|
||||
|
||||
virtual TypeDescr struct_td() const override { return EstablishTypeDescr::establish<StructT>(); }
|
||||
virtual TypeDescr struct_td() const override { return EstablishTypeDescr::establish<StructT>(); }
|
||||
|
||||
virtual TypeDescr member_td() const override { return this->member_td_; }
|
||||
virtual TypeDescr member_td() const override { return this->member_td_; }
|
||||
|
||||
virtual void * address(void * struct_addr) const override {
|
||||
return this->address_impl(reinterpret_cast<StructT *>(struct_addr));
|
||||
} /*address*/
|
||||
virtual void * address(void * struct_addr) const override {
|
||||
return this->address_impl(reinterpret_cast<StructT *>(struct_addr));
|
||||
} /*address*/
|
||||
|
||||
virtual std::unique_ptr<AbstractStructMemberAccessor> clone() const override {
|
||||
return std::unique_ptr<AbstractStructMemberAccessor>
|
||||
(new GeneralStructMemberAccessor(*this));
|
||||
} /*clone*/
|
||||
virtual std::unique_ptr<AbstractStructMemberAccessor> clone() const override {
|
||||
return std::unique_ptr<AbstractStructMemberAccessor>
|
||||
(new GeneralStructMemberAccessor(*this));
|
||||
} /*clone*/
|
||||
|
||||
private:
|
||||
/* type description for MemberT; .memptr is pointer-to-member-of-OwnerT,
|
||||
* where that member has type MemberT
|
||||
*/
|
||||
TypeDescr member_td_ = nullptr;
|
||||
/* pointer to member of OwnerT */
|
||||
Memptr memptr_ = nullptr;
|
||||
}; /*GeneralStructMemberAccessor*/
|
||||
private:
|
||||
/* type description for MemberT; .memptr is pointer-to-member-of-OwnerT,
|
||||
* where that member has type MemberT
|
||||
*/
|
||||
TypeDescr member_td_ = nullptr;
|
||||
/* pointer to member of OwnerT */
|
||||
Memptr memptr_ = nullptr;
|
||||
}; /*GeneralStructMemberAccessor*/
|
||||
|
||||
/* struct-member accessor via delegation,
|
||||
* to accessor of a parent (or some other ancestor) class.
|
||||
*
|
||||
* struct Foo { int x_; }
|
||||
* struct Bar { char * y_; }
|
||||
*
|
||||
* auto bar_x_access = GeneralStructMemberAccessor<Bar, Foo, int>::make(&Foo::x_);
|
||||
*
|
||||
* or equivalently:
|
||||
* auto foo_x_access = GeneralStructMemberAccessor<Foo, Foo, int>::make(&Foo::x_);
|
||||
* auto bar_x_access = AncestorStructMemberAccessor<Bar, Foo>::adopt(foo_x_access);
|
||||
*
|
||||
* can use the 2nd form to adopt accessors from an already-reflected ancestor class
|
||||
*
|
||||
* Require:
|
||||
* - StructT -isa-> AncestorT
|
||||
*/
|
||||
template <typename StructT, typename AncestorT>
|
||||
class AncestorStructMemberAccessor : public AbstractStructMemberAccessor {
|
||||
public:
|
||||
AncestorStructMemberAccessor(std::unique_ptr<AbstractStructMemberAccessor> ancestor_accessor)
|
||||
: ancestor_accessor_{std::move(ancestor_accessor)} {}
|
||||
AncestorStructMemberAccessor(AncestorStructMemberAccessor const & x) = default;
|
||||
virtual ~AncestorStructMemberAccessor() = default;
|
||||
/* struct-member accessor via delegation,
|
||||
* to accessor of a parent (or some other ancestor) class.
|
||||
*
|
||||
* struct Foo { int x_; }
|
||||
* struct Bar { char * y_; }
|
||||
*
|
||||
* auto bar_x_access = GeneralStructMemberAccessor<Bar, Foo, int>::make(&Foo::x_);
|
||||
*
|
||||
* or equivalently:
|
||||
* auto foo_x_access = GeneralStructMemberAccessor<Foo, Foo, int>::make(&Foo::x_);
|
||||
* auto bar_x_access = AncestorStructMemberAccessor<Bar, Foo>::adopt(foo_x_access);
|
||||
*
|
||||
* can use the 2nd form to adopt accessors from an already-reflected ancestor class
|
||||
*
|
||||
* Require:
|
||||
* - StructT -isa-> AncestorT
|
||||
*/
|
||||
template <typename StructT, typename AncestorT>
|
||||
class AncestorStructMemberAccessor : public AbstractStructMemberAccessor {
|
||||
public:
|
||||
AncestorStructMemberAccessor(std::unique_ptr<AbstractStructMemberAccessor> ancestor_accessor)
|
||||
: ancestor_accessor_{std::move(ancestor_accessor)} {}
|
||||
AncestorStructMemberAccessor(AncestorStructMemberAccessor const & x) = default;
|
||||
virtual ~AncestorStructMemberAccessor() = default;
|
||||
|
||||
static std::unique_ptr<AncestorStructMemberAccessor>
|
||||
adopt(std::unique_ptr<AbstractStructMemberAccessor> ancestor_accessor) {
|
||||
return std::unique_ptr<AncestorStructMemberAccessor>
|
||||
(new AncestorStructMemberAccessor(std::move(ancestor_accessor)));
|
||||
} /*adopt*/
|
||||
static std::unique_ptr<AncestorStructMemberAccessor>
|
||||
adopt(std::unique_ptr<AbstractStructMemberAccessor> ancestor_accessor) {
|
||||
return std::unique_ptr<AncestorStructMemberAccessor>
|
||||
(new AncestorStructMemberAccessor(std::move(ancestor_accessor)));
|
||||
} /*adopt*/
|
||||
|
||||
void * address_impl(StructT * self_addr) const {
|
||||
/* to use access-via-ancestor, need to convert to ancestor pointer */
|
||||
AncestorT * ancestor_addr = self_addr;
|
||||
void * address_impl(StructT * self_addr) const {
|
||||
/* to use access-via-ancestor, need to convert to ancestor pointer */
|
||||
AncestorT * ancestor_addr = self_addr;
|
||||
|
||||
return this->ancestor_accessor_->address(ancestor_addr);
|
||||
} /*address_impl*/
|
||||
return this->ancestor_accessor_->address(ancestor_addr);
|
||||
} /*address_impl*/
|
||||
|
||||
// ----- inherited from AbstractStructMemberAccessor -----
|
||||
// ----- inherited from AbstractStructMemberAccessor -----
|
||||
|
||||
#ifdef OBSOLETE
|
||||
virtual TaggedPtr member_tp(void * struct_addr) const override {
|
||||
AncestorT * ancestor_addr = reinterpret_cast<StructT *>(struct_addr);
|
||||
virtual TaggedPtr member_tp(void * struct_addr) const override {
|
||||
AncestorT * ancestor_addr = reinterpret_cast<StructT *>(struct_addr);
|
||||
|
||||
return this->ancestor_accessor_->member_tp(ancestor_addr);
|
||||
} /*member_tp*/
|
||||
return this->ancestor_accessor_->member_tp(ancestor_addr);
|
||||
} /*member_tp*/
|
||||
#endif
|
||||
|
||||
virtual TypeDescr struct_td() const override { return EstablishTypeDescr::establish<StructT>(); }
|
||||
virtual TypeDescr member_td() const override { return this->ancestor_accessor_->member_td(); }
|
||||
virtual TypeDescr struct_td() const override { return EstablishTypeDescr::establish<StructT>(); }
|
||||
virtual TypeDescr member_td() const override { return this->ancestor_accessor_->member_td(); }
|
||||
|
||||
virtual void * address(void * struct_addr) const override {
|
||||
return this->address_impl(reinterpret_cast<StructT *>(struct_addr));
|
||||
}
|
||||
virtual void * address(void * struct_addr) const override {
|
||||
return this->address_impl(reinterpret_cast<StructT *>(struct_addr));
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<AbstractStructMemberAccessor> clone() const override {
|
||||
return std::unique_ptr<AbstractStructMemberAccessor>
|
||||
(new AncestorStructMemberAccessor(std::move(this->ancestor_accessor_->clone())));
|
||||
} /*clone*/
|
||||
virtual std::unique_ptr<AbstractStructMemberAccessor> clone() const override {
|
||||
return std::unique_ptr<AbstractStructMemberAccessor>
|
||||
(new AncestorStructMemberAccessor(std::move(this->ancestor_accessor_->clone())));
|
||||
} /*clone*/
|
||||
|
||||
private:
|
||||
/* .ancestor_accessor fetches some particular member of AncestorT */
|
||||
std::unique_ptr<AbstractStructMemberAccessor> ancestor_accessor_;
|
||||
}; /*AncestorStructMemberAccessor*/
|
||||
private:
|
||||
/* .ancestor_accessor fetches some particular member of AncestorT */
|
||||
std::unique_ptr<AbstractStructMemberAccessor> ancestor_accessor_;
|
||||
}; /*AncestorStructMemberAccessor*/
|
||||
|
||||
/* describes a member of a struct/class
|
||||
* see [reflect/StructReflector.hpp]
|
||||
*/
|
||||
class StructMember {
|
||||
public:
|
||||
StructMember() = default;
|
||||
StructMember(std::string const & name,
|
||||
std::unique_ptr<AbstractStructMemberAccessor> accessor)
|
||||
: member_name_{name}, accessor_{std::move(accessor)} {}
|
||||
StructMember(StructMember && x)
|
||||
: member_name_{std::move(x.member_name_)},
|
||||
accessor_{std::move(x.accessor_)} {}
|
||||
/* describes a member of a struct/class
|
||||
* see [reflect/StructReflector.hpp]
|
||||
*/
|
||||
class StructMember {
|
||||
public:
|
||||
StructMember() = default;
|
||||
StructMember(std::string const & name,
|
||||
std::unique_ptr<AbstractStructMemberAccessor> accessor)
|
||||
: member_name_{name}, accessor_{std::move(accessor)} {}
|
||||
StructMember(StructMember && x)
|
||||
: member_name_{std::move(x.member_name_)},
|
||||
accessor_{std::move(x.accessor_)} {}
|
||||
|
||||
static StructMember null();
|
||||
static StructMember null();
|
||||
|
||||
std::string const & member_name() const { return member_name_; }
|
||||
std::string const & member_name() const { return member_name_; }
|
||||
|
||||
TaggedPtr get_member_tp(void * struct_addr) const { return this->accessor_->member_tp(struct_addr); }
|
||||
TypeDescr get_struct_td() const { return this->accessor_->struct_td(); }
|
||||
TypeDescr get_member_td() const { return this->accessor_->member_td(); }
|
||||
//void * get_member_addr(void * struct_addr) const { return this->accessor_->address(struct_addr); }
|
||||
TaggedPtr get_member_tp(void * struct_addr) const { return this->accessor_->member_tp(struct_addr); }
|
||||
TypeDescr get_struct_td() const { return this->accessor_->struct_td(); }
|
||||
TypeDescr get_member_td() const { return this->accessor_->member_td(); }
|
||||
//void * get_member_addr(void * struct_addr) const { return this->accessor_->address(struct_addr); }
|
||||
|
||||
/* make copy that accesses this member, but starting
|
||||
* from pointer to some derived class DescendantT,
|
||||
* instead of from container type StructT known to (but not exposed by) *this
|
||||
*/
|
||||
template <typename DescendantT, typename StructT>
|
||||
StructMember for_descendant() const {
|
||||
assert(EstablishTypeDescr::establish<StructT>() == this->get_struct_td());
|
||||
/* make copy that accesses this member, but starting
|
||||
* from pointer to some derived class DescendantT,
|
||||
* instead of from container type StructT known to (but not exposed by) *this
|
||||
*/
|
||||
template <typename DescendantT, typename StructT>
|
||||
StructMember for_descendant() const {
|
||||
assert(EstablishTypeDescr::establish<StructT>() == this->get_struct_td());
|
||||
|
||||
return StructMember(this->member_name(),
|
||||
std::move(AncestorStructMemberAccessor<DescendantT, StructT>::adopt
|
||||
(std::move(this->accessor_->clone()))));
|
||||
} /*for_descendant*/
|
||||
return StructMember(this->member_name(),
|
||||
std::move(AncestorStructMemberAccessor<DescendantT, StructT>::adopt
|
||||
(std::move(this->accessor_->clone()))));
|
||||
} /*for_descendant*/
|
||||
|
||||
StructMember & operator=(StructMember && x) {
|
||||
member_name_ = std::move(x.member_name_);
|
||||
accessor_ = std::move(x.accessor_);
|
||||
return *this;
|
||||
}
|
||||
StructMember & operator=(StructMember && x) {
|
||||
member_name_ = std::move(x.member_name_);
|
||||
accessor_ = std::move(x.accessor_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
/* member name, e.g. foo if
|
||||
* struct StructT { MemberT foo; }
|
||||
*/
|
||||
std::string member_name_;
|
||||
/* T recd;
|
||||
* this->accessor_->address_impl(&recd) ==> &(recd.member)
|
||||
*/
|
||||
std::unique_ptr<AbstractStructMemberAccessor> accessor_;
|
||||
}; /*StructMember*/
|
||||
} /*namespace reflect*/
|
||||
private:
|
||||
/* member name, e.g. foo if
|
||||
* struct StructT { MemberT foo; }
|
||||
*/
|
||||
std::string member_name_;
|
||||
/* T recd;
|
||||
* this->accessor_->address_impl(&recd) ==> &(recd.member)
|
||||
*/
|
||||
std::unique_ptr<AbstractStructMemberAccessor> accessor_;
|
||||
}; /*StructMember*/
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end StructMember.hpp */
|
||||
|
|
|
|||
|
|
@ -67,7 +67,9 @@ namespace xo {
|
|||
return TypeDescrExtra::most_derived_self_tp(object_td, object);
|
||||
}
|
||||
}
|
||||
/* object argument ignored for structs, since size is fixed */
|
||||
virtual uint32_t n_child(void * /*object*/) const override { return this->member_v_.size(); }
|
||||
virtual uint32_t n_child_fixed() const override { return this->member_v_.size(); }
|
||||
virtual TaggedPtr child_tp(uint32_t i, void * object) const override;
|
||||
virtual std::string const & struct_member_name(uint32_t i) const override;
|
||||
virtual StructMember const * struct_member(uint32_t i) const override;
|
||||
|
|
|
|||
|
|
@ -17,10 +17,14 @@ namespace xo {
|
|||
/* named ctor idiom. create new instance for a vector type */
|
||||
//static std::unique_ptr<VectorTdx> make();
|
||||
|
||||
/** @brief true if array elements are stored at regularly-spaced offsetts **/
|
||||
virtual bool has_contiguous_storage() const = 0;
|
||||
|
||||
// ----- Inherited from TypeDescrExtra -----
|
||||
|
||||
virtual Metatype metatype() const override { return Metatype::mt_vector; }
|
||||
virtual uint32_t n_child(void * object) const override = 0;
|
||||
virtual uint32_t n_child_fixed() const override = 0;
|
||||
virtual TaggedPtr child_tp(uint32_t i, void * object) const override = 0;
|
||||
/* (forbidden) */
|
||||
virtual std::string const & struct_member_name(uint32_t i) const override;
|
||||
|
|
@ -41,12 +45,16 @@ namespace xo {
|
|||
return std::unique_ptr<StlVectorTdx>(new StlVectorTdx());
|
||||
} /*make*/
|
||||
|
||||
virtual bool has_contiguous_storage() const override { return true; }
|
||||
|
||||
virtual uint32_t n_child(void * object) const override {
|
||||
target_t * vec = reinterpret_cast<target_t *>(object);
|
||||
|
||||
return vec->size();
|
||||
} /*n_child*/
|
||||
|
||||
virtual uint32_t n_child_fixed() const override { return 0; /*unknown*/ }
|
||||
|
||||
virtual TaggedPtr child_tp(uint32_t i, void * object) const override {
|
||||
target_t * vec = reinterpret_cast<target_t *>(object);
|
||||
|
||||
|
|
@ -61,7 +69,10 @@ namespace xo {
|
|||
*/
|
||||
|
||||
template<typename Element, std::size_t N>
|
||||
using StdArrayTdx = StlVectorTdx<std::array<Element, N>>;
|
||||
class StdArrayTdx : public StlVectorTdx<std::array<Element, N>> {
|
||||
virtual uint32_t n_child(void * /*object*/) const override { return N; }
|
||||
virtual uint32_t n_child_fixed() const override { return N; }
|
||||
}; /*StdArrayTdx*/
|
||||
|
||||
// ----- std::vector<Element> -----
|
||||
|
||||
|
|
@ -77,12 +88,18 @@ namespace xo {
|
|||
return std::unique_ptr<StdVectorTdx>(new StdVectorTdx());
|
||||
} /*make*/
|
||||
|
||||
virtual bool has_contiguous_storage() const override { return true; }
|
||||
|
||||
virtual uint32_t n_child(void * object) const override {
|
||||
target_t * vec = reinterpret_cast<target_t *>(object);
|
||||
|
||||
return vec->size();
|
||||
} /*n_child*/
|
||||
|
||||
virtual uint32_t n_child_fixed() const override {
|
||||
return 0; /* not known without object */
|
||||
}
|
||||
|
||||
virtual TaggedPtr child_tp(uint32_t i, void * object) const override {
|
||||
target_t * vec = reinterpret_cast<target_t *>(object);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace xo {
|
|||
namespace reflect {
|
||||
TaggedPtr
|
||||
TypeDescrExtra::most_derived_self_tp(TypeDescrBase const * object_td,
|
||||
void * object) const
|
||||
void * object) const
|
||||
{
|
||||
return TaggedPtr(object_td, object);
|
||||
} /*most_derived_self_tp*/
|
||||
|
|
@ -24,7 +24,7 @@ namespace xo {
|
|||
static std::string s_null;
|
||||
return s_null;
|
||||
} /*struct_member_name*/
|
||||
|
||||
|
||||
StructMember const *
|
||||
TypeDescrExtra::struct_member(uint32_t /*i*/) const {
|
||||
assert(false);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "atomic/AtomicTdx.hpp"
|
||||
#include "TaggedPtr.hpp"
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace xo {
|
||||
namespace reflect {
|
||||
|
|
|
|||
|
|
@ -3,53 +3,53 @@
|
|||
#include "struct/StructTdx.hpp"
|
||||
|
||||
namespace xo {
|
||||
using std::uint32_t;
|
||||
using std::uint32_t;
|
||||
|
||||
namespace reflect {
|
||||
std::unique_ptr<StructTdx>
|
||||
StructTdx::make(std::vector<StructMember> member_v,
|
||||
bool have_to_self_tp,
|
||||
std::function<TaggedPtr (void*)> to_self_tp)
|
||||
{
|
||||
return std::unique_ptr<StructTdx>(new StructTdx(std::move(member_v),
|
||||
have_to_self_tp,
|
||||
std::move(to_self_tp)));
|
||||
} /*make*/
|
||||
namespace reflect {
|
||||
std::unique_ptr<StructTdx>
|
||||
StructTdx::make(std::vector<StructMember> member_v,
|
||||
bool have_to_self_tp,
|
||||
std::function<TaggedPtr (void*)> to_self_tp)
|
||||
{
|
||||
return std::unique_ptr<StructTdx>(new StructTdx(std::move(member_v),
|
||||
have_to_self_tp,
|
||||
std::move(to_self_tp)));
|
||||
} /*make*/
|
||||
|
||||
TaggedPtr
|
||||
StructTdx::child_tp(uint32_t i, void * object) const
|
||||
{
|
||||
if (i >= this->member_v_.size()) {
|
||||
/* TODO: raise exception here? */
|
||||
return TaggedPtr::universal_null();
|
||||
}
|
||||
TaggedPtr
|
||||
StructTdx::child_tp(uint32_t i, void * object) const
|
||||
{
|
||||
if (i >= this->member_v_.size()) {
|
||||
/* TODO: raise exception here? */
|
||||
return TaggedPtr::universal_null();
|
||||
}
|
||||
|
||||
StructMember const & member_info = this->member_v_[i];
|
||||
StructMember const & member_info = this->member_v_[i];
|
||||
|
||||
return member_info.get_member_tp(object);
|
||||
return member_info.get_member_tp(object);
|
||||
|
||||
} /*get_child*/
|
||||
} /*get_child*/
|
||||
|
||||
std::string const &
|
||||
StructTdx::struct_member_name(uint32_t i) const
|
||||
{
|
||||
StructMember const * sm = this->struct_member(i);
|
||||
std::string const &
|
||||
StructTdx::struct_member_name(uint32_t i) const
|
||||
{
|
||||
StructMember const * sm = this->struct_member(i);
|
||||
|
||||
return sm->member_name();
|
||||
} /*struct_member_name*/
|
||||
return sm->member_name();
|
||||
} /*struct_member_name*/
|
||||
|
||||
StructMember const *
|
||||
StructTdx::struct_member(uint32_t i) const
|
||||
{
|
||||
if (i >= this->member_v_.size()) {
|
||||
/* TODO: raise exception here */
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
StructMember const *
|
||||
StructTdx::struct_member(uint32_t i) const
|
||||
{
|
||||
if (i >= this->member_v_.size()) {
|
||||
/* TODO: raise exception here */
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &(this->member_v_[i]);
|
||||
} /*struct_member*/
|
||||
} /*namespace reflect*/
|
||||
return &(this->member_v_[i]);
|
||||
} /*struct_member*/
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end StructTdx.cpp */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue