Skip to content

Instantly share code, notes, and snippets.

@crackcomm
Created November 2, 2022 01:17
Show Gist options
  • Save crackcomm/5e4da78a9d212c380ae610d7922cc7ea to your computer and use it in GitHub Desktop.
Save crackcomm/5e4da78a9d212c380ae610d7922cc7ea to your computer and use it in GitHub Desktop.
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