// Copyright satoren // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #pragma once #include #include #include #include "kaguya/config.hpp" #include "kaguya/utility.hpp" #include "kaguya/type.hpp" #include "kaguya/lua_ref.hpp" #if KAGUYA_USE_CPP11 #include "kaguya/native_function_cxx11.hpp" #else #include "kaguya/native_function_cxx03.hpp" #endif #include "kaguya/function_tuple_def.hpp" namespace kaguya { struct FunctionImpl { virtual int invoke(lua_State *state) = 0; virtual std::string argTypesName() const = 0; virtual bool checkArgTypes(lua_State *state) const = 0; virtual bool strictCheckArgTypes(lua_State *state) const = 0; virtual int minArgCount() const = 0; virtual int maxArgCount() const = 0; virtual ~FunctionImpl() {} }; struct PolymorphicInvoker { typedef standard::shared_ptr holder_type; PolymorphicInvoker(const holder_type &fptr) : fnc(fptr) {} int invoke(lua_State *state) const { return fnc->invoke(state); } std::string argTypesName() const { return fnc->argTypesName(); } bool checkArgTypes(lua_State *state) const { return fnc->checkArgTypes(state); } bool strictCheckArgTypes(lua_State *state) const { return fnc->strictCheckArgTypes(state); } int minArgCount() const { return fnc->minArgCount(); } int maxArgCount() const { return fnc->maxArgCount(); } ~PolymorphicInvoker() {} private: holder_type fnc; }; struct PolymorphicMemberInvoker : PolymorphicInvoker { PolymorphicMemberInvoker(const holder_type &fptr) : PolymorphicInvoker(fptr) {} }; namespace nativefunction { template typename lua_type_traits::type>::get_type getArgument(lua_State *state) { return lua_type_traits::type>::get( state, INDEX + 1); } template struct is_callable : traits::integral_constant< bool, !traits::is_same< void, typename util::FunctionSignature::type>::value> {}; template struct is_callable : traits::integral_constant {}; template struct is_callable > : traits::integral_constant {}; // for constructors template int call(lua_State *state, ConstructorFunctor &con) { return con(state); } template int call(lua_State *state, const ConstructorFunctor &con) { return con(state); } template bool checkArgTypes(lua_State *state, const ConstructorFunctor &con, int opt_count = 0) { return con.checkArgTypes(state, opt_count); } template bool strictCheckArgTypes(lua_State *state, const ConstructorFunctor &con, int opt_count = 0) { return con.strictCheckArgTypes(state, opt_count); } template std::string argTypesName(const ConstructorFunctor &con) { return con.argTypesName(); } template int minArgCount(const ConstructorFunctor &) { return ConstructorFunctor::signature_type::argument_count; } template int maxArgCount(const ConstructorFunctor &) { return ConstructorFunctor::signature_type::argument_count; } // for data member // using is_member_function_pointer in MSVC2010 : fatal error LNK1179: invalid // or corrupt file: duplicate COMDAT // '?value@?$result_@P8ABC@test_02_classreg@@AE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ@?$is_mem_fun_pointer_select@$0A@@detail@boost@@2_NB' template typename traits::enable_if::value, int>::type call(lua_State *state, MemType T::*mptr) { T *this_ = lua_type_traits::get(state, 1); if (lua_gettop(state) == 1) { if (!this_) { const T &this_ = lua_type_traits::get(state, 1); if (is_usertype::value && !traits::is_pointer::value) { return util::push_args( state, standard::reference_wrapper(this_.*mptr)); } else { return util::push_args(state, this_.*mptr); } } else { if (is_usertype::value && !traits::is_pointer::value) { return util::push_args( state, standard::reference_wrapper(this_->*mptr)); } else { return util::push_args(state, this_->*mptr); } } } else { if (!this_) { throw LuaTypeMismatch(); } this_->*mptr = lua_type_traits::get(state, 2); return 0; } } template typename traits::enable_if::value, bool>::type checkArgTypes(lua_State *state, MemType T::*, int opt_count = 0) { KAGUYA_UNUSED(opt_count); if (lua_gettop(state) >= 2) { // setter typecheck return lua_type_traits::checkType(state, 2) && lua_type_traits::checkType(state, 1); } // getter typecheck return lua_type_traits::checkType(state, 1); } template typename traits::enable_if::value, bool>::type strictCheckArgTypes(lua_State *state, MemType T::*, int opt_count = 0) { KAGUYA_UNUSED(opt_count); if (lua_gettop(state) == 2) { // setter typecheck return lua_type_traits::strictCheckType(state, 2) && lua_type_traits::strictCheckType(state, 1); } // getter typecheck return lua_type_traits::strictCheckType(state, 1); } template typename traits::enable_if::value, std::string>::type argTypesName(MemType T::*) { return util::pretty_name(typeid(T *)) + ",[OPT] " + util::pretty_name(typeid(MemType)); } template typename traits::enable_if::value, int>::type minArgCount(MemType T::*) { return 1; } template typename traits::enable_if::value, int>::type maxArgCount(MemType T::*) { return 2; } inline int call(lua_State *state, const PolymorphicInvoker &f) { return f.invoke(state); } inline int call(lua_State *state, PolymorphicInvoker &f) { return f.invoke(state); } inline bool checkArgTypes(lua_State *state, const PolymorphicInvoker &f) { return f.checkArgTypes(state); } inline bool strictCheckArgTypes(lua_State *state, const PolymorphicInvoker &f) { return f.strictCheckArgTypes(state); } inline std::string argTypesName(const PolymorphicInvoker &f) { return f.argTypesName(); } inline int minArgCount(const PolymorphicInvoker &f) { return f.minArgCount(); } inline int maxArgCount(const PolymorphicInvoker &f) { return f.maxArgCount(); } template <> struct is_callable : traits::integral_constant { }; inline int call(lua_State *state, const PolymorphicMemberInvoker &f) { return f.invoke(state); } inline int call(lua_State *state, PolymorphicMemberInvoker &f) { return f.invoke(state); } inline bool checkArgTypes(lua_State *state, const PolymorphicMemberInvoker &f) { return f.checkArgTypes(state); } inline bool strictCheckArgTypes(lua_State *state, const PolymorphicMemberInvoker &f) { return f.strictCheckArgTypes(state); } inline std::string argTypesName(const PolymorphicMemberInvoker &f) { return f.argTypesName(); } inline int minArgCount(const PolymorphicMemberInvoker &f) { return f.minArgCount(); } inline int maxArgCount(const PolymorphicMemberInvoker &f) { return f.maxArgCount(); } template <> struct is_callable : traits::integral_constant {}; } class VariadicArgType { public: VariadicArgType(lua_State *state, int startIndex) : state_(state), startIndex_(startIndex), endIndex_(lua_gettop(state) + 1) { if (startIndex_ > endIndex_) { endIndex_ = startIndex_; } } template operator std::vector() const { if (startIndex_ >= endIndex_) { return std::vector(); } std::vector result; result.reserve(endIndex_ - startIndex_); for (int index = startIndex_; index < endIndex_; ++index) { result.push_back(lua_type_traits::get(state_, index)); } return result; } struct reference : public Ref::StackRef, public detail::LuaVariantImpl { reference(lua_State *s, int index) : Ref::StackRef(s, index, false) {} const reference *operator->() const { return this; } }; struct iterator { typedef std::random_access_iterator_tag iterator_category; typedef VariadicArgType::reference reference; typedef int difference_type; typedef reference value_type; typedef reference *pointer; iterator() : state_(0), stack_index_(0) {} iterator(lua_State *state, int index) : state_(state), stack_index_(index) {} reference operator*() const { return reference(state_, stack_index_); } reference operator->() const { return reference(state_, stack_index_); } iterator &operator++() { stack_index_++; return *this; } iterator operator++(int) { return iterator(state_, stack_index_++); } iterator &operator+=(int n) { stack_index_ += n; return *this; } iterator operator+(int n) const { return iterator(state_, stack_index_ + n); } iterator &operator--() { stack_index_--; return *this; } iterator operator--(int) { return iterator(state_, stack_index_--); } iterator &operator-=(int n) { stack_index_ -= n; return *this; } iterator operator-(int n) const { return iterator(state_, stack_index_ - n); } difference_type operator-(const iterator &n) { return stack_index_ - n.stack_index_; } reference operator[](difference_type offset) const { return reference(state_, stack_index_ + offset); } /** * @name relational operators * @brief */ //@{ bool operator==(const iterator &other) const { return state_ == other.state_ && stack_index_ == other.stack_index_; } bool operator!=(const iterator &other) const { return !(*this == other); } bool operator<(const iterator &other) const { return stack_index_ < other.stack_index_; } bool operator>(const iterator &other) const { return other < *this; } bool operator<=(const iterator &other) const { return other >= *this; } bool operator>=(const iterator &other) const { return !(*this < other); } //@} private: lua_State *state_; int stack_index_; }; typedef iterator const_iterator; typedef reference const_reference; typedef reference value_type; iterator begin() { return iterator(state_, startIndex_); } iterator end() { return iterator(state_, endIndex_); } const_iterator cbegin() { return const_iterator(state_, startIndex_); } const_iterator cend() { return const_iterator(state_, endIndex_); } template typename lua_type_traits::get_type at(size_t index) const { if (index >= size()) { throw std::out_of_range("variadic arguments out of range"); } return lua_type_traits::get(state_, startIndex_ + static_cast(index)); } reference at(size_t index) const { if (index >= size()) { throw std::out_of_range("variadic arguments out of range"); } return reference(state_, startIndex_ + static_cast(index)); } reference operator[](size_t index) const { return reference(state_, startIndex_ + static_cast(index)); } size_t size() const { return endIndex_ - startIndex_; } size_t empty() const { return endIndex_ == startIndex_; } private: lua_State *state_; int startIndex_; int endIndex_; }; inline VariadicArgType::iterator operator+(int n, const VariadicArgType::iterator &i) { return i + n; } /// @ingroup lua_type_traits /// @brief lua_type_traits for VariadicArgType template <> struct lua_type_traits { typedef VariadicArgType get_type; static bool strictCheckType(lua_State *l, int index) { KAGUYA_UNUSED(l); KAGUYA_UNUSED(index); return true; } static bool checkType(lua_State *l, int index) { KAGUYA_UNUSED(l); KAGUYA_UNUSED(index); return true; } static get_type get(lua_State *l, int index) { return VariadicArgType(l, index); } }; namespace nativefunction { static const int MAX_OVERLOAD_SCORE = 255; template uint8_t compute_function_matching_score(lua_State *state, const Fn &fn) { int argcount = lua_gettop(state); if (strictCheckArgTypes(state, fn)) { const int minargcount = minArgCount(fn); const int maxargcount = maxArgCount(fn); if (minargcount <= argcount && maxargcount >= argcount) { return MAX_OVERLOAD_SCORE; } else { int diff = std::min(std::abs(argcount - minargcount), std::abs(argcount - maxargcount)); return std::max(100 - diff, 51); } } else if (checkArgTypes(state, fn)) { const int minargcount = minArgCount(fn); const int maxargcount = maxArgCount(fn); if (minargcount <= argcount && maxargcount >= argcount) { return 200; } else { int diff = std::min(std::abs(argcount - minargcount), std::abs(argcount - maxargcount)); return std::max(50 - diff, 1); } } else { return 0; } } inline int pushArgmentTypeNames(lua_State *state, int top) { for (int i = 1; i <= top; i++) { if (i != 1) { lua_pushliteral(state, ","); } int type = lua_type(state, i); if (type == LUA_TUSERDATA) { int nametype = luaL_getmetafield(state, i, "__name"); if (nametype != LUA_TSTRING) { lua_pop(state, 1); lua_pushstring(state, lua_typename(state, type)); } } else { lua_pushstring(state, lua_typename(state, type)); } } return lua_gettop(state) - top; } } #if KAGUYA_USE_CPP11 namespace detail { template void function_match_scoring(lua_State *state, uint8_t *score_array, int current_index, const Fn &fn) { score_array[current_index] = nativefunction::compute_function_matching_score(state, fn); } template void function_match_scoring(lua_State *state, uint8_t *score_array, int current_index, const Fn &fn, const Functions &... fns) { score_array[current_index] = nativefunction::compute_function_matching_score(state, fn); if (score_array[current_index] < nativefunction::MAX_OVERLOAD_SCORE) { function_match_scoring(state, score_array, current_index + 1, fns...); } } template int best_function_index(lua_State *state, const Functions &... fns) { static const int fncount = sizeof...(fns); uint8_t score[fncount] = {}; function_match_scoring(state, score, 0, fns...); uint8_t best_score = 0; int best_score_index = -1; for (int i = 0; i < fncount; ++i) { if (best_score < score[i]) { best_score = score[i]; best_score_index = i; if (best_score == nativefunction::MAX_OVERLOAD_SCORE) { break; } } } return best_score_index; } template int invoke_index(lua_State *state, int index, int current_index, Fn &&fn) { KAGUYA_UNUSED(index); KAGUYA_UNUSED(current_index); return nativefunction::call(state, fn); } template int invoke_index(lua_State *state, int index, int current_index, Fn &&fn, Functions &&... fns) { if (index == current_index) { return nativefunction::call(state, fn); } else { return invoke_index(state, index, current_index + 1, fns...); } } template int best_match_invoke(lua_State *state, Fun &&fn) { return nativefunction::call(state, fn); } template int best_match_invoke(lua_State *state, Fun &&fn, Functions &&... fns) { int index = best_function_index(state, fn, fns...); if (index >= 0) { assert(size_t(index) <= sizeof...(fns)); return invoke_index(state, index, 0, fn, fns...); } else { throw LuaTypeMismatch(); } return 0; } template int invoke_tuple_impl(lua_State *state, TupleType &&tuple, nativefunction::index_tuple) { return best_match_invoke(state, fntuple::get(tuple)...); } template int invoke_tuple(lua_State *state, TupleType &&tuple) { typedef typename std::decay::type ttype; typedef typename nativefunction::index_range< 0, fntuple::tuple_size::value>::type indexrange; return invoke_tuple_impl(state, tuple, indexrange()); } template void push_arg_typename(lua_State *state, const Fun &fn) { lua_pushliteral(state, "\t\t"); lua_pushstring(state, nativefunction::argTypesName(fn).c_str()); lua_pushliteral(state, "\n"); } template void push_arg_typename(lua_State *state, const Fun &fn, const Functions &... fns) { lua_pushliteral(state, "\t\t"); lua_pushstring(state, nativefunction::argTypesName(fn).c_str()); lua_pushliteral(state, "\n"); push_arg_typename(state, fns...); } template void push_arg_typename_tuple_impl(lua_State *state, TupleType &&tuple, nativefunction::index_tuple) { return push_arg_typename(state, fntuple::get(tuple)...); } template void push_arg_typename_tuple(lua_State *state, TupleType &&tuple) { typedef typename std::decay::type ttype; typedef typename nativefunction::index_range< 0, fntuple::tuple_size::value>::type indexrange; return push_arg_typename_tuple_impl(state, tuple, indexrange()); } } #else namespace detail { #define KAGUYA_FUNCTION_SCOREING(N) \ if (currentbestscore < nativefunction::MAX_OVERLOAD_SCORE) { \ int score = nativefunction::compute_function_matching_score( \ state, fntuple::get(tuple)); \ if (currentbestscore < score) { \ currentbestscore = score; \ currentbestindex = N; \ } \ } #define KAGUYA_FUNCTION_INVOKE(N) \ if (currentbestindex == N) { \ return nativefunction::call(state, fntuple::get(tuple)); \ } #define KAGUYA_ARG_PUSH_TYPENAMES(N) \ lua_pushliteral(state, "\t\t"); \ lua_pushstring( \ state, \ nativefunction::argTypesName(fntuple::get(tuple)).c_str()); \ lua_pushliteral(state, "\n"); #define KAGUYA_TEMPLATE_PARAMETER(N) template #define KAGUYA_TUPLE_INVOKE_DEF(N) \ KAGUYA_TEMPLATE_PARAMETER(N) \ int invoke_tuple(lua_State *state, \ fntuple::tuple &tuple) { \ if (N == 1) { \ return nativefunction::call(state, fntuple::get<0>(tuple)); \ } \ int32_t currentbestscore = 0; \ int32_t currentbestindex = -1; \ KAGUYA_PP_REPEAT(N, KAGUYA_FUNCTION_SCOREING); \ KAGUYA_PP_REPEAT(N, KAGUYA_FUNCTION_INVOKE); \ throw LuaTypeMismatch(); \ } \ KAGUYA_TEMPLATE_PARAMETER(N) \ void push_arg_typename_tuple( \ lua_State *state, \ fntuple::tuple &tuple) { \ KAGUYA_PP_REPEAT(N, KAGUYA_ARG_PUSH_TYPENAMES); \ } KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_TUPLE_INVOKE_DEF) #undef KAGUYA_TEMPLATE_PARAMETER #undef KAGUYA_TUPLE_INVOKE_DEF #undef KAGUYA_ARG_TYPENAMES #undef KAGUYA_FUNCTION_INVOKE #undef KAGUYA_FUNCTION_SCOREING template int invoke_tuple(lua_State *state, TupleType &tuple) { KAGUYA_UNUSED(state); KAGUYA_UNUSED(tuple); return 0; } } #endif template struct FunctionInvokerType { FunctionTuple functions; FunctionInvokerType(const FunctionTuple &t) : functions(t) {} }; template inline FunctionInvokerType > function(T f) { KAGUYA_STATIC_ASSERT( nativefunction::is_callable::type>::value, "argument need callable"); return FunctionInvokerType >(fntuple::tuple(f)); } template inline FunctionInvokerType > > function(T f) { return FunctionInvokerType > >( fntuple::tuple >(standard::function(f))); } #if KAGUYA_USE_CPP11 template FunctionInvokerType > overload(Functions... fns) { return FunctionInvokerType >( fntuple::tuple(fns...)); } #else #define KAGUYA_FOVERLOAD_DEF(N) \ template \ FunctionInvokerType > \ overload(KAGUYA_PP_ARG_DEF_REPEAT(N)) { \ typedef typename fntuple::tuple ttype; \ return FunctionInvokerType(ttype(KAGUYA_PP_ARG_REPEAT(N))); \ } KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_FOVERLOAD_DEF) #undef KAGUYA_FOVERLOAD_DEF #endif struct luacfunction { lua_CFunction ptr; luacfunction(lua_CFunction f) : ptr(f) {} operator lua_CFunction() { return ptr; } }; /// @ingroup lua_type_traits /// @brief lua_type_traits for FunctionInvokerType template struct lua_type_traits > { typedef FunctionInvokerType userdatatype; typedef const FunctionInvokerType &push_type; static const char *build_arg_error_message(lua_State *state, const char *msg, FunctionTuple *tuple) { int stack_top = lua_gettop(state); if (msg) { lua_pushstring(state, msg); } lua_pushliteral(state, "Argument mismatch:"); nativefunction::pushArgmentTypeNames(state, stack_top); lua_pushliteral(state, "\t candidate is:\n"); detail::push_arg_typename_tuple(state, *tuple); lua_concat(state, lua_gettop(state) - stack_top); return lua_tostring(state, -1); } static int invoke(lua_State *state) { FunctionTuple *t = static_cast( lua_touserdata(state, lua_upvalueindex(1))); if (t) { try { return detail::invoke_tuple(state, *t); } catch (LuaTypeMismatch &e) { if (strcmp(e.what(), "type mismatch!!") == 0) { util::traceBack(state, build_arg_error_message(state, "maybe...", t)); } else { util::traceBack(state, e.what()); } } catch (std::exception &e) { util::traceBack(state, e.what()); } catch (...) { util::traceBack(state, "Unknown exception"); } } return lua_error(state); } inline static int tuple_destructor(lua_State *state) { FunctionTuple *f = static_cast(lua_touserdata(state, 1)); if (f) { f->~FunctionTuple(); } return 0; } static int push(lua_State *state, push_type fns) { void *ptr = lua_newuserdata(state, sizeof(FunctionTuple)); new (ptr) FunctionTuple(fns.functions); lua_createtable(state, 0, 2); lua_pushcclosure(state, &tuple_destructor, 0); lua_setfield(state, -2, "__gc"); lua_pushvalue(state, -1); lua_setfield(state, -1, "__index"); lua_setmetatable(state, -2); lua_pushcclosure(state, &invoke, 1); return 1; } }; /// @ingroup lua_type_traits /// @brief lua_type_traits for c function template struct lua_type_traits< T, typename traits::enable_if::type>::value>::type> { static int push(lua_State *l, T f) { return util::one_push(l, kaguya::function(f)); } }; /// @ingroup lua_type_traits /// @brief lua_type_traits for luacfunction template <> struct lua_type_traits { typedef luacfunction push_type; typedef luacfunction get_type; static bool strictCheckType(lua_State *l, int index) { return lua_iscfunction(l, index) != 0; } static bool checkType(lua_State *l, int index) { return lua_iscfunction(l, index) != 0; } static get_type get(lua_State *l, int index) { return lua_tocfunction(l, index); } static int push(lua_State *l, push_type f) { lua_pushcfunction(l, f); return 1; } }; /// @ingroup lua_type_traits /// @brief lua_type_traits for std::function or boost::function template struct lua_type_traits > { typedef const standard::function &push_type; typedef standard::function get_type; static bool strictCheckType(lua_State *l, int index) { return lua_type(l, index) == LUA_TFUNCTION; } static bool checkType(lua_State *l, int index) { return lua_type(l, index) == LUA_TFUNCTION; } static get_type get(lua_State *l, int index) { if (!l || lua_type(l, index) != LUA_TFUNCTION) { return get_type(); } lua_pushvalue(l, index); return get_type(LuaFunction(l, StackTop())); } static int push(lua_State *l, push_type v) { return util::one_push(l, kaguya::function(v)); } }; template ::type::result_type> struct OverloadFunctionImpl : kaguya::FunctionImpl { typedef Ret result_type; typedef typename util::FunctionSignature::type::c_function_type c_function_type; virtual result_type invoke_type(lua_State *state) = 0; virtual int invoke(lua_State *state) { return util::push_args(state, invoke_type(state)); } virtual std::string argTypesName() const { return nativefunction::argTypesName(c_function_type(0), maxArgCount() - minArgCount()); } virtual bool checkArgTypes(lua_State *state) const { return kaguya::nativefunction::checkArgTypes(state, c_function_type(0), maxArgCount() - minArgCount()); } virtual bool strictCheckArgTypes(lua_State *state) const { return kaguya::nativefunction::strictCheckArgTypes( state, c_function_type(0), maxArgCount() - minArgCount()); } }; template struct OverloadFunctionImpl : kaguya::FunctionImpl { typedef void result_type; typedef typename util::FunctionSignature::type::c_function_type c_function_type; virtual result_type invoke_type(lua_State *state) = 0; virtual int invoke(lua_State *state) { invoke_type(state); return 0; } virtual std::string argTypesName() const { return nativefunction::argTypesName(c_function_type(0), maxArgCount() - minArgCount()); } virtual bool checkArgTypes(lua_State *state) const { return kaguya::nativefunction::checkArgTypes(state, c_function_type(0), maxArgCount() - minArgCount()); } virtual bool strictCheckArgTypes(lua_State *state) const { return kaguya::nativefunction::strictCheckArgTypes( state, c_function_type(0), maxArgCount() - minArgCount()); } }; } #define KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REP(N) \ getArgument(state) #define KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REPEAT(N) \ KAGUYA_PP_REPEAT_ARG(N, KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REP) #define KAGUYA_INTERNAL_OVERLOAD_FUNCTION_INVOKE(N, FNAME, MINARG, MAXARG) \ if (argcount == KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N))) { \ return FNAME(KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REPEAT( \ KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N)))); \ } #define KAGUYA_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, FNAME, MINARG, \ MAXARG, CREATE_FN) \ \ struct GENERATE_NAME \ { \ template struct Function : kaguya::OverloadFunctionImpl { \ typedef \ typename kaguya::OverloadFunctionImpl::result_type result_type; \ virtual result_type invoke_type(lua_State *state) { \ using namespace kaguya::nativefunction; \ int argcount = lua_gettop(state); \ KAGUYA_PP_REPEAT_DEF_VA_ARG( \ KAGUYA_PP_INC(KAGUYA_PP_SUB(MAXARG, MINARG)), \ KAGUYA_INTERNAL_OVERLOAD_FUNCTION_INVOKE, FNAME, MINARG, MAXARG) \ throw kaguya::LuaTypeMismatch("argument count mismatch"); \ } \ virtual int minArgCount() const { return MINARG; } \ virtual int maxArgCount() const { return MAXARG; } \ }; \ template kaguya::PolymorphicInvoker::holder_type create(F) { \ kaguya::OverloadFunctionImpl *ptr = new Function(); \ return kaguya::PolymorphicInvoker::holder_type(ptr); \ } \ template kaguya::PolymorphicInvoker::holder_type create() { \ kaguya::OverloadFunctionImpl *ptr = new Function(); \ return kaguya::PolymorphicInvoker::holder_type(ptr); \ } \ kaguya::PolymorphicInvoker operator()() { return CREATE_FN; } \ \ } \ GENERATE_NAME; #define KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REP(N) \ getArgument(state) #define KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REPEAT(N) \ KAGUYA_PP_REPEAT_ARG(N, KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REP) #define KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_INVOKE(N, FNAME, MINARG, \ MAXARG) \ if (argcount == 1 + KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N))) { \ return (getArgument<0, F>(state)) \ .FNAME(KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REPEAT( \ KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N)))); \ } #define KAGUYA_MEMBER_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, CLASS, FNAME, \ MINARG, MAXARG, CREATE_FN) \ \ struct GENERATE_NAME \ { \ template struct Function : kaguya::OverloadFunctionImpl { \ typedef \ typename kaguya::OverloadFunctionImpl::result_type result_type; \ virtual result_type invoke_type(lua_State *state) { \ using namespace kaguya::nativefunction; \ int argcount = lua_gettop(state); \ KAGUYA_PP_REPEAT_DEF_VA_ARG( \ KAGUYA_PP_INC(KAGUYA_PP_SUB(MAXARG, MINARG)), \ KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_INVOKE, FNAME, MINARG, \ MAXARG) \ throw kaguya::LuaTypeMismatch("argument count mismatch"); \ } \ virtual int minArgCount() const { return MINARG + 1; } \ virtual int maxArgCount() const { return MAXARG + 1; } \ }; \ template \ kaguya::PolymorphicMemberInvoker::holder_type create(F f) { \ KAGUYA_UNUSED(f); \ kaguya::OverloadFunctionImpl *ptr = new Function(); \ return kaguya::PolymorphicMemberInvoker::holder_type(ptr); \ } \ template \ kaguya::PolymorphicMemberInvoker::holder_type create() { \ kaguya::OverloadFunctionImpl *ptr = new Function(); \ return kaguya::PolymorphicMemberInvoker::holder_type(ptr); \ } \ kaguya::PolymorphicMemberInvoker operator()() { return CREATE_FN; } \ \ } \ GENERATE_NAME; /// @brief Generate wrapper function object for count based overloads with /// nonvoid return function. Include default arguments parameter function /// @param GENERATE_NAME generate function object name /// @param FNAME target function name /// @param MINARG minimum arguments count /// @param MAXARG maximum arguments count #define KAGUYA_FUNCTION_OVERLOADS(GENERATE_NAME, FNAME, MINARG, MAXARG) \ KAGUYA_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, FNAME, MINARG, MAXARG, \ create(FNAME)) /// @brief Generate wrapper function object for count based overloads with /// nonvoid return function. Include default arguments parameter function /// @param GENERATE_NAME generate function object name /// @param FNAME target function name /// @param MINARG minimum arguments count /// @param MAXARG maximum arguments count /// @param SIGNATURE function signature. e,g, int(int) #define KAGUYA_FUNCTION_OVERLOADS_WITH_SIGNATURE(GENERATE_NAME, FNAME, MINARG, \ MAXARG, SIGNATURE) \ KAGUYA_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, FNAME, MINARG, MAXARG, \ create()) /// @brief Generate wrapper function object for count based overloads with /// nonvoid return function. Include default arguments parameter function /// @param GENERATE_NAME generate function object name /// @param CLASS target class name /// @param FNAME target function name /// @param MINARG minimum arguments count /// @param MAXARG maximum arguments count #define KAGUYA_MEMBER_FUNCTION_OVERLOADS(GENERATE_NAME, CLASS, FNAME, MINARG, \ MAXARG) \ KAGUYA_MEMBER_FUNCTION_OVERLOADS_INTERNAL( \ GENERATE_NAME, CLASS, FNAME, MINARG, MAXARG, create(&CLASS::FNAME)) /// @brief Generate wrapper function object for count based overloads with /// nonvoid return function. Include default arguments parameter function /// @param GENERATE_NAME generate function object name /// @param CLASS target class name /// @param FNAME target function name /// @param MINARG minimum arguments count /// @param MAXARG maximum arguments count /// @param SIGNATURE function signature. e,g, int(Test::*)(int) #define KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE( \ GENERATE_NAME, CLASS, FNAME, MINARG, MAXARG, SIGNATURE) \ KAGUYA_MEMBER_FUNCTION_OVERLOADS_INTERNAL( \ GENERATE_NAME, CLASS, FNAME, MINARG, MAXARG, create())