Created
April 5, 2020 23:30
-
-
Save Matthewacon/42a1297121757741f6c3a1546ebf6f86 to your computer and use it in GitHub Desktop.
This file contains 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
#include <cstdio> | |
#include <stdlib.h> | |
//Stub environment | |
struct Environment { | |
int GetRegister(int i) const { | |
printf("GetRegister(%d)\n", i); | |
return i; | |
} | |
}; | |
//Actual implementation | |
template<auto F, typename = decltype(F)> | |
struct Invoker; | |
//Forward to Invoker<F, R (*)(Args...)> | |
template<auto F, typename R, typename... Args> | |
struct Invoker<F, R (*)(Args...) noexcept> { | |
[[gnu::always_inline]] | |
inline static R invoke(const Environment& env) { | |
return Invoker<F, R (*)(Args...)>::invoke(env); | |
} | |
}; | |
template<auto F, size_t N, typename...> | |
struct InternalInvoker; | |
template<auto F> | |
struct InternalInvoker<F, 0> { | |
template<typename R, typename... Values> | |
[[gnu::always_inline]] | |
inline static R internal_invoke(const Environment& env, Values... values) { | |
return (*F)(values...); | |
} | |
}; | |
template<auto F, size_t N, typename T, typename... TS> | |
struct InternalInvoker<F, N, T, TS...> { | |
template<typename R, typename... Values> | |
[[gnu::always_inline]] | |
inline static R internal_invoke(const Environment& env, Values... values) { | |
return InternalInvoker<F, N - 1, TS...>::template internal_invoke<R, T, Values...>(env, static_cast<T>(env.GetRegister(N - 1)), values...); | |
} | |
}; | |
template<auto F, typename R, typename... Args> | |
struct Invoker<F, R (*)(Args...)> { | |
static_assert(sizeof...(Args) < 8); | |
//TODO add static_assert for Args to ensure that conversion from int to Arg is valid | |
//static_assert((CX::IsCastable<Args, int>::value && ...)); | |
[[gnu::always_inline]] | |
inline static R invoke(const Environment& env) { | |
return InternalInvoker<F, sizeof...(Args), Args...>::template internal_invoke<R>(env); | |
} | |
}; | |
void test(int i1, float i2, short i3) { | |
printf("test: %d %f %hi\n", i1, i2, i3); | |
} | |
double test2(double d, long l) noexcept { | |
printf("test2: %f %ld\n", d, l); | |
return d + l; | |
} | |
int main() { | |
Environment env; | |
Invoker<test>::invoke(env); | |
auto ret = Invoker<test2>::invoke(env); | |
printf("test2 returned %f\n", ret); | |
auto ptr = Invoker<malloc>::invoke(env); | |
if (ptr) { | |
free(ptr); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment