您的位置:首页 > 编程语言 > Lua

C++调用LUA函数,可变参模板实现

2015-06-30 10:19 686 查看
极其方便调用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. */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ lua