C++調用LUA函數,可變參模板實現

極其方便調用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. */


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章