reflect: insert xo/ subdir into include path
This commit is contained in:
parent
ba95d0a40c
commit
6be9037f10
20 changed files with 179 additions and 184 deletions
161
include/xo/reflect/StructReflector.hpp
Normal file
161
include/xo/reflect/StructReflector.hpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/* @file StructReflector.hpp */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Reflect.hpp"
|
||||
#include "TypeDescr.hpp"
|
||||
#include "struct/StructMember.hpp"
|
||||
#include "struct/StructTdx.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace xo {
|
||||
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, false> {
|
||||
static TaggedPtr self_tp(void * /*object*/) { assert(false); return TaggedPtr::universal_null(); }
|
||||
};
|
||||
|
||||
/* 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; }
|
||||
|
||||
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_)
|
||||
*/
|
||||
#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"
|
||||
*/
|
||||
#define REFLECT_MEMBER(sr, member_name) sr.reflect_member(#member_name, &decltype(sr)::struct_t::member_name##_)
|
||||
|
||||
} /*namespace xo*/
|
||||
Loading…
Add table
Add a link
Reference in a new issue