Skip to content

Instantly share code, notes, and snippets.

@JohnnyonFlame
Last active October 7, 2023 13:20
Show Gist options
  • Save JohnnyonFlame/ab2eb12654a22e4935715baf2cb997a9 to your computer and use it in GitHub Desktop.
Save JohnnyonFlame/ab2eb12654a22e4935715baf2cb997a9 to your computer and use it in GitHub Desktop.
Atuomatic dispatch from variadic/array procedures (from fake_jni).
// Automatic generator for function dispatch
template <auto F>
struct dispatch
{
// The following nested structure does two things:
// 1: Unwraps details about the function (e.g. argument type list,
// return type) with the template.
// 2: Implements the dispatcher as needed (will extract from va_list and push)
// into the function call that is being wrapped, taking care to also return
// the value if applicable.
template<typename S>
struct unwrap;
template<typename R, typename... Args>
struct unwrap<R(Args...)>
{
// brace-initialization is necessary to ensure the parameters are
// evaluated in left-to-right order on gcc...
struct BraceCall
{
R ret;
template <typename... Arg>
BraceCall(Arg... args) : ret( F(args...) ) { };
};
struct BraceCallVoid
{
template <typename... Arg>
BraceCallVoid(Arg... args) { F(args...); };
};
public:
static R dispatch_v(va_list va)
{
if constexpr (std::is_same_v<R, void>) {
BraceCallVoid{(Args)va_arg(va, Args)...};
} else {
return BraceCall{(Args)va_arg(va, Args)...}.ret;
}
}
static R dispatch_a(jvalue *arr)
{
auto get = [&]() { return arr++; };
if constexpr (std::is_same_v<R, void>) {
BraceCallVoid{(*((Args*)get()))...};
} else {
return BraceCall{*((Args*)get())...}.ret;
}
}
};
// Unwrap the function
using sig = unwrap<typename std::remove_pointer<decltype(F)>::type>;
// Expose the dispatch function :)
static constexpr auto vargs = sig::dispatch_v;
static constexpr auto aargs = sig::dispatch_a;
};
@JohnnyonFlame
Copy link
Author

JohnnyonFlame commented Oct 7, 2023

usage:

struct Method {
    Class *clazz;
    const char *name;
    const char *signature;
    const void *addr_variadic; // For <...> and <va_list> 
    const void *addr_array; // For arrays

    template <auto *F>
    static const Method Register(Class &clazz, const char *name, const char *signature)
    {
        using disp = dispatch<F>;
        return Method {
            .clazz = &clazz,
            .name = name,
            .signature = signature,
            .addr_variadic = (void*)disp::vargs,
            .addr_array = (void*)disp::aargs,
        };
    }
};
<...>

const Method RunnerJNILibClassMethods[] = {
    Method::Register<GamepadAxesValues>(RunnerJNILibClass::clazz, "GamepadAxesValues", "(I)[F"),
    NULL
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment