Page MenuHomec4science

static_dispatch.hh
No OneTemporary

File Metadata

Created
Fri, Aug 16, 08:16

static_dispatch.hh

#ifndef __LIBMULTISCALE_AUTOMATIC_CAST_HH__
#define __LIBMULTISCALE_AUTOMATIC_CAST_HH__
#include <any>
#include <iostream>
#include <stdexcept>
#include <tuple>
#include <utility>
//****************************************************************
// apply static functor on tuple
//****************************************************************
#if __cplusplus <= 201402
namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F &&f, Tuple &&t,
std::index_sequence<I...>) {
return f(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail
template <class F, class Tuple>
constexpr decltype(auto) apply(F &&f, Tuple &&t) {
return detail::apply_impl(
std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<
std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}
#else
#define apply std::apply
#endif
//****************************************************************
// casting of objects
//****************************************************************
template <typename possible_types, int n> struct _cpp_dynamic_cast {
template <typename CastFunctor, typename AfterCastFunctor, typename Arg>
static void cast(CastFunctor &cast_functor, AfterCastFunctor &call_after_cast,
Arg &arg) {
using _type = std::remove_pointer_t<
std::decay_t<std::tuple_element_t<n, possible_types>>>;
if (auto *ptr = cast_functor.template cast<_type>(arg)) {
call_after_cast(*ptr);
return;
}
_cpp_dynamic_cast<possible_types, n - 1>::template cast(
cast_functor, call_after_cast, arg);
}
};
template <typename possible_types>
struct _cpp_dynamic_cast<possible_types, -1> {
template <typename CastFunctor, typename AfterCastFunctor, typename Arg>
static void cast(CastFunctor &, AfterCastFunctor &, Arg &) {
throw std::bad_cast();
}
};
template <typename... Args> void toto(std::tuple<Args...>) {}
template <typename possible_types, typename CastFunctor,
typename AfterCastFunctor, typename Arg>
void cpp_dynamic_cast(CastFunctor &cast_functor,
AfterCastFunctor &call_after_cast, Arg &arg) {
constexpr size_t N = std::tuple_size<possible_types>::value;
_cpp_dynamic_cast<possible_types, N - 1>::cast(cast_functor, call_after_cast,
arg);
}
/* --------------------------------------------------------------------- */
template <int argument_position, typename PossibleTypes,
typename ArgumentsTuple, typename ArgumentsCastedTuple>
struct Dispatch {
template <typename Functor, typename CastFunctor>
static void dispatch(Functor &functor, CastFunctor &cast_functor,
ArgumentsTuple args, ArgumentsCastedTuple args_casted) {
using possible_types =
std::tuple_element_t<argument_position, PossibleTypes>;
auto arg = std::get<argument_position>(args);
// functor that will be called after resolving
// the dynamic cast of the current argument
// => It will proceed to the next argument
auto &&call_after_cast = [&](auto &&casted_object) {
auto tup = std::forward_as_tuple(casted_object);
auto new_args_casted = std::tuple_cat(tup, args_casted);
Dispatch<argument_position - 1, PossibleTypes, ArgumentsTuple,
decltype(new_args_casted)>::dispatch(functor, cast_functor, args,
new_args_casted);
};
cpp_dynamic_cast<possible_types>(cast_functor, call_after_cast, arg);
}
};
// specialization for the end of recursion: all args have been dynamic casted
// need to call the function
template <typename PossibleTypes, typename ArgumentsTuple,
typename ArgumentsCastedTuple>
struct Dispatch<-1, PossibleTypes, ArgumentsTuple, ArgumentsCastedTuple> {
template <typename Functor, typename CastFunctor>
static void dispatch(Functor &functor, CastFunctor &, ArgumentsTuple,
ArgumentsCastedTuple args_formatted) {
apply([&](auto &... args) { functor(args...); }, args_formatted);
}
};
template <typename PossibleTypes, typename CastFunctor, typename Functor,
typename... Args>
void _static_dispatch(Functor func, Args &... args) {
auto arguments_tuple = std::make_tuple(&args...);
constexpr size_t N = std::tuple_size<decltype(arguments_tuple)>::value;
auto cast_functor = CastFunctor{};
Dispatch<N - 1, PossibleTypes, decltype(arguments_tuple),
std::tuple<>>::dispatch(func, cast_functor, arguments_tuple,
std::tuple<>{});
}
/* --------------------------------------------------------------------- */
// DECORATION POSSIBILITY
/* --------------------------------------------------------------------- */
#define _Args(...) __VA_ARGS__
#define STRIP_PARENS(X) X
#define STATIC_DISPATCH_DECLARE(NAME, POS_TYPES) \
template <typename... Args> void NAME##_dispatch(Args &&... args) { \
using possible_types = std::tuple<STRIP_PARENS(_Args POS_TYPES)>; \
_static_dispatch<possible_types, _simple_cast>( \
[&](auto &&... args) { NAME(std::forward<decltype(args)>(args)...); }, \
std::forward<Args>(args)...); \
}
#define STATIC_CLASS_DISPATCH_DECLARE(NAME, POS_TYPES) \
template <typename... Args> void NAME##_dispatch(Args &&... args) { \
using possible_types = std::tuple<STRIP_PARENS(_Args POS_TYPES)>; \
_static_dispatch<possible_types, _simple_cast>( \
[&](auto &&... args) { NAME(std::forward<decltype(args)>(args)...); }, \
std::forward<Args>(args)...); \
} \
friend void _instanciate_static_class_dispatch();
struct _simple_cast {
template <typename type, typename Arg> type *cast(Arg &arg) {
if (auto *ptr = dynamic_cast<type *>(arg)) {
return ptr;
}
return nullptr;
}
};
/* --------------------------------------------------------------------- */
#endif // __LIBMULTISCALE_AUTOMATIC_CAST_HH__

Event Timeline