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"
|
#include "TaggedPtr.hpp"
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
namespace reflect {
|
namespace reflect {
|
||||||
class EstablishTypeDescr {
|
/** @class EstablishTypeDescr
|
||||||
public:
|
* @brief class to establish globally-unique TypeDescr object for a type T
|
||||||
/* implementation method; expect this to be used only within reflect/ library.
|
*
|
||||||
* avoids some otherwise-cyclic #include paths
|
* We don't require the full definition of T to use EstablishTypeDescr::establish<T>().
|
||||||
* between specialized headers such as vector/VectorTdx.hpp and this
|
* In particular, a forward declaration is sufficient.
|
||||||
* EstablishTypeDescr.hpp
|
*
|
||||||
*/
|
* 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
|
#ifdef OBSOLETE
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static TaggedPtr establish_tp(T * x) { return TaggedPtr(establish<T>(), x); }
|
static TaggedPtr establish_tp(T * x) { return TaggedPtr(establish<T>(), x); }
|
||||||
#endif
|
#endif
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static TaggedPtr establish_most_derived_tp(T * x) { return establish<T>()->most_derived_self_tp(x); }
|
static TaggedPtr establish_most_derived_tp(T * x) { return establish<T>()->most_derived_self_tp(x); }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static TypeDescrW establish() {
|
static TypeDescrW establish() {
|
||||||
TypeDescrW td = TypeDescrBase::require(&typeid(T),
|
TypeDescrW td = TypeDescrBase::require(&typeid(T),
|
||||||
type_name<T>(),
|
type_name<T>(),
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
#ifdef NOT_USING
|
#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>) {
|
if (std::is_base_of_v<SelfTagging, T>) {
|
||||||
/* T is a descendant of SelfTagging (or T = SelfTagging);
|
/* T is a descendant of SelfTagging (or T = SelfTagging);
|
||||||
* use SelfTagging.self_tp()
|
* use SelfTagging.self_tp()
|
||||||
*/
|
*/
|
||||||
to_self_tp = [](void * x) { return reinterpret_cast<T *>(x)->self_tp(); };
|
to_self_tp = [](void * x) { return reinterpret_cast<T *>(x)->self_tp(); };
|
||||||
} else {
|
} else {
|
||||||
/* T is not a descendant of SelfTagging.
|
/* T is not a descendant of SelfTagging.
|
||||||
* want to return
|
* want to return
|
||||||
*/
|
*/
|
||||||
to_self_tp = [td](void * x) { return TaggedPtr(td, x); };
|
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
|
#endif
|
||||||
return td;
|
return td;
|
||||||
}
|
}
|
||||||
}; /*EstablishTypeDescr*/
|
}; /*EstablishTypeDescr*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline TaggedPtr establish_most_derived_tp(T * x) {
|
inline TaggedPtr establish_most_derived_tp(T * x) {
|
||||||
return EstablishTypeDescr::establish_most_derived_tp<T>(x);
|
return EstablishTypeDescr::establish_most_derived_tp<T>(x);
|
||||||
}
|
}
|
||||||
} /*namespace reflect*/
|
} /*namespace reflect*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "pointer/PointerTdx.hpp"
|
#include "pointer/PointerTdx.hpp"
|
||||||
#include "vector/VectorTdx.hpp"
|
#include "vector/VectorTdx.hpp"
|
||||||
#include "struct/StructTdx.hpp"
|
#include "struct/StructTdx.hpp"
|
||||||
|
#include "function/FunctionTdx.hpp"
|
||||||
#include "xo/refcnt/Refcounted.hpp"
|
#include "xo/refcnt/Refcounted.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
@ -21,44 +22,69 @@ namespace xo {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class EstablishTdx {
|
class EstablishTdx {
|
||||||
public:
|
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(); }
|
static std::unique_ptr<TypeDescrExtra> make() { return AtomicTdx::make(); }
|
||||||
}; /*EstablishTdx*/
|
};
|
||||||
|
|
||||||
// ----- xo::ref::rp<Object> -----
|
// ----- xo::ref::rp<Object> -----
|
||||||
|
|
||||||
/* definition provide after decl for Reflect {} below */
|
|
||||||
template<typename Object>
|
template<typename Object>
|
||||||
class EstablishTdx<xo::ref::rp<Object>> {
|
class EstablishTdx<xo::ref::rp<Object>> {
|
||||||
public:
|
public:
|
||||||
|
/* definition provide after decl for Reflect {} below */
|
||||||
static std::unique_ptr<TypeDescrExtra> make();
|
static std::unique_ptr<TypeDescrExtra> make();
|
||||||
}; /*EstablishTdx*/
|
};
|
||||||
|
|
||||||
// ----- std::array<Element, N> -----
|
// ----- std::array<Element, N> -----
|
||||||
|
|
||||||
/* definition provide after decl for Reflect {} below */
|
|
||||||
template<typename Element, std::size_t N>
|
template<typename Element, std::size_t N>
|
||||||
class EstablishTdx<std::array<Element, N>> {
|
class EstablishTdx<std::array<Element, N>> {
|
||||||
public:
|
public:
|
||||||
|
/* definition provide after decl for Reflect {} below */
|
||||||
static std::unique_ptr<TypeDescrExtra> make();
|
static std::unique_ptr<TypeDescrExtra> make();
|
||||||
}; /*EstablishTdx*/
|
};
|
||||||
|
|
||||||
// ----- std::vector<Element> -----
|
// ----- std::vector<Element> -----
|
||||||
|
|
||||||
/* definition provide after decl for Reflect {} below */
|
|
||||||
template<typename Element>
|
template<typename Element>
|
||||||
class EstablishTdx<std::vector<Element>> {
|
class EstablishTdx<std::vector<Element>> {
|
||||||
public:
|
public:
|
||||||
|
/* definition provide after decl for Reflect {} below */
|
||||||
static std::unique_ptr<TypeDescrExtra> make();
|
static std::unique_ptr<TypeDescrExtra> make();
|
||||||
}; /*EstablishTdx*/
|
};
|
||||||
|
|
||||||
// ----- std::pair<Lhs, Rhs> -----
|
// ----- std::pair<Lhs, Rhs> -----
|
||||||
|
|
||||||
/* definition provide after decl for Reflect {} below */
|
|
||||||
template<typename Lhs, typename Rhs>
|
template<typename Lhs, typename Rhs>
|
||||||
class EstablishTdx<std::pair<Lhs, Rhs>> {
|
class EstablishTdx<std::pair<Lhs, Rhs>> {
|
||||||
public:
|
public:
|
||||||
|
/* definition provide after decl for Reflect {} below */
|
||||||
static std::unique_ptr<TypeDescrExtra> make();
|
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 -----
|
// ----- MakeTagged -----
|
||||||
|
|
||||||
|
|
@ -229,6 +255,46 @@ namespace xo {
|
||||||
|
|
||||||
return StructTdx::pair<Lhs, Rhs>();
|
return StructTdx::pair<Lhs, Rhs>();
|
||||||
} /*make*/
|
} /*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 reflect*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,10 @@ namespace xo {
|
||||||
void assign_address(void * x) { address_ = x; }
|
void assign_address(void * x) { address_ = x; }
|
||||||
|
|
||||||
bool is_universal_null() const { return (td_ == nullptr) && (address_ == nullptr); }
|
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_vector() const { return td_ && td_->is_vector(); }
|
||||||
bool is_struct() const { return td_ && td_->is_struct(); }
|
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
|
/* returns pointer-to-T, if in fact this tagged pointer is understood
|
||||||
* to refer to a T-instance; otherwise nullptr
|
* to refer to a T-instance; otherwise nullptr
|
||||||
|
|
@ -71,11 +72,16 @@ namespace xo {
|
||||||
|
|
||||||
uint32_t n_child() const {
|
uint32_t n_child() const {
|
||||||
return this->td_->n_child(this->address_);
|
return this->td_->n_child(this->address_);
|
||||||
} /*n_child*/
|
}
|
||||||
|
|
||||||
TaggedPtr get_child(uint32_t i) const {
|
TaggedPtr get_child(uint32_t i) const {
|
||||||
return this->td_->child_tp(i, this->address_);
|
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:
|
/* require:
|
||||||
* - .is_struct() is true
|
* - .is_struct() is true
|
||||||
|
|
|
||||||
|
|
@ -179,8 +179,10 @@ namespace xo {
|
||||||
}
|
}
|
||||||
} /*recover_native*/
|
} /*recover_native*/
|
||||||
|
|
||||||
|
bool is_pointer() const { return this->tdextra_->is_pointer(); }
|
||||||
bool is_vector() const { return this->tdextra_->is_vector(); }
|
bool is_vector() const { return this->tdextra_->is_vector(); }
|
||||||
bool is_struct() const { return this->tdextra_->is_struct(); }
|
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
|
/* given a T-instance object, return tagged pointer with T replaced
|
||||||
* by the most-derived-subtype of T to which *object belongs.
|
* 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 {
|
std::string const & struct_member_name(uint32_t i) const {
|
||||||
return this->tdextra_->struct_member_name(i);
|
return this->tdextra_->struct_member_name(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fetch runtime description for i'th reflected instance variable.
|
/* fetch runtime description for i'th reflected instance variable.
|
||||||
*
|
*
|
||||||
* require:
|
* require:
|
||||||
|
|
@ -216,6 +219,14 @@ namespace xo {
|
||||||
return *sm;
|
return *sm;
|
||||||
} /*struct_member*/
|
} /*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;
|
void display(std::ostream & os) const;
|
||||||
std::string display_string() const;
|
std::string display_string() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,58 +8,70 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
namespace reflect {
|
namespace reflect {
|
||||||
/* forward-declaring here. see [reflect/struct/StructMember.hpp] */
|
/* forward-declaring here. see [reflect/struct/StructMember.hpp] */
|
||||||
class StructMember;
|
class StructMember;
|
||||||
class TypeDescrBase;
|
class TypeDescrBase;
|
||||||
class TaggedPtr;
|
class TaggedPtr;
|
||||||
|
|
||||||
/* information associated with a c++ type.
|
/* information associated with a c++ type.
|
||||||
* distinct from TypeDescrImpl:
|
* distinct from TypeDescrImpl:
|
||||||
* 1. want to use reflection to support for runtime polymorphism over similar but
|
* 1. want to use reflection to support for runtime polymorphism over similar but
|
||||||
* not directly-related types: for example
|
* not directly-related types: for example
|
||||||
* std::vector<int>
|
* std::vector<int>
|
||||||
* and
|
* and
|
||||||
* std::list<std::string>
|
* std::list<std::string>
|
||||||
* are both ordered collections
|
* are both ordered collections
|
||||||
* 2. some information can't be universally established via template-fu,
|
* 2. some information can't be universally established via template-fu,
|
||||||
* for example struct member names
|
* for example struct member names
|
||||||
* 3. descriptions for recursive types require 2-stage construction
|
* 3. descriptions for recursive types require 2-stage construction
|
||||||
*
|
*
|
||||||
* A TypeDescrImpl instance will contain a pointer to a suitable
|
* A TypeDescrImpl instance will contain a pointer to a suitable
|
||||||
* TypeDescrExtra instance.
|
* TypeDescrExtra instance.
|
||||||
*
|
*
|
||||||
* The single TypeDescrImpl instance for some type T can be established
|
* The single TypeDescrImpl instance for some type T can be established
|
||||||
* automatically, see Reflect::require().
|
* automatically, see Reflect::require().
|
||||||
*
|
*
|
||||||
* A specific TypeDescrExtra instance may be attached in a non-automated way
|
* A specific TypeDescrExtra instance may be attached in a non-automated way
|
||||||
* later
|
* later
|
||||||
*/
|
*/
|
||||||
class TypeDescrExtra {
|
class TypeDescrExtra {
|
||||||
public:
|
public:
|
||||||
using uint32_t = std::uint32_t;
|
using uint32_t = std::uint32_t;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~TypeDescrExtra() = default;
|
virtual ~TypeDescrExtra() = default;
|
||||||
|
|
||||||
bool is_vector() const { return this->metatype() == Metatype::mt_vector; }
|
bool is_pointer() const { return this->metatype() == Metatype::mt_pointer; }
|
||||||
bool is_struct() const { return this->metatype() == Metatype::mt_struct; }
|
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;
|
virtual Metatype metatype() const = 0;
|
||||||
/* given a T-instance, report most-derived subtype of T to which *object belongs.
|
/* 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.
|
* 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 TaggedPtr most_derived_self_tp(TypeDescrBase const * object_td, void * object) const;
|
||||||
virtual uint32_t n_child(void * object) const = 0;
|
virtual uint32_t n_child(void * object) const = 0;
|
||||||
virtual TaggedPtr child_tp(uint32_t i, void * object) const = 0;
|
virtual TaggedPtr child_tp(uint32_t i, void * object) const = 0;
|
||||||
/* require:
|
/* require:
|
||||||
* .is_struct()
|
* .is_struct()
|
||||||
*/
|
*/
|
||||||
virtual std::string const & struct_member_name(uint32_t i) const = 0;
|
virtual std::string const & struct_member_name(uint32_t i) const = 0;
|
||||||
/* nullptr unless *this represents a struct/class type */
|
/* nullptr unless *this represents a struct/class type */
|
||||||
virtual StructMember const * struct_member(uint32_t i) const;
|
virtual StructMember const * struct_member(uint32_t i) const;
|
||||||
}; /*TypeDescrExtra*/
|
|
||||||
} /*namespace reflect*/
|
// 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*/
|
} /*namespace xo*/
|
||||||
|
|
||||||
/* end TypeDescrExtra.hpp */
|
/* end TypeDescrExtra.hpp */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue