#pragma once #include "Emu/Cell/PPUThread.h" class func_caller { public: virtual void operator()() = 0; virtual ~func_caller(){}; }; namespace detail { enum bind_arg_type { ARG_GENERAL, ARG_FLOAT, ARG_VECTOR, ARG_STACK, }; template struct bind_arg; template struct bind_arg { static_assert(sizeof(T) <= 8, "Wrong argument type for ARG_GENERAL"); static __forceinline T func(PPUThread& CPU) { return (T&)CPU.GPR[g_count + 2]; } }; template struct bind_arg { static_assert(sizeof(T) <= 8, "Wrong argument type for ARG_FLOAT"); static __forceinline T func(PPUThread& CPU) { return (T)CPU.FPR[f_count]; } }; template struct bind_arg { static_assert(std::is_same::value, "Wrong argument type for ARG_VECTOR"); static __forceinline T func(PPUThread& CPU) { return (T&)CPU.VPR[v_count + 1]; } }; template struct bind_arg { static_assert(sizeof(T) <= 8 && v_count <= 12, "Wrong argument type for ARG_STACK"); static __forceinline T func(PPUThread& CPU) { const u64 res = CPU.GetStackArg(8 + std::max(g_count - 8, 0) + std::max(f_count - 12, 0)); return (T&)res; } }; template struct bind_result { static_assert(!std::is_pointer::value, "Invalid function result type: pointer"); static_assert(sizeof(T) <= 8, "Invalid function result type"); static __forceinline void func(PPUThread& CPU, T value) { if (std::is_floating_point::value) { CPU.FPR[1] = (double)value; } else { (T&)CPU.GPR[3] = value; } } }; template<> struct bind_result { static __forceinline void func(PPUThread& CPU, u128 value) { CPU.VPR[2] = value; } }; template struct call_impl { static __forceinline RT call(F f, Tuple && t) { return call_impl::call(f, std::forward(t)); } }; template struct call_impl { static __forceinline RT call(F f, Tuple && t) { return f(std::get(std::forward(t))...); } }; template static __forceinline RT call(F f, Tuple && t) { typedef typename std::decay::type ttype; return detail::call_impl::value, std::tuple_size::value>::call(f, std::forward(t)); } template static __forceinline std::tuple<> iterate(PPUThread& CPU) { return std::tuple<>(); } template static __forceinline std::tuple iterate(PPUThread& CPU) { static_assert(!std::is_pointer::value, "Invalid function argument type: pointer"); // TODO: check calculations const bool is_float = std::is_floating_point::value; const bool is_vector = std::is_same::value; const bind_arg_type t = is_float ? ((f_count >= 12) ? ARG_STACK : ARG_FLOAT) : (is_vector ? ((v_count >= 12) ? ARG_STACK : ARG_VECTOR) : ((g_count >= 8) ? ARG_STACK : ARG_GENERAL)); const int g = g_count + (is_float || is_vector ? 0 : 1); const int f = f_count + (is_float ? 1 : 0); const int v = v_count + (is_vector ? 1 : 0); return std::tuple_cat(std::tuple(bind_arg::func(CPU)), iterate(CPU)); } template class func_binder; template class func_binder : public func_caller { typedef void(*func_t)(TA...); const func_t m_call; public: func_binder(func_t call) : func_caller() , m_call(call) { } virtual void operator()() { declCPU(); call(m_call, iterate<0, 0, 0, TA...>(CPU)); } }; template class func_binder : public func_caller { typedef TR(*func_t)(TA...); const func_t m_call; public: func_binder(func_t call) : func_caller() , m_call(call) { } virtual void operator()() { declCPU(); bind_result::func(CPU, call(m_call, iterate<0, 0, 0, TA...>(CPU))); } }; } template func_caller* bind_func(TR(*call)(TA...)) { return new detail::func_binder(call); }