xo-reflect: automatically reflecct function pointers
This commit is contained in:
parent
ec365d8b6f
commit
ef191b136e
5 changed files with 209 additions and 101 deletions
|
|
@ -9,53 +9,66 @@
|
|||
#include "TaggedPtr.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace reflect {
|
||||
class EstablishTypeDescr {
|
||||
public:
|
||||
/* implementation method; expect this to be used only within reflect/ library.
|
||||
* avoids some otherwise-cyclic #include paths
|
||||
* between specialized headers such as vector/VectorTdx.hpp and this
|
||||
* EstablishTypeDescr.hpp
|
||||
*/
|
||||
namespace reflect {
|
||||
/** @class EstablishTypeDescr
|
||||
* @brief class to establish globally-unique TypeDescr object for a type T
|
||||
*
|
||||
* We don't require the full definition of T to use EstablishTypeDescr::establish<T>().
|
||||
* In particular, a forward declaration is sufficient.
|
||||
*
|
||||
* Additional information (that depends on full definition) may be attached later,
|
||||
* by assigning (once-only) to @ref TypeDescr::tdextra_
|
||||
*
|
||||
* @note Application code will use @ref Reflect::require; that in turn relies on the
|
||||
* template @ref EstablishTdx to leverage template pattern-matching for
|
||||
* recurring patterns.
|
||||
**/
|
||||
class EstablishTypeDescr {
|
||||
public:
|
||||
/* implementation method; expect this to be used only within reflect/ library.
|
||||
* avoids some otherwise-cyclic #include paths
|
||||
* between specialized headers such as vector/VectorTdx.hpp and this
|
||||
* EstablishTypeDescr.hpp
|
||||
*/
|
||||
#ifdef OBSOLETE
|
||||
template<typename T>
|
||||
static TaggedPtr establish_tp(T * x) { return TaggedPtr(establish<T>(), x); }
|
||||
template<typename T>
|
||||
static TaggedPtr establish_tp(T * x) { return TaggedPtr(establish<T>(), x); }
|
||||
#endif
|
||||
template<typename T>
|
||||
static TaggedPtr establish_most_derived_tp(T * x) { return establish<T>()->most_derived_self_tp(x); }
|
||||
template<typename T>
|
||||
static TaggedPtr establish_most_derived_tp(T * x) { return establish<T>()->most_derived_self_tp(x); }
|
||||
|
||||
template<typename T>
|
||||
static TypeDescrW establish() {
|
||||
TypeDescrW td = TypeDescrBase::require(&typeid(T),
|
||||
type_name<T>(),
|
||||
nullptr);
|
||||
template<typename T>
|
||||
static TypeDescrW establish() {
|
||||
TypeDescrW td = TypeDescrBase::require(&typeid(T),
|
||||
type_name<T>(),
|
||||
nullptr);
|
||||
|
||||
#ifdef NOT_USING
|
||||
std::function<TaggedPtr (void *)> to_self_tp;
|
||||
std::function<TaggedPtr (void *)> to_self_tp;
|
||||
|
||||
if (std::is_base_of_v<SelfTagging, T>) {
|
||||
/* T is a descendant of SelfTagging (or T = SelfTagging);
|
||||
* use SelfTagging.self_tp()
|
||||
*/
|
||||
to_self_tp = [](void * x) { return reinterpret_cast<T *>(x)->self_tp(); };
|
||||
} else {
|
||||
/* T is not a descendant of SelfTagging.
|
||||
* want to return
|
||||
*/
|
||||
to_self_tp = [td](void * x) { return TaggedPtr(td, x); };
|
||||
}
|
||||
if (std::is_base_of_v<SelfTagging, T>) {
|
||||
/* T is a descendant of SelfTagging (or T = SelfTagging);
|
||||
* use SelfTagging.self_tp()
|
||||
*/
|
||||
to_self_tp = [](void * x) { return reinterpret_cast<T *>(x)->self_tp(); };
|
||||
} else {
|
||||
/* T is not a descendant of SelfTagging.
|
||||
* want to return
|
||||
*/
|
||||
to_self_tp = [td](void * x) { return TaggedPtr(td, x); };
|
||||
}
|
||||
|
||||
td->assign_to_self_tp(to_self_tp);
|
||||
td->assign_to_self_tp(to_self_tp);
|
||||
#endif
|
||||
return td;
|
||||
}
|
||||
}; /*EstablishTypeDescr*/
|
||||
return td;
|
||||
}
|
||||
}; /*EstablishTypeDescr*/
|
||||
|
||||
template<typename T>
|
||||
inline TaggedPtr establish_most_derived_tp(T * x) {
|
||||
return EstablishTypeDescr::establish_most_derived_tp<T>(x);
|
||||
}
|
||||
} /*namespace reflect*/
|
||||
template<typename T>
|
||||
inline TaggedPtr establish_most_derived_tp(T * x) {
|
||||
return EstablishTypeDescr::establish_most_derived_tp<T>(x);
|
||||
}
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "pointer/PointerTdx.hpp"
|
||||
#include "vector/VectorTdx.hpp"
|
||||
#include "struct/StructTdx.hpp"
|
||||
#include "function/FunctionTdx.hpp"
|
||||
#include "xo/refcnt/Refcounted.hpp"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
|
@ -21,44 +22,69 @@ namespace xo {
|
|||
template<typename T>
|
||||
class EstablishTdx {
|
||||
public:
|
||||
/** Create auxiliary reflection info for type @tparam T,
|
||||
* once full definition is available.
|
||||
*
|
||||
* This includes:
|
||||
* - metatype
|
||||
* - component structure (types for navigable component objects)
|
||||
*
|
||||
**/
|
||||
static std::unique_ptr<TypeDescrExtra> make() { return AtomicTdx::make(); }
|
||||
}; /*EstablishTdx*/
|
||||
};
|
||||
|
||||
// ----- xo::ref::rp<Object> -----
|
||||
|
||||
/* definition provide after decl for Reflect {} below */
|
||||
template<typename Object>
|
||||
class EstablishTdx<xo::ref::rp<Object>> {
|
||||
public:
|
||||
/* definition provide after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
}; /*EstablishTdx*/
|
||||
};
|
||||
|
||||
// ----- std::array<Element, N> -----
|
||||
|
||||
/* definition provide after decl for Reflect {} below */
|
||||
template<typename Element, std::size_t N>
|
||||
class EstablishTdx<std::array<Element, N>> {
|
||||
public:
|
||||
/* definition provide after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
}; /*EstablishTdx*/
|
||||
};
|
||||
|
||||
// ----- std::vector<Element> -----
|
||||
|
||||
/* definition provide after decl for Reflect {} below */
|
||||
template<typename Element>
|
||||
class EstablishTdx<std::vector<Element>> {
|
||||
public:
|
||||
/* definition provide after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
}; /*EstablishTdx*/
|
||||
};
|
||||
|
||||
// ----- std::pair<Lhs, Rhs> -----
|
||||
|
||||
/* definition provide after decl for Reflect {} below */
|
||||
template<typename Lhs, typename Rhs>
|
||||
class EstablishTdx<std::pair<Lhs, Rhs>> {
|
||||
public:
|
||||
/* definition provide after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
}; /*EstablishTdx*/
|
||||
};
|
||||
|
||||
// ----- Retval (*)(A1 .. An) -----
|
||||
|
||||
template<typename Retval, typename... Args>
|
||||
class EstablishTdx<Retval(*)(Args...)> {
|
||||
public:
|
||||
/* definition provided after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
};
|
||||
|
||||
// ----- Retval (*)() -----
|
||||
|
||||
template <typename Retval>
|
||||
class EstablishTdx<Retval(*)()> {
|
||||
/* definition provided after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
};
|
||||
|
||||
// ----- MakeTagged -----
|
||||
|
||||
|
|
@ -229,6 +255,46 @@ namespace xo {
|
|||
|
||||
return StructTdx::pair<Lhs, Rhs>();
|
||||
} /*make*/
|
||||
|
||||
// ----- Retval (*) (A1 .. An) -----
|
||||
|
||||
namespace detail {
|
||||
/** @class AssembleArgv
|
||||
* @brief create vector of complete TypeDescr objects comprising all template arguments
|
||||
*
|
||||
* Use:
|
||||
* std::vector<TypeDescr> v;
|
||||
* AssembleArgv<Arg1, .., Argn>::append_argv(&v);
|
||||
* // do something with v
|
||||
**/
|
||||
template <typename... Args>
|
||||
struct AssembleArgv;
|
||||
|
||||
template <>
|
||||
struct AssembleArgv<> {
|
||||
static void append_argv(std::vector<TypeDescr> * p_v) {}
|
||||
};
|
||||
|
||||
template <typename Arg, typename... Rest>
|
||||
struct AssembleArgv<Arg, Rest...> {
|
||||
static void append_argv(std::vector<TypeDescr> * p_v) {
|
||||
p_v->push_back(Reflect::require<Arg>());
|
||||
AssembleArgv<Rest...>::append_argv(p_v);
|
||||
}
|
||||
};
|
||||
} /*detail*/
|
||||
|
||||
/* declared above before
|
||||
* class Reflect { ... }
|
||||
*/
|
||||
template <typename Retval, typename... Args>
|
||||
std::unique_ptr<TypeDescrExtra>
|
||||
EstablishTdx<Retval (*)(Args...)>::make() {
|
||||
std::vector<TypeDescr> argv;
|
||||
detail::AssembleArgv<Args...>::append_argv(&argv);
|
||||
|
||||
return FunctionTdx::make_function(Reflect::require<Retval>(), std::move(argv));
|
||||
}
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -59,9 +59,10 @@ namespace xo {
|
|||
void assign_address(void * x) { address_ = x; }
|
||||
|
||||
bool is_universal_null() const { return (td_ == nullptr) && (address_ == nullptr); }
|
||||
bool is_pointer() const { return td_ && td_->is_pointer(); }
|
||||
bool is_vector() const { return td_ && td_->is_vector(); }
|
||||
bool is_struct() const { return td_ && td_->is_struct(); }
|
||||
|
||||
bool is_function() const { return td_ && td_->is_function(); }
|
||||
|
||||
/* returns pointer-to-T, if in fact this tagged pointer is understood
|
||||
* to refer to a T-instance; otherwise nullptr
|
||||
|
|
@ -71,11 +72,16 @@ namespace xo {
|
|||
|
||||
uint32_t n_child() const {
|
||||
return this->td_->n_child(this->address_);
|
||||
} /*n_child*/
|
||||
}
|
||||
|
||||
TaggedPtr get_child(uint32_t i) const {
|
||||
return this->td_->child_tp(i, this->address_);
|
||||
} /*get_child*/
|
||||
}
|
||||
|
||||
/* if reflected function (.is_function() = true):
|
||||
* number of arguments to that function
|
||||
*/
|
||||
uint32_t n_fn_arg() const { return this->td_->n_fn_arg(); }
|
||||
|
||||
/* require:
|
||||
* - .is_struct() is true
|
||||
|
|
|
|||
|
|
@ -179,8 +179,10 @@ namespace xo {
|
|||
}
|
||||
} /*recover_native*/
|
||||
|
||||
bool is_pointer() const { return this->tdextra_->is_pointer(); }
|
||||
bool is_vector() const { return this->tdextra_->is_vector(); }
|
||||
bool is_struct() const { return this->tdextra_->is_struct(); }
|
||||
bool is_function() const { return this->tdextra_->is_function(); }
|
||||
|
||||
/* given a T-instance object, return tagged pointer with T replaced
|
||||
* by the most-derived-subtype of T to which *object belongs.
|
||||
|
|
@ -203,6 +205,7 @@ namespace xo {
|
|||
std::string const & struct_member_name(uint32_t i) const {
|
||||
return this->tdextra_->struct_member_name(i);
|
||||
}
|
||||
|
||||
/* fetch runtime description for i'th reflected instance variable.
|
||||
*
|
||||
* require:
|
||||
|
|
@ -216,6 +219,14 @@ namespace xo {
|
|||
return *sm;
|
||||
} /*struct_member*/
|
||||
|
||||
uint32_t n_fn_arg() const { return this->tdextra_->n_fn_arg(); }
|
||||
|
||||
/* require:
|
||||
* - .is_function() = true
|
||||
*/
|
||||
TypeDescr fn_retval() const { return this->tdextra_->fn_retval(); }
|
||||
TypeDescr fn_arg(uint32_t i) const { return this->tdextra_->fn_arg(i); }
|
||||
|
||||
void display(std::ostream & os) const;
|
||||
std::string display_string() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,58 +8,70 @@
|
|||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace reflect {
|
||||
/* forward-declaring here. see [reflect/struct/StructMember.hpp] */
|
||||
class StructMember;
|
||||
class TypeDescrBase;
|
||||
class TaggedPtr;
|
||||
namespace reflect {
|
||||
/* forward-declaring here. see [reflect/struct/StructMember.hpp] */
|
||||
class StructMember;
|
||||
class TypeDescrBase;
|
||||
class TaggedPtr;
|
||||
|
||||
/* information associated with a c++ type.
|
||||
* distinct from TypeDescrImpl:
|
||||
* 1. want to use reflection to support for runtime polymorphism over similar but
|
||||
* not directly-related types: for example
|
||||
* std::vector<int>
|
||||
* and
|
||||
* std::list<std::string>
|
||||
* are both ordered collections
|
||||
* 2. some information can't be universally established via template-fu,
|
||||
* for example struct member names
|
||||
* 3. descriptions for recursive types require 2-stage construction
|
||||
*
|
||||
* A TypeDescrImpl instance will contain a pointer to a suitable
|
||||
* TypeDescrExtra instance.
|
||||
*
|
||||
* The single TypeDescrImpl instance for some type T can be established
|
||||
* automatically, see Reflect::require().
|
||||
*
|
||||
* A specific TypeDescrExtra instance may be attached in a non-automated way
|
||||
* later
|
||||
*/
|
||||
class TypeDescrExtra {
|
||||
public:
|
||||
using uint32_t = std::uint32_t;
|
||||
/* information associated with a c++ type.
|
||||
* distinct from TypeDescrImpl:
|
||||
* 1. want to use reflection to support for runtime polymorphism over similar but
|
||||
* not directly-related types: for example
|
||||
* std::vector<int>
|
||||
* and
|
||||
* std::list<std::string>
|
||||
* are both ordered collections
|
||||
* 2. some information can't be universally established via template-fu,
|
||||
* for example struct member names
|
||||
* 3. descriptions for recursive types require 2-stage construction
|
||||
*
|
||||
* A TypeDescrImpl instance will contain a pointer to a suitable
|
||||
* TypeDescrExtra instance.
|
||||
*
|
||||
* The single TypeDescrImpl instance for some type T can be established
|
||||
* automatically, see Reflect::require().
|
||||
*
|
||||
* A specific TypeDescrExtra instance may be attached in a non-automated way
|
||||
* later
|
||||
*/
|
||||
class TypeDescrExtra {
|
||||
public:
|
||||
using uint32_t = std::uint32_t;
|
||||
|
||||
public:
|
||||
virtual ~TypeDescrExtra() = default;
|
||||
public:
|
||||
virtual ~TypeDescrExtra() = default;
|
||||
|
||||
bool is_vector() const { return this->metatype() == Metatype::mt_vector; }
|
||||
bool is_struct() const { return this->metatype() == Metatype::mt_struct; }
|
||||
bool is_pointer() const { return this->metatype() == Metatype::mt_pointer; }
|
||||
bool is_vector() const { return this->metatype() == Metatype::mt_vector; }
|
||||
bool is_struct() const { return this->metatype() == Metatype::mt_struct; }
|
||||
bool is_function() const { return this->metatype() == Metatype::mt_function; }
|
||||
|
||||
virtual Metatype metatype() const = 0;
|
||||
/* given a T-instance, report most-derived subtype of T to which *object belongs.
|
||||
* this works only for types that are derived from reflect::SelfTagging.
|
||||
*/
|
||||
virtual TaggedPtr most_derived_self_tp(TypeDescrBase const * object_td, void * object) const;
|
||||
virtual uint32_t n_child(void * object) const = 0;
|
||||
virtual TaggedPtr child_tp(uint32_t i, void * object) const = 0;
|
||||
/* require:
|
||||
* .is_struct()
|
||||
*/
|
||||
virtual std::string const & struct_member_name(uint32_t i) const = 0;
|
||||
/* nullptr unless *this represents a struct/class type */
|
||||
virtual StructMember const * struct_member(uint32_t i) const;
|
||||
}; /*TypeDescrExtra*/
|
||||
} /*namespace reflect*/
|
||||
virtual Metatype metatype() const = 0;
|
||||
/* given a T-instance, report most-derived subtype of T to which *object belongs.
|
||||
* this works only for types that are derived from reflect::SelfTagging.
|
||||
*/
|
||||
virtual TaggedPtr most_derived_self_tp(TypeDescrBase const * object_td, void * object) const;
|
||||
virtual uint32_t n_child(void * object) const = 0;
|
||||
virtual TaggedPtr child_tp(uint32_t i, void * object) const = 0;
|
||||
/* require:
|
||||
* .is_struct()
|
||||
*/
|
||||
virtual std::string const & struct_member_name(uint32_t i) const = 0;
|
||||
/* nullptr unless *this represents a struct/class type */
|
||||
virtual StructMember const * struct_member(uint32_t i) const;
|
||||
|
||||
// methods for working with reflected functions/methods
|
||||
|
||||
/** number of arguments to function-like value
|
||||
*
|
||||
* @pre @ref TypeDescrExtra::is_function() is true
|
||||
**/
|
||||
virtual uint32_t n_fn_arg() const { return 0; }
|
||||
virtual const TypeDescrBase * fn_retval() const { return nullptr; }
|
||||
virtual const TypeDescrBase * fn_arg(uint32_t /*i_arg*/) const { return nullptr; }
|
||||
}; /*TypeDescrExtra*/
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end TypeDescrExtra.hpp */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue