diff --git a/include/xo/reflect/StructReflector.hpp b/include/xo/reflect/StructReflector.hpp index 750b8669..220990a5 100644 --- a/include/xo/reflect/StructReflector.hpp +++ b/include/xo/reflect/StructReflector.hpp @@ -9,153 +9,154 @@ #include namespace xo { - namespace reflect { - template - class SelfTagger {}; + namespace reflect { + template + class SelfTagger {}; - template - struct SelfTagger { - static TaggedPtr self_tp(void * object) { - return (reinterpret_cast(object))->self_tp(); - } - }; + template + struct SelfTagger { + static TaggedPtr self_tp(void * object) { + return (reinterpret_cast(object))->self_tp(); + } + }; - template - struct SelfTagger { - static TaggedPtr self_tp(void * /*object*/) { assert(false); return TaggedPtr::universal_null(); } - }; + template + struct SelfTagger { + 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 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 + class StructReflector { + public: + using struct_t = StructT; + + public: + StructReflector() : td_{EstablishTypeDescr::establish()} {} + ~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 + void reflect_member(std::string const & member_name, + MemberT OwnerT::* member_addr) { + + auto accessor + (GeneralStructMemberAccessor::make(member_addr)); + + /* used to do this in GeneralStructMemberAccessor<> ctor, + * but that introduces #include cycle + */ + Reflect::require(); + + 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; + + /* if self-tagging, can use .self_tp() to get most-derived tagged pointer */ + auto to_self_tp_fn + = ([](void * object) + { + return SelfTagger::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 + void adopt_ancestors() { + assert(Reflect::is_reflected()); + + TypeDescr ancestor_td = Reflect::require(); + + /* 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()); + } + } /*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 member_v_; + }; /*StructReflector*/ + + template + bool StructReflector::s_reflected_flag = false; + } /*namespace reflect*/ + + /* e.g. + * struct Foo { int bar_; }; + * struct Bar : public Foo { .. }; * - * Use: - * struct Foo { int x_; double y_; }; - * - * StructReflector 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 sr; + * REFLECT_EXPLICIT_MEMBER(sr, "bar", &Foo::bar_); */ - template - class StructReflector { - public: - using struct_t = StructT; - - public: - StructReflector() : td_{EstablishTypeDescr::establish()} {} - ~StructReflector() { - this->require_complete(); - } - - bool is_complete() const { return s_reflected_flag; } - bool is_incomplete() const { return !s_reflected_flag; } - - template - void reflect_member(std::string const & member_name, - MemberT OwnerT::* member_addr) { - - auto accessor - (GeneralStructMemberAccessor::make(member_addr)); - - /* used to do this in GeneralStructMemberAccessor<> ctor, - * but that introduces #include cycle - */ - Reflect::require(); - - 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; - - /* if self-tagging, can use .self_tp() to get most-derived tagged pointer */ - auto to_self_tp_fn - = ([](void * object) - { - return SelfTagger::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 - void adopt_ancestors() { - assert(Reflect::is_reflected()); - - TypeDescr ancestor_td = Reflect::require(); - - /* 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()); - } - } /*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 member_v_; - }; /*StructReflector*/ - - template - bool StructReflector::s_reflected_flag = false; - } /*namespace reflect*/ - - /* e.g. - * struct Foo { int bar_; }; - * struct Bar : public Foo { .. }; - * - * StructReflector 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 sr; - * REFLECT_LITERAL_MEMBER(sr, bar_); - * - * then REFLECT_LITERAL_MEMBER() expands to something like: - * sr.reflect_member("bar_", &StructReflector::struct_t::bar_) - */ + /* e.g. + * struct Foo { int bar_; }; + * + * StructReflector sr; + * REFLECT_LITERAL_MEMBER(sr, bar_); + * + * then REFLECT_LITERAL_MEMBER() expands to something like: + * sr.reflect_member("bar_", &StructReflector::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 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 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*/ diff --git a/include/xo/reflect/TypeDescr.hpp b/include/xo/reflect/TypeDescr.hpp index 31c58063..034f9e1c 100644 --- a/include/xo/reflect/TypeDescr.hpp +++ b/include/xo/reflect/TypeDescr.hpp @@ -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: diff --git a/include/xo/reflect/TypeDescrExtra.hpp b/include/xo/reflect/TypeDescrExtra.hpp index bef9463e..68291654 100644 --- a/include/xo/reflect/TypeDescrExtra.hpp +++ b/include/xo/reflect/TypeDescrExtra.hpp @@ -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() diff --git a/include/xo/reflect/atomic/AtomicTdx.hpp b/include/xo/reflect/atomic/AtomicTdx.hpp index 98e10cfe..9bd5e567 100644 --- a/include/xo/reflect/atomic/AtomicTdx.hpp +++ b/include/xo/reflect/atomic/AtomicTdx.hpp @@ -7,31 +7,32 @@ #include 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 make(); + static std::unique_ptr 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 */ diff --git a/include/xo/reflect/function/FunctionTdx.hpp b/include/xo/reflect/function/FunctionTdx.hpp index 5d2f57c2..64b02da3 100644 --- a/include/xo/reflect/function/FunctionTdx.hpp +++ b/include/xo/reflect/function/FunctionTdx.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; diff --git a/include/xo/reflect/reflect_struct.hpp b/include/xo/reflect/reflect_struct.hpp new file mode 100644 index 00000000..8c0c843a --- /dev/null +++ b/include/xo/reflect/reflect_struct.hpp @@ -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 will separately + * have been specialized for T. + * See discussion in [reflect_struct_info.hpp] + * + * + **/ + template + 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 * p_sr) { + const auto & member_info + = reflect_struct_member().get(); + + p_sr->reflect_member(member_info.member_name_.c_str(), + member_info.member_addr_); + + /** reflect remaining members **/ + sr_member_helper::add_members_from(p_sr); + } + }; + + template + struct sr_member_helper { + /** base case -- all members have been refleccted **/ + static void add_members_from(StructReflector *) {} + }; + } /*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() instead + **/ + template + TypeDescr reflect_struct() { + StructReflector sr; + + if (sr.is_incomplete()) + detail::sr_member_helper::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 **/ diff --git a/include/xo/reflect/struct/StructMember.hpp b/include/xo/reflect/struct/StructMember.hpp index 3c7bab62..e7b76413 100644 --- a/include/xo/reflect/struct/StructMember.hpp +++ b/include/xo/reflect/struct/StructMember.hpp @@ -9,227 +9,227 @@ #include 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(); - */ - 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(); + */ + 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 clone() const = 0; - }; /*AbstractStructMemberAccessor*/ + virtual std::unique_ptr 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 - 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 + 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()}, - memptr_{memptr} {} - GeneralStructMemberAccessor(GeneralStructMemberAccessor const & x) = default; - virtual ~GeneralStructMemberAccessor() = default; + public: + GeneralStructMemberAccessor(Memptr memptr) : member_td_{EstablishTypeDescr::establish()}, + memptr_{memptr} {} + GeneralStructMemberAccessor(GeneralStructMemberAccessor const & x) = default; + virtual ~GeneralStructMemberAccessor() = default; - static std::unique_ptr make(Memptr memptr) { - return std::unique_ptr(new GeneralStructMemberAccessor(memptr)); } + static std::unique_ptr make(Memptr memptr) { + return std::unique_ptr(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(); } + virtual TypeDescr struct_td() const override { return EstablishTypeDescr::establish(); } - 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(struct_addr)); - } /*address*/ + virtual void * address(void * struct_addr) const override { + return this->address_impl(reinterpret_cast(struct_addr)); + } /*address*/ - virtual std::unique_ptr clone() const override { - return std::unique_ptr - (new GeneralStructMemberAccessor(*this)); - } /*clone*/ + virtual std::unique_ptr clone() const override { + return std::unique_ptr + (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::make(&Foo::x_); - * - * or equivalently: - * auto foo_x_access = GeneralStructMemberAccessor::make(&Foo::x_); - * auto bar_x_access = AncestorStructMemberAccessor::adopt(foo_x_access); - * - * can use the 2nd form to adopt accessors from an already-reflected ancestor class - * - * Require: - * - StructT -isa-> AncestorT - */ - template - class AncestorStructMemberAccessor : public AbstractStructMemberAccessor { - public: - AncestorStructMemberAccessor(std::unique_ptr 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::make(&Foo::x_); + * + * or equivalently: + * auto foo_x_access = GeneralStructMemberAccessor::make(&Foo::x_); + * auto bar_x_access = AncestorStructMemberAccessor::adopt(foo_x_access); + * + * can use the 2nd form to adopt accessors from an already-reflected ancestor class + * + * Require: + * - StructT -isa-> AncestorT + */ + template + class AncestorStructMemberAccessor : public AbstractStructMemberAccessor { + public: + AncestorStructMemberAccessor(std::unique_ptr ancestor_accessor) + : ancestor_accessor_{std::move(ancestor_accessor)} {} + AncestorStructMemberAccessor(AncestorStructMemberAccessor const & x) = default; + virtual ~AncestorStructMemberAccessor() = default; - static std::unique_ptr - adopt(std::unique_ptr ancestor_accessor) { - return std::unique_ptr - (new AncestorStructMemberAccessor(std::move(ancestor_accessor))); - } /*adopt*/ + static std::unique_ptr + adopt(std::unique_ptr ancestor_accessor) { + return std::unique_ptr + (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(struct_addr); + virtual TaggedPtr member_tp(void * struct_addr) const override { + AncestorT * ancestor_addr = reinterpret_cast(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(); } - virtual TypeDescr member_td() const override { return this->ancestor_accessor_->member_td(); } + virtual TypeDescr struct_td() const override { return EstablishTypeDescr::establish(); } + 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(struct_addr)); - } + virtual void * address(void * struct_addr) const override { + return this->address_impl(reinterpret_cast(struct_addr)); + } - virtual std::unique_ptr clone() const override { - return std::unique_ptr - (new AncestorStructMemberAccessor(std::move(this->ancestor_accessor_->clone()))); - } /*clone*/ + virtual std::unique_ptr clone() const override { + return std::unique_ptr + (new AncestorStructMemberAccessor(std::move(this->ancestor_accessor_->clone()))); + } /*clone*/ - private: - /* .ancestor_accessor fetches some particular member of AncestorT */ - std::unique_ptr ancestor_accessor_; - }; /*AncestorStructMemberAccessor*/ + private: + /* .ancestor_accessor fetches some particular member of AncestorT */ + std::unique_ptr 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 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 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 - StructMember for_descendant() const { - assert(EstablishTypeDescr::establish() == 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 + StructMember for_descendant() const { + assert(EstablishTypeDescr::establish() == this->get_struct_td()); - return StructMember(this->member_name(), - std::move(AncestorStructMemberAccessor::adopt - (std::move(this->accessor_->clone())))); - } /*for_descendant*/ + return StructMember(this->member_name(), + std::move(AncestorStructMemberAccessor::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 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 accessor_; + }; /*StructMember*/ + } /*namespace reflect*/ } /*namespace xo*/ /* end StructMember.hpp */ diff --git a/include/xo/reflect/struct/StructTdx.hpp b/include/xo/reflect/struct/StructTdx.hpp index 15eebe9b..0cd524d8 100644 --- a/include/xo/reflect/struct/StructTdx.hpp +++ b/include/xo/reflect/struct/StructTdx.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; diff --git a/include/xo/reflect/vector/VectorTdx.hpp b/include/xo/reflect/vector/VectorTdx.hpp index 84e414b4..dcdc20c1 100644 --- a/include/xo/reflect/vector/VectorTdx.hpp +++ b/include/xo/reflect/vector/VectorTdx.hpp @@ -17,10 +17,14 @@ namespace xo { /* named ctor idiom. create new instance for a vector type */ //static std::unique_ptr 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(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(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(object); @@ -61,7 +69,10 @@ namespace xo { */ template - using StdArrayTdx = StlVectorTdx>; + class StdArrayTdx : public StlVectorTdx> { + virtual uint32_t n_child(void * /*object*/) const override { return N; } + virtual uint32_t n_child_fixed() const override { return N; } + }; /*StdArrayTdx*/ // ----- std::vector ----- @@ -77,12 +88,18 @@ namespace xo { return std::unique_ptr(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(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(object); diff --git a/src/reflect/TypeDescrExtra.cpp b/src/reflect/TypeDescrExtra.cpp index e53a216b..9e82fc8e 100644 --- a/src/reflect/TypeDescrExtra.cpp +++ b/src/reflect/TypeDescrExtra.cpp @@ -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); diff --git a/src/reflect/atomic/AtomicTdx.cpp b/src/reflect/atomic/AtomicTdx.cpp index 2e04ab4d..86e5d5ba 100644 --- a/src/reflect/atomic/AtomicTdx.cpp +++ b/src/reflect/atomic/AtomicTdx.cpp @@ -2,6 +2,7 @@ #include "atomic/AtomicTdx.hpp" #include "TaggedPtr.hpp" +#include namespace xo { namespace reflect { diff --git a/src/reflect/struct/StructTdx.cpp b/src/reflect/struct/StructTdx.cpp index 593ad388..bf969724 100644 --- a/src/reflect/struct/StructTdx.cpp +++ b/src/reflect/struct/StructTdx.cpp @@ -3,53 +3,53 @@ #include "struct/StructTdx.hpp" namespace xo { - using std::uint32_t; + using std::uint32_t; - namespace reflect { - std::unique_ptr - StructTdx::make(std::vector member_v, - bool have_to_self_tp, - std::function to_self_tp) - { - return std::unique_ptr(new StructTdx(std::move(member_v), - have_to_self_tp, - std::move(to_self_tp))); - } /*make*/ + namespace reflect { + std::unique_ptr + StructTdx::make(std::vector member_v, + bool have_to_self_tp, + std::function to_self_tp) + { + return std::unique_ptr(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 */