// 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 "kaguya/config.hpp" #include "kaguya/utility.hpp" #include "kaguya/object.hpp" namespace kaguya { namespace nativefunction { template struct index_tuple {}; template , bool flag = first >= last> struct index_range { using type = result; }; template struct index_range, false> : index_range > {}; template int _call_apply(lua_State *state, F &&f, index_tuple, util::FunctionSignatureType) { return util::push_args( state, util::invoke(f, lua_type_traits::get(state, Indexes)...)); } template int _call_apply(lua_State *state, F &&f, index_tuple, util::FunctionSignatureType) { KAGUYA_UNUSED(state); util::invoke(f, lua_type_traits::get(state, Indexes)...); return 0; } inline bool all_true() { return true; } template bool all_true(Arg f, Args... args) { // check from backward and lazy evaluation return all_true(args...) && bool(f); } inline void join(std::string &, const char *) {} template void join(std::string &result, const char *delim, const Arg &str, const Args &... args) { result += str; result += delim; join(result, delim, args...); } template struct _wcheckeval { _wcheckeval(lua_State *s, int i, bool opt) : state(s), index(i), opt_arg(opt) {} lua_State *state; int index; bool opt_arg; operator bool() { return (opt_arg && lua_isnoneornil(state, index)) || lua_type_traits::checkType(state, index); } }; template struct _scheckeval { _scheckeval(lua_State *s, int i, bool opt) : state(s), index(i), opt_arg(opt) {} lua_State *state; int index; bool opt_arg; operator bool() { return (opt_arg && lua_isnoneornil(state, index)) || lua_type_traits::strictCheckType(state, index); } }; template bool _ctype_apply(lua_State *state, index_tuple, util::TypeTuple, int opt_count) { KAGUYA_UNUSED(state); KAGUYA_UNUSED(opt_count); return all_true(_wcheckeval( state, Indexes, sizeof...(Indexes) - opt_count < Indexes)...); } template bool _sctype_apply(lua_State *state, index_tuple, util::TypeTuple, int opt_count) { KAGUYA_UNUSED(state); KAGUYA_UNUSED(opt_count); return all_true(_scheckeval( state, Indexes, sizeof...(Indexes) - opt_count < Indexes)...); } template std::string _type_name_apply(index_tuple, util::TypeTuple, int opt_count) { KAGUYA_UNUSED(opt_count); std::string result; const int max_arg = sizeof...(Args); join(result, ",", (((max_arg - opt_count < int(Indexes)) ? std::string("[OPT]") : std::string("")) + util::pretty_name(typeid(Args)))...); return result; } template int call(lua_State *state, F &&f) { typedef typename traits::decay::type ftype; typedef typename util::FunctionSignature::type fsigtype; typedef typename index_range<1, fsigtype::argument_count + 1>::type index; return _call_apply(state, f, index(), fsigtype()); } template bool checkArgTypes(lua_State *state, const F &, int opt_count = 0) { typedef typename traits::decay::type ftype; typedef typename util::FunctionSignature::type fsigtype; typedef typename index_range<1, fsigtype::argument_count + 1>::type index; typedef typename fsigtype::argument_type_tuple argument_type_tuple; return _ctype_apply(state, index(), argument_type_tuple(), opt_count); } template bool strictCheckArgTypes(lua_State *state, const F &, int opt_count = 0) { typedef typename traits::decay::type ftype; typedef typename util::FunctionSignature::type fsigtype; typedef typename index_range<1, fsigtype::argument_count + 1>::type index; typedef typename fsigtype::argument_type_tuple argument_type_tuple; return _sctype_apply(state, index(), argument_type_tuple(), opt_count); } template std::string argTypesName(const F &, int opt_count = 0) { typedef typename traits::decay::type ftype; typedef typename util::FunctionSignature::type fsigtype; typedef typename index_range<1, fsigtype::argument_count + 1>::type index; typedef typename fsigtype::argument_type_tuple argument_type_tuple; return _type_name_apply(index(), argument_type_tuple(), opt_count); } template int minArgCount(const F &) { typedef typename traits::decay::type ftype; typedef typename util::FunctionSignature::type fsigtype; return fsigtype::argument_count; } template int maxArgCount(const F &) { typedef typename traits::decay::type ftype; typedef typename util::FunctionSignature::type fsigtype; return fsigtype::argument_count; } // for constructor template struct ConstructorFunctor; template struct ConstructorFunctor > { typedef util::FunctionSignatureType signature_type; typedef typename index_range<1, sizeof...(Args) + 1>::type get_index; template int invoke(lua_State *L, index_tuple) const { typedef ObjectWrapper wrapper_type; void *storage = lua_newuserdata(L, sizeof(wrapper_type)); try { new (storage) wrapper_type(lua_type_traits::get(L, Indexes)...); } catch (...) { lua_pop(L, 1); throw; } class_userdata::setmetatable(L); return 1; } int operator()(lua_State *L) const { return invoke(L, get_index()); } bool checkArgTypes(lua_State *L, int opt_count = 0) const { return _ctype_apply(L, get_index(), typename signature_type::argument_type_tuple(), opt_count); } bool strictCheckArgTypes(lua_State *L, int opt_count = 0) const { return _sctype_apply(L, get_index(), typename signature_type::argument_type_tuple(), opt_count); } std::string argTypesName(int opt_count = 0) const { return _type_name_apply( get_index(), typename signature_type::argument_type_tuple(), opt_count); } }; template struct ConstructorFunction; template struct ConstructorFunction { typedef ConstructorFunctor > type; }; template struct ConstructorFunction // class type check version { typedef ConstructorFunctor > type; }; } using nativefunction::ConstructorFunction; }