美文网首页
使用c++返回的userdata

使用c++返回的userdata

作者: ManjackGo | 来源:发表于2018-02-01 17:43 被阅读40次

    首先定义一个数据体

    typedef struct NumArray{
        int content[256];
        int size = 256;
    } NumArray;
    

    然后定义各种方法。

    new方法

    开辟一块内存并把地址传给array。然后就可以在c++这边初始化array了。后面那一句是设置metatable的,在这里姑且先理解为找出一个叫做TYPE_LUA_ARRAY的metatable然后设置给本userdata。

    int newArray(lua_State *L){
        NumArray *array = (NumArray*)lua_newuserdata(L, sizeof(NumArray));
        array->size = 256;
        for (auto i = 0; i != array->size; i++){
            array->content[i] = 0;
        }
    
        // find out the metatable that created in the function `luaopen_array`
        // which content the method 'get' and 'set'.
        luaL_getmetatable(L, TYPE_LUA_ARRAY); // metatable's at the top
        lua_setmetatable(L, -2);
    
        return 1;
    }
    

    操作方法

    几个点要注意一下。

    • 传进来的参数必须要是lua_State *类型,返回必须是int类型
    • 先取参数,先来的参数在靠近栈底的地方,后来的在栈顶
    • 操作之后如果有返回值,把返回值放到栈顶
    • 返回代表操作的返回个数
    • 第一个参数一般为userdata,取出来后用lua_touserdata转成void*类型的指针,然后再转成对应的指针
    
    int setArray(lua_State *L){
        NumArray *array = (NumArray*)lua_touserdata(L, -3);
        int index = lua_tointeger(L, -2);
        int value = lua_tointeger(L, -1);
        if (index >= (array->size - 1) || index < 0){
            print_in_lua(current_lua_state, "index out of bound");
            return 0;
        }
        array->content[index] = value;
        return 0;
    }
    
    int array2string(lua_State *L){
        NumArray *array = (NumArray*)lua_touserdata(L, -1);
        string ret = string("array content: ");
        int index = 0;
        for (auto value : array->content){
            if (value == 0){
                continue;
            }
            ret = ret + to_string(value) + ",\t";
            index++;
            if (index >= 15){
                ret = ret + "\n";
                index = 0;
            }
        }
        lua_pushstring(L, ret.c_str());
        return 1;
    }
    
    int getArray(lua_State *L){
        NumArray *array = (NumArray*)lua_touserdata(L, -2);
        int index = lua_tointeger(L, -1);
        int value = array->content[index];
        lua_pushinteger(L, value);
        return 1;
    }
    
    int size(lua_State *L){
        NumArray *array = (NumArray*)lua_touserdata(L, -1);
        lua_pushinteger(L, (int)(array->size));
        return 1;
    }
    

    注册

    lib

    lib分为两部分,一部分为静态函数,一部分为成员函数

    static const struct luaL_reg arraylib_f[] = {
        {"new", newArray},
        { nullptr, nullptr },
    };
    
    static const struct luaL_reg arraylib_m[] = {
        { "set", setArray },
        { "get", getArray },
        { "size", size },
        { "__tostring", array2string },
        { nullptr, nullptr },
    };
    

    注册lib

    1. 首先放一个新的metatable
    2. 注册成员函数lib,第二个参数为nullptr代表着注册到栈顶的表里面去
    3. 把metatable的__index等同于get方法,把__newindex等同于set方法。这样做的好处是可以在lua中使用t[key] = value的方法来调用set,用t[key]来调用get

    上面一部分被我注释掉的代码可以把metatable的__index方法设置为metatable自己。

    int luaopen_array(lua_State *L){
        luaL_newmetatable(L, TYPE_LUA_ARRAY);
        //lua_pushstring(L, "__index");
        //lua_pushvalue(L, -2); // stack: (top->) metatable, "__tostring", metatable
        //lua_settable(L, -3); // result: metatable.__index = metatable
    
        // stack: (top->) metatable
        luaL_openlib(L, nullptr, arraylib_m, 0); // register with the metatable at the stack top
    
        lua_pushstring(L, "__index"); // 
        lua_pushstring(L, "get"); // result: (top->) "get", "__index", metatable
        lua_gettable(L, -3); // result: top-> (the function)__index, "get", metatable
        lua_settable(L, -3); // result: metatable.get = metatable.__index
        // stack: (top->)metatable
    
        // to make __newindex = set
        lua_pushstring(L, "__newindex"); 
        lua_pushstring(L, "set"); 
        lua_gettable(L, -3);
        lua_settable(L, -3);
    
        luaL_openlib(L, "numarray", arraylib_f, 0);
        return 0;
    }
    

    最后在lua代码里可以实现这种效果

    local aArray = numarray.new(); // aAarry的类型是userdata
    aArray[0] = 999;
    print(aArray[0]) // output: 999
    print(aArray) // automatically call the "__tostring" function
    

    相关文章

      网友评论

          本文标题:使用c++返回的userdata

          本文链接:https://www.haomeiwen.com/subject/qgxjzxtx.html