Page MenuHomec4science

auto_arguments.hh
No OneTemporary

File Metadata

Created
Fri, Jun 28, 04:39

auto_arguments.hh

#ifndef __AUTO_ARGUMENTS_HH__
#define __AUTO_ARGUMENTS_HH__
/*****************************************************************/
#include "auto_argument.hh"
#include <functional>
#include <iostream>
/*****************************************************************/
namespace AutoDispatch {
/*****************************************************************/
struct dispatch {};
/*****************************************************************/
template <int n_arg> struct apply_arguments {
template <typename Functor, typename Arguments>
static decltype(auto) apply(Functor &&f, Arguments &args) {
apply_arguments::apply(f, args, std::make_tuple<>());
}
template <typename Functor, typename Arguments, typename CastedArguments>
static decltype(auto) apply(Functor &&f, Arguments &args,
CastedArguments &&casted_arguments) {
auto &&arg = args.template get<n_arg>();
try {
arg.visit([&](auto &&a) {
auto &&new_args =
std::tuple_cat(std::forward_as_tuple(a), casted_arguments);
apply_arguments<n_arg - 1>::apply(f, args, new_args);
});
} catch (bad_argument_cast &e) {
bad_argument_cast ex;
ex.str = "Error while calling function " +
demangle(typeid(Functor).name()) + " => Cannot cast argument #" +
std::to_string(n_arg) + " => " + e.str;
throw ex;
} catch (no_argument &e) {
no_argument ex;
ex.str = e.str;
if (ex.str == "")
ex.str = "Error while calling function " +
demangle(typeid(Functor).name()) +
" => Cannot cast argument #" + std::to_string(n_arg) +
" => ArgumentAny has no value";
throw ex;
}
}
};
template <> struct apply_arguments<-1> {
template <typename Functor, typename Arguments, typename CastedArguments>
static decltype(auto) apply(Functor &&f, Arguments &,
CastedArguments &&casted_arguments) {
std::apply(f, casted_arguments);
}
};
/*****************************************************************/
template <typename... possible_types> class arguments {
using _args = typename std::tuple<argument<possible_types>...>;
static constexpr std::size_t size = std::tuple_size<_args>();
public:
arguments() = default;
template <typename... Ts> arguments(Ts &&... a) {
args = std::forward_as_tuple(a...);
}
template <typename F> decltype(auto) visit(F &&f) {
apply_arguments<size - 1>::apply(f, *this);
}
template <int n> decltype(auto) get() { return std::get<n>(args); }
private:
_args args;
};
/*****************************************************************/
template <typename possible_types, typename... Tup>
struct create_arguments_and_visit {
template <typename F, typename... Ts> static void visit(F &&f, Ts &&... v) {
arguments<Tup...> args(std::forward<Ts>(v)...);
args.visit(f);
}
};
/*****************************************************************/
template <typename... possible_types>
struct create_arguments_and_visit<std::tuple<possible_types...>, dispatch> {
template <typename F, typename... Ts> static void visit(F &&f, Ts &&... v) {
static_assert(std::tuple_size_v<std::tuple<possible_types...>>> 0,
"For automatic dispatch the decoration "
"DECORATE_FUNCTION_DISPATCH must define valid types");
arguments<possible_types...> args(std::forward<Ts>(v)...);
args.visit(f);
}
};
/*****************************************************************/
template <typename T> struct add_pointer_to_tuple {
using type = std::tuple<std::add_pointer_t<T>>;
};
template <typename... Ts> struct add_pointer_to_tuple<std::tuple<Ts...>> {
using type = std::tuple<std::add_pointer_t<std::decay_t<Ts>>...>;
};
template <typename T> struct remove_pointer_to_tuple;
template <typename... Ts> struct remove_pointer_to_tuple<std::tuple<Ts...>> {
using type = typename std::tuple<std::remove_pointer_t<std::decay_t<Ts>>...>;
};
template <class F, class Tuple, std::size_t... I>
void apply_ptr(F &&f, Tuple &&t, std::index_sequence<I...> &&) {
return f(std::get<I>(t)...);
}
template <typename T> struct apply_tuple_types_impl {};
template <typename... Ts> struct apply_tuple_types_impl<std::tuple<Ts...>> {
template <typename F> static void apply(F &&f) {
std::tuple<typename add_pointer_to_tuple<Ts>::type...> args;
apply_ptr(std::forward<F>(f), args,
std::make_index_sequence<sizeof...(Ts)>{});
}
};
#define apply_tuple_types(fname, _tuple, ...) \
AutoDispatch::apply_tuple_types_impl<_tuple>::apply([&](auto... Ts) { \
fname<typename AutoDispatch::remove_pointer_to_tuple<decltype( \
Ts)>::type...>(__VA_ARGS__); \
});
/*****************************************************************/
template <typename T> struct make_it_tuple { using type = std::tuple<T>; };
template <typename... T> struct make_it_tuple<std::tuple<T...>> {
using type = std::tuple<T...>;
};
/*****************************************************************/
template <typename... T> struct _or_impl;
template <typename T, typename... T2> struct _or_impl<T, T2...> {
using type_tail = typename _or_impl<T2...>::type;
using head = typename make_it_tuple<T>::type;
using type =
decltype(std::tuple_cat(std::declval<head>(), std::declval<type_tail>()));
};
template <> struct _or_impl<> { using type = std::tuple<>; };
template <typename... T> using _or = typename _or_impl<T...>::type;
/*****************************************************************/
template <typename... T> struct _tuple_params_impl;
template <typename T, typename... T2> struct _tuple_params_impl<T, T2...> {
using head = std::tuple<typename make_it_tuple<T>::type>;
using type_tail = typename _tuple_params_impl<T2...>::type;
using type =
decltype(std::tuple_cat(std::declval<head>(), std::declval<type_tail>()));
};
template <> struct _tuple_params_impl<> { using type = std::tuple<>; };
template <typename... T>
using _tuple_params = typename _tuple_params_impl<T...>::type;
template <typename... T> using _params = std::tuple<T...>;
/*****************************************************************/
template <typename T, typename Tuple> struct has_type;
template <typename T> struct has_type<T, std::tuple<>> : std::false_type {};
template <typename T, typename U, typename... Ts>
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
template <typename T, typename... Ts>
struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
template <typename Ts, typename Tuples> void debug(std::ostream &os) {
os << "has_type: " << demangle(typeid(Ts).name()) << ", "
<< demangle(typeid(Tuples).name()) << " => " << has_type<Ts, Tuples>::value
<< std::endl;
}
template <typename Ts, typename Tuples> struct param_has_types;
template <typename... Ts, typename... Tuples>
struct param_has_types<std::tuple<Ts...>, std::tuple<Tuples...>> {
constexpr static bool value =
true and (has_type<std::decay_t<Ts>, Tuples>::value and ...);
// static void get_tests() {
// std::cout << Argument::demangle(typeid(std::tuple<Ts...>).name())
// << std::endl;
// (debug<Ts, Tuples>(std::cout), ...);
// }
// using types = std::tuple<std::pair<Ts *, Tuples *>...>;
};
template <typename paramTypes, typename... possible_types>
using enable_if_type = std::enable_if_t<
param_has_types<paramTypes, _tuple_params<possible_types...>>::value>;
template <typename paramTypes, typename... possible_types>
using enable_if_not_type = std::enable_if_t<
not param_has_types<paramTypes, _tuple_params<possible_types...>>::value>;
/*****************************************************************/
// functions decorators
/*****************************************************************/
#define DECORATE_FUNCTION_DISPATCH(fname, ...) \
using fname##_possible_types = std::tuple<__VA_ARGS__>; \
void fname##_force_instanciation(); \
template <typename... Tup, typename... Ts> \
std::enable_if_t<sizeof...(Tup) != 0> fname(Ts &&... v) { \
AutoDispatch::create_arguments_and_visit<fname##_possible_types, Tup...>:: \
visit([&](auto &&... a) { fname(a...); }, v...); \
}
#define INSTANCIATE_DISPATCH(fname) \
void fname##_force_instanciation() { \
constexpr int sz = std::tuple_size_v<fname##_possible_types>; \
std::array<AutoDispatch::Argument, sz> args; \
std::apply( \
[&](auto &&... a) { \
apply_tuple_types(fname, fname##_possible_types, a...); \
}, \
args); \
}
} // namespace AutoDispatch
#endif //__AUTO_ARGUMENTS_HH__

Event Timeline