xo-reflect: + EstablishFunctionTdx + bugfix deducing fptr inputs
This commit is contained in:
parent
6c856be0fc
commit
515cedf160
5 changed files with 133 additions and 18 deletions
|
|
@ -72,16 +72,38 @@ namespace xo {
|
|||
// ----- Retval (*)(A1 .. An) -----
|
||||
|
||||
template<typename Retval, typename... Args>
|
||||
class EstablishTdx<Retval(*)(Args...)> {
|
||||
class EstablishTdx<Retval (*)(Args...)> {
|
||||
public:
|
||||
/* definition provided after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
};
|
||||
|
||||
// ----- Retval (*)() -----
|
||||
// ----- Retval (*)(A1 .. An) noexcept -----
|
||||
|
||||
template <typename Retval>
|
||||
class EstablishTdx<Retval(*)()> {
|
||||
template<typename Retval, typename... Args>
|
||||
class EstablishTdx<Retval (*)(Args...) noexcept> {
|
||||
public:
|
||||
/* definition provided after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
};
|
||||
|
||||
// ----- EstasblishFunctionTdx -------------------------------------
|
||||
|
||||
template <typename T>
|
||||
class EstablishFunctionTdx;
|
||||
|
||||
// ----- Retval (*)(A1 .. An) -----
|
||||
|
||||
template<typename Retval, typename... Args>
|
||||
class EstablishFunctionTdx<Retval (*)(Args...)> {
|
||||
public:
|
||||
/* definition provided after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
};
|
||||
|
||||
template<typename Retval, typename... Args>
|
||||
class EstablishFunctionTdx<Retval (*)(Args...) noexcept> {
|
||||
public:
|
||||
/* definition provided after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
};
|
||||
|
|
@ -170,6 +192,41 @@ namespace xo {
|
|||
return retval_td;
|
||||
} /*require*/
|
||||
|
||||
/* can optionally use this when reflecting a function pointer.
|
||||
* Should get the same result as reflect<T>(),
|
||||
* but will not fallback to AtomicTdx if T is not recognized as a function pointer
|
||||
*/
|
||||
template <typename T>
|
||||
static TypeDescrW require_function() {
|
||||
//static_assert(std::is_function_v<T>);
|
||||
|
||||
TypeDescrW retval_td = EstablishTypeDescr::establish<T>();
|
||||
|
||||
/* mark TypeDescr for T as complete (even though it isn't quite yet),
|
||||
* so that when we encounter recursive types, reflection terminates.
|
||||
* For example consider type resulting from code like
|
||||
*
|
||||
* typename T;
|
||||
* using T = std::vector<T *>;
|
||||
*
|
||||
*/
|
||||
if (retval_td->mark_complete()) {
|
||||
/* control here on 2nd+later calls to require<T>().
|
||||
* in principle can immediately short-circuit.
|
||||
*/
|
||||
} else {
|
||||
/* control comes here the first time require<T>() runs */
|
||||
|
||||
auto final_tdx = EstablishFunctionTdx<T>::make();
|
||||
|
||||
retval_td->assign_tdextra(std::move(final_tdx));
|
||||
|
||||
/* also need to require for each child */
|
||||
}
|
||||
|
||||
return retval_td;
|
||||
}
|
||||
|
||||
/* Use:
|
||||
* T * xyz = ...;
|
||||
* TaggedPtr xyz_tp = Reflect::make_tp(xyz);
|
||||
|
|
@ -256,7 +313,7 @@ namespace xo {
|
|||
return StructTdx::pair<Lhs, Rhs>();
|
||||
} /*make*/
|
||||
|
||||
// ----- Retval (*) (A1 .. An) -----
|
||||
// ----- Retval(A1 .. An) -----
|
||||
|
||||
namespace detail {
|
||||
/** @class AssembleArgv
|
||||
|
|
@ -272,7 +329,7 @@ namespace xo {
|
|||
|
||||
template <>
|
||||
struct AssembleArgv<> {
|
||||
static void append_argv(std::vector<TypeDescr> * p_v) {}
|
||||
static void append_argv(std::vector<TypeDescr> * /*p_v*/) {}
|
||||
};
|
||||
|
||||
template <typename Arg, typename... Rest>
|
||||
|
|
@ -284,6 +341,28 @@ namespace xo {
|
|||
};
|
||||
} /*detail*/
|
||||
|
||||
template <typename Retval, typename... Args>
|
||||
std::unique_ptr<TypeDescrExtra>
|
||||
EstablishFunctionTdx<Retval (*)(Args...)>::make() {
|
||||
std::vector<TypeDescr> argv;
|
||||
detail::AssembleArgv<Args...>::append_argv(&argv);
|
||||
|
||||
return FunctionTdx::make_function(Reflect::require<Retval>(),
|
||||
std::move(argv),
|
||||
false /*!is_noexcept*/);
|
||||
}
|
||||
|
||||
template <typename Retval, typename... Args>
|
||||
std::unique_ptr<TypeDescrExtra>
|
||||
EstablishFunctionTdx<Retval (*)(Args...) noexcept>::make() {
|
||||
std::vector<TypeDescr> argv;
|
||||
detail::AssembleArgv<Args...>::append_argv(&argv);
|
||||
|
||||
return FunctionTdx::make_function(Reflect::require<Retval>(),
|
||||
std::move(argv),
|
||||
true /*is_noexcept*/);
|
||||
}
|
||||
|
||||
/* declared above before
|
||||
* class Reflect { ... }
|
||||
*/
|
||||
|
|
@ -293,8 +372,25 @@ namespace xo {
|
|||
std::vector<TypeDescr> argv;
|
||||
detail::AssembleArgv<Args...>::append_argv(&argv);
|
||||
|
||||
return FunctionTdx::make_function(Reflect::require<Retval>(), std::move(argv));
|
||||
return FunctionTdx::make_function(Reflect::require<Retval>(),
|
||||
std::move(argv),
|
||||
false /*!is_noexcept*/);
|
||||
}
|
||||
|
||||
/* declared above before
|
||||
* class Reflect { ... }
|
||||
*/
|
||||
template <typename Retval, typename... Args>
|
||||
std::unique_ptr<TypeDescrExtra>
|
||||
EstablishTdx<Retval (*)(Args...) noexcept>::make() {
|
||||
std::vector<TypeDescr> argv;
|
||||
detail::AssembleArgv<Args...>::append_argv(&argv);
|
||||
|
||||
return FunctionTdx::make_function(Reflect::require<Retval>(),
|
||||
std::move(argv),
|
||||
true /*is_noexcept*/);
|
||||
}
|
||||
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ namespace xo {
|
|||
*/
|
||||
TypeDescr fn_retval() const { return this->tdextra_->fn_retval(); }
|
||||
TypeDescr fn_arg(uint32_t i) const { return this->tdextra_->fn_arg(i); }
|
||||
bool fn_is_noexcept() const { return this->tdextra_->fn_is_noexcept(); }
|
||||
|
||||
void display(std::ostream & os) const;
|
||||
std::string display_string() const;
|
||||
|
|
|
|||
|
|
@ -67,9 +67,10 @@ namespace xo {
|
|||
*
|
||||
* @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 uint32_t n_fn_arg() const { return 0; }
|
||||
virtual const TypeDescrBase * fn_arg(uint32_t /*i_arg*/) const { return nullptr; }
|
||||
virtual bool fn_is_noexcept() const { return false; }
|
||||
}; /*TypeDescrExtra*/
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
|
|
@ -15,11 +15,15 @@ namespace xo {
|
|||
public:
|
||||
virtual ~FunctionTdx() = default;
|
||||
|
||||
/** create instance. Will be invoked exactly once for each reflected function type **/
|
||||
/** create instance. Will be invoked exactly once for each reflected function type
|
||||
*
|
||||
* @param retval_td. type description for return value
|
||||
* @param arg_td_v. type descriptions for arguments, in positional order
|
||||
* @param is_noexcept. true iff function marked noexcept
|
||||
**/
|
||||
static std::unique_ptr<FunctionTdx> make_function(TypeDescr retval_td,
|
||||
std::vector<TypeDescr> arg_td_v);
|
||||
|
||||
|
||||
std::vector<TypeDescr> arg_td_v,
|
||||
bool is_noexcept);
|
||||
|
||||
// ----- Inherited from TypeDescrExtra -----
|
||||
|
||||
|
|
@ -28,12 +32,14 @@ namespace xo {
|
|||
virtual TaggedPtr child_tp(uint32_t i, void * object) const override;
|
||||
const std::string & struct_member_name(uint32_t i) const override;
|
||||
|
||||
virtual uint32_t n_fn_arg() const override { return arg_td_v_.size(); }
|
||||
virtual TypeDescr fn_retval() const override { return retval_td_; }
|
||||
virtual uint32_t n_fn_arg() const override { return arg_td_v_.size(); }
|
||||
virtual TypeDescr fn_arg(uint32_t i) const override { return arg_td_v_[i]; }
|
||||
virtual bool fn_is_noexcept() const override { return is_noexcept_; }
|
||||
|
||||
private:
|
||||
FunctionTdx(TypeDescr retval_td,
|
||||
bool is_noexcept,
|
||||
std::vector<TypeDescr> arg_td_v);
|
||||
|
||||
private:
|
||||
|
|
@ -41,6 +47,8 @@ namespace xo {
|
|||
TypeDescr retval_td_;
|
||||
/** function arguments, in positional order **/
|
||||
std::vector<TypeDescr> arg_td_v_;
|
||||
/** true iff function promises never to throw **/
|
||||
bool is_noexcept_ = false;
|
||||
}; /*FunctionTdx*/
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
|
|
@ -5,19 +5,28 @@
|
|||
|
||||
namespace xo {
|
||||
namespace reflect {
|
||||
/** create instance. Will be invoked exactly once for each reflected function type **/
|
||||
/** create instance. Will be invoked exactly once for each reflected function type **/
|
||||
std::unique_ptr<FunctionTdx>
|
||||
FunctionTdx::make_function(TypeDescr retval_td,
|
||||
std::vector<TypeDescr> arg_td_v)
|
||||
std::vector<TypeDescr> arg_td_v,
|
||||
bool is_noexcept)
|
||||
{
|
||||
return std::unique_ptr<FunctionTdx>(new FunctionTdx(retval_td, std::move(arg_td_v)));
|
||||
return std::unique_ptr<FunctionTdx>(new FunctionTdx(retval_td,
|
||||
is_noexcept,
|
||||
std::move(arg_td_v)));
|
||||
}
|
||||
|
||||
FunctionTdx::FunctionTdx(TypeDescr retval_td,
|
||||
bool is_noexcept,
|
||||
std::vector<TypeDescr> arg_td_v)
|
||||
: retval_td_{retval_td},
|
||||
arg_td_v_{std::move(arg_td_v)}
|
||||
{}
|
||||
arg_td_v_{std::move(arg_td_v)},
|
||||
is_noexcept_{is_noexcept}
|
||||
{
|
||||
if (!retval_td) {
|
||||
throw std::runtime_error("FunctionTdx::ctor: null return type?");
|
||||
}
|
||||
}
|
||||
|
||||
TaggedPtr
|
||||
FunctionTdx::child_tp(uint32_t /*i*/, void * /*object*/) const
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue