极其方便调用LUA函数,支持返回值方式:
调用示例:
luax_vcall("func_1", 12, 33, 4.0, "helloworld");
int result = luax_pvicall("utils.math.add", 20, 30, 100);
直接贴出代码:
/* powerful lua call, vardic template. */
#ifndef _POWERFUL_LUA_CALL_HELPER_
#define _POWERFUL_LUA_CALL_HELPER_
/// helper
inline bool luax_assume_func(lua_State* L, const char* func);
/// FUNCTION TEMPLATE: luax_vcall
template<typename..._Args> inline
void luax_vcall(const char* func, const _Args&...args);
template<typename _Result, typename..._Args> inline
_Result luax_vxcall(const char* func, const _Args&...args);
/// TEMPLATE luax_vxcall alias
template<typename..._Args> inline
int luax_vicall(const char* func, const _Args&...args);
template<typename..._Args> inline
float luax_vfcall(const char* func, const _Args&...args);
template<typename..._Args> inline
double luax_vdcall(const char* func, const _Args&...args);
template<typename..._Args> inline
std::string luax_vvcall(const char* func, const _Args&...args);
/// FUNCTION TEMPLATE: luax_vpcall
template<typename..._Args> inline
void luax_pvcall(const char* func, const _Args&...args);
template<typename _Result, typename..._Args> inline
_Result luax_pvxcall(const char* func, const _Args&...args);
/// TEMPLATE luax_pvxcall alias
template<typename..._Args> inline
int luax_pvicall(const char* func, const _Args&...args);
template<typename..._Args> inline
float luax_pvfcall(const char* func, const _Args&...args);
template<typename..._Args> inline
double luax_pvdcall(const char* func, const _Args&...args);
template<typename..._Args> inline
std::string luax_pvvcall(const char* func, const _Args&...args);
/// arg push helper
inline
void luax_vpusharg(lua_State* L, int& carg, int& narg)
{
}
inline
void luax_vpusharg(lua_State* L, int& carg, int& narg, int arg)
{
++carg;
if (lua_checkstack(L, 1))
lua_pushinteger(L, arg), ++narg;
}
inline
void luax_vpusharg(lua_State* L, int& carg, int& narg, float arg)
{
++carg;
if (lua_checkstack(L, 1))
lua_pushnumber(L, arg), ++narg;
}
inline
void luax_vpusharg(lua_State* L, int& carg, int& narg, double arg)
{
++carg;
if (lua_checkstack(L, 1))
lua_pushnumber(L, arg), ++narg;
}
inline
void luax_vpusharg(lua_State* L, int& carg, int& narg, const char* arg)
{
++carg;
if (lua_checkstack(L, 1))
lua_pushstring(L, arg), ++narg;
}
inline
void luax_vpusharg(lua_State* L, int& carg, int& narg, const std::string& arg)
{
++carg;
if (lua_checkstack(L, 1))
lua_pushlstring(L, arg.c_str(), arg.length()), ++narg;
}
inline
void luax_vpusharg(lua_State* L, int& carg, int& narg, void* arg)
{
++carg;
if (lua_checkstack(L, 1))
tolua_pushuserdata(L, arg), ++narg;
}
/// cocos2d-x object support
#define LUAX_VCALL_ADD_CCOBJ_SUPPORT(type) \
inline \
void luax_vpusharg(lua_State* L, int& carg, int& narg, cocos2d::type* arg) \
{ \
++carg; \
if (lua_checkstack(L, 1)) \
object_to_luaval<cocos2d::type>(L, "cc." #type, arg),/*tolua_pushuserdata(L, arg),*/ ++narg; \
}
#define LUAX_VCALL_ADD_CCUI_SUPPORT(type) \
inline \
void luax_vpusharg(lua_State* L, int& carg, int& narg, type* arg) \
{ \
++carg; \
if (lua_checkstack(L, 1)) \
object_to_luaval<cocos2d::ui::type>(L, "ccui." #type, arg),/*tolua_pushuserdata(L, arg),*/ ++narg; \
}
LUAX_VCALL_ADD_CCOBJ_SUPPORT(Node)
LUAX_VCALL_ADD_CCOBJ_SUPPORT(Scene)
LUAX_VCALL_ADD_CCOBJ_SUPPORT(Layer)
LUAX_VCALL_ADD_CCOBJ_SUPPORT(LayerColor)
LUAX_VCALL_ADD_CCOBJ_SUPPORT(Sprite)
template<typename _Ty, typename..._Args> inline
void luax_vpusharg(lua_State* L, int& carg, int& narg, _Ty arg1, const _Args&...args)
{
luax_vpusharg(L, carg, narg, arg1);
luax_vpusharg(L, carg, narg, args...);
}
template<typename _Ty> inline
_Ty luax_getretval(lua_State* L);
template<> inline
int luax_getretval<int>(lua_State* L)
{
if (lua_isnumber(L, -1)){
return lua_tointeger(L, -1);
}
return 0;
}
template<> inline
float luax_getretval<float>(lua_State* L)
{
if (lua_isnumber(L, -1)){
return lua_tonumber(L, -1);
}
return 0;
}
template<> inline
double luax_getretval<double>(lua_State* L)
{
if (lua_isnumber(L, -1)){
return lua_tonumber(L, -1);
}
return 0;
}
template<> inline
std::string luax_getretval<std::string>(lua_State* L)
{
if (lua_isstring(L, -1)){
return lua_tostring(L, -1);
}
return 0;
}
template<typename..._Args> inline
void luax_vcall(const char* func, const _Args&...args)
{
auto L = luax_get_L();
auto top = lua_gettop(L); // store stack
int carg = 0, narg = 0;
lua_getglobal(L, func);
if (!lua_isfunction(L, -1))
{
cocos2d::log("luax_vcall failed, function:%s not exist!", func);
goto err_exit;
}
luax_vpusharg(L, carg, narg, args...);
if (carg != narg) {
cocos2d::log("luax_vcall failed, argument exception:carg:%d,narg:%d", carg, narg);
goto err_exit;
}
if (lua_pcall(L, narg, 0, 0) != 0)
{
cocos2d::log("luax_vcall failed, func:%s", func);
goto err_exit;
}
lua_settop(L, top); // resume stack
err_exit:
lua_settop(L, top); // resume stack
}
inline bool luax_assume_func(lua_State* L, const char* func)
{
std::string source = func;
const char* orig = source.c_str();
const char* name = orig;
auto offst = 0;
auto end = 0;
end = source.find_first_of('.', offst);
if (end == std::string::npos)
{ // assume _G.func
lua_getglobal(L, name);
if (lua_isfunction(L, -1))
return true;
else
return false;
}
// assume table
source[end] = '\0';
lua_getglobal(L, name);
if (!lua_istable(L, -1))
return false;
offst = end + 1;
// continue check sub table
while ((end = source.find_first_of('.', offst)) != std::string::npos)
{ // assume table
source[end] = '\0';
name = orig + offst;
lua_getfield(L, -1, name);
if (!lua_istable(L, -1))
{
return false;
}
offst = end + 1;
}
// now assume function
name = orig + offst;
lua_getfield(L, -1, name);
return !!lua_isfunction(L, -1);
}
template<typename _Result, typename..._Args> inline
_Result luax_vxcall(const char* func, const _Args&...args)
{
auto L = luax_get_L();
auto top = lua_gettop(L); // store stack
_Result result;
int carg = 0, narg = 0;
lua_getglobal(L, func);
if (!lua_isfunction(L, -1))
{
cocos2d::log("luax_vcall failed, function:%s not exist!", func);
goto err_exit;
}
luax_vpusharg(L, carg, narg, args...);
if (carg != narg) {
cocos2d::log("luax_vcall failed, argument exception:carg:%d,narg:%d", carg, narg);
goto err_exit;
}
if (lua_pcall(L, narg, 1, 0) != 0)
{
cocos2d::log("luax_vcall failed, lua_pcall failed");
goto err_exit;
}
result = luax_getretval<_Result>(L);
lua_settop(L, top); // resume stack
return std::move(result);
err_exit:
lua_settop(L, top); // resume stack
return _Result();
}
// TEMPLATE luax_vxcall alias
template<typename..._Args> inline
int luax_vicall(const char* func, const _Args&...args)
{
return luax_vxcall<int>(func, args...);
}
template<typename..._Args> inline
float luax_vfcall(const char* func, const _Args&...args)
{
return luax_vxcall<float>(func, args...);
}
template<typename..._Args> inline
double luax_vdcall(const char* func, const _Args&...args)
{
return luax_vxcall<double>(func, args...);
}
template<typename..._Args> inline
std::string luax_vvcall(const char* func, const _Args&...args)
{
return luax_vxcall<std::string>(func, args...);
}
// support any talbe prefix
template<typename..._Args> inline
void luax_pvcall(const char* func, const _Args&...args)
{
auto L = luax_get_L();
auto top = lua_gettop(L); // store stack
int carg = 0, narg = 0;
if (!luax_assume_func(L, func))
{
cocos2d::log("luax_vcall failed, function:%s not exist!", func);
goto err_exit;
}
do_call:
luax_vpusharg(L, carg, narg, args...);
if (carg != narg) {
goto err_exit;
}
if (lua_pcall(L, narg, 0, 0) != 0)
{
goto err_exit;
}
lua_settop(L, top); // resume stack
err_exit:
lua_settop(L, top); // resume stack
}
template<typename _Result, typename..._Args> inline
_Result luax_pvxcall(const char* func, const _Args&...args)
{
auto L = luax_get_L();
auto top = lua_gettop(L); // store stack
_Result result;
int carg = 0, narg = 0;
if (!luax_assume_func(L, func))
{
cocos2d::log("luax_vcall failed, function:%s not exist!", func);
goto err_exit;
}
luax_vpusharg(L, carg, narg, args...);
if (carg != narg) {
cocos2d::log("luax_vcall failed, argument exception:carg:%d,narg:%d", carg, narg);
goto err_exit;
}
if (lua_pcall(L, narg, 1, 0) != 0)
{
cocos2d::log("luax_vcall failed, lua_pcall failed");
goto err_exit;
}
result = luax_getretval<_Result>(L);
lua_settop(L, top); // resume stack
return std::move(result);
err_exit:
lua_settop(L, top); // resume stack
return _Result();
}
template<typename..._Args> inline
int luax_pvicall(const char* func, const _Args&...args)
{
return luax_pvxcall<int>(func, args...);
}
template<typename..._Args> inline
float luax_pvfcall(const char* func, const _Args&...args)
{
return luax_pvxcall<float>(func, args...);
}
template<typename..._Args> inline
double luax_pvdcall(const char* func, const _Args&...args)
{
return luax_pvxcall<double>(func, args...);
}
template<typename..._Args> inline
std::string luax_pvvcall(const char* func, const _Args&...args)
{
return luax_pvxcall<std::string>(func, args...);
}
#endif /* powerful lua call, vardic template. */