Created
November 2, 2022 01:17
-
-
Save crackcomm/5e4da78a9d212c380ae610d7922cc7ea to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <typename... Ts> | |
struct type_list {}; | |
// base case | |
template <typename Func, typename = void> | |
struct invoke_args; | |
// nonmembers | |
template <typename Ret, typename... Args, bool noex> | |
struct invoke_args<Ret(Args...) noexcept(noex)> { using args = type_list<Args...>; }; | |
template <typename Ret, typename... Args, bool noex> | |
struct invoke_args<Ret(Args..., ...) noexcept(noex)> { using args = type_list<Args...>; }; | |
// members | |
template <typename T, typename C> | |
struct invoke_args<T C::*> { using args = type_list<C>; }; | |
#define COMMA , | |
#define GENERATE_4(var, cv, ref) \ | |
template <typename Ret, typename Cls, typename... Args, bool noex> \ | |
struct invoke_args<Ret (Cls::*) (Args... var) cv ref noexcept(noex)> { \ | |
using args = type_list<std::add_lvalue_reference_t<Cls cv ref>, Args...>; \ | |
using args_no_obj = type_list<Args...>; \ | |
}; | |
#define GENERATE_3(cv, ref) \ | |
GENERATE_4(, cv, ref) \ | |
GENERATE_4(COMMA ..., cv, ref) | |
#define GENERATE_2(ref) \ | |
GENERATE_3(, ref) \ | |
GENERATE_3(const, ref) \ | |
GENERATE_3(volatile, ref) \ | |
GENERATE_3(const volatile, ref) | |
#define GENERATE_1() \ | |
GENERATE_2() \ | |
GENERATE_2(&) \ | |
GENERATE_2(&&) | |
GENERATE_1; | |
#undef GENERATE_1 | |
#undef GENERATE_2 | |
#undef GENERATE_3 | |
#undef GENERATE_4 | |
#undef COMMA | |
// objects with call operator | |
template <typename T> | |
struct invoke_args<T, std::void_t<decltype(&T::operator())>> { | |
using args = typename invoke_args<decltype(&T::operator())>::args_no_obj; | |
}; | |
// ============ | |
template <typename... Args, typename Func, typename... Values> | |
decltype(auto) forward_call_impl(type_list<Args...>, Func&& f, Values&&... args) { | |
return std::invoke( | |
std::forward<Func>(f), | |
from_ocaml::from_value<Args>(std::forward<Values>(args))...); | |
} | |
template <typename Func, typename... Values> | |
decltype(auto) forward_call(Func&& f, Values&&... args) { | |
return forward_call_impl( | |
typename invoke_args<std::remove_cvref_t<Func>>::args{}, | |
std::forward<Func>(f), | |
std::forward<Values>(args)...); | |
} | |
/* don't have this | |
template<typename T> | |
inline constexpr value to_value(T); | |
*/ | |
inline value to_value(std::monostate) { | |
return Val_unit; | |
} | |
inline value to_value(double v) { | |
return caml_copy_double(v); | |
} | |
// ... | |
template <typename... Args, typename Func, typename... Values> | |
decltype(auto) forward_call_impl(type_list<Args...>, Func&& f, Values&&... args) { | |
if constexpr (std::is_void_v<std::invoke_result_t<Func, Args...>>) { | |
std::invoke( | |
std::forward<Func>(f), | |
from_ocaml::from_value<Args>(std::forward<Values>(args))...); | |
return std::monostate{}; | |
} else { | |
return std::invoke( | |
std::forward<Func>(f), | |
from_ocaml::from_value<Args>(std::forward<Values>(args))...); | |
} | |
} | |
template <typename Func, typename... Values> | |
decltype(auto) forward_call(Func&& f, Values&&... args) { | |
return forward_call_impl( | |
typename invoke_args<std::remove_cvref_t<Func>>::args{}, | |
std::forward<Func>(f), | |
std::forward<Values>(args)...); | |
} | |
// ... and now this works: | |
auto result = ocaml::forward_call(/* ... */); | |
value caml__temp_result = to_value(result); | |
Caml_state->local_roots = caml__frame; | |
return caml__temp_result; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment