7 Stimmen

Klonen einer Lua-Tabelle in Lua C API

Es gibt haufenweise Beispiele dafür, wie man eine Lua-Tabelle in Lua klont, aber ich konnte kein Beispiel dafür finden, wie man es mit der nativen Lua-C-API macht. Ich habe zweimal versucht, es von Hand zu machen, aber es endete mit einem echten (wenn auch funktionierenden) Chaos.

Hat jemand irgendwelche Tipps oder Links, wie man elegant eine flache Kopie einer Lua-Tabelle in der C-API tun?

10voto

Puppy Punkte 141483

Sie müssen die Lua-Funktion definieren und sie dann in die zugehörigen API-Aufrufe aufschlüsseln.

shallow_copy = function(tab)
    local retval = {}
    for k, v in pairs(tab) do
        retval[k] = v
    end
    return retval
end

Wir müssen also den Index einer Tabelle auf dem Stack und den lua_State nehmen.

void shallow_copy(lua_State* L, int index) {

/*Create a new table on the stack.*/

        lua_newtable(L);

/*Now we need to iterate through the table. 
Going to steal the Lua API's example of this.*/

        lua_pushnil(L);
        while(lua_next(L, index) != 0) {
/*Need to duplicate the key, as we need to set it
(one pop) and keep it for lua_next (the next pop). Stack looks like table, k, v.*/

            lua_pushvalue(L, -2);
/*Now the stack looks like table, k, v, k. 
But now the key is on top. Settable expects the value to be on top. So we 
need to do a swaparooney.*/

            lua_insert(L, -2);

    /*Now we just set them. Stack looks like table,k,k,v, so the table is at -4*/

    lua_settable(L, -4);

/*Now the key and value were set in the table, and we popped off, so we have
table, k on the stack- which is just what lua_next wants, as it wants to find
the next key on top. So we're good.*/

        }
    }

Unsere kopierte Tabelle befindet sich nun oben auf dem Stapel.

Mein Gott, die Lua-API nervt.

0voto

Chaos Punkte 1

HI folgendes Codesegment implementiert deepcopy,enjoy:

static int deepCopy(lua_State* L,int n,int CacheT)
{
    int copyIndex = 0;
    switch (lua_type(L, n))
    {
    case LUA_TNIL:
        lua_pushnil(L);
        copyIndex = lua_gettop(L);
        break;
    case LUA_TBOOLEAN:
        lua_pushboolean(L, lua_toboolean(L, n));
        copyIndex = lua_gettop(L);
        break;
    case LUA_TNUMBER:
        lua_pushnumber(L, lua_tonumber(L, n));
        copyIndex = lua_gettop(L);
        break;
    case LUA_TSTRING:
        lua_pushlstring(L, lua_tostring(L, n), lua_rawlen(L, n));
        copyIndex = lua_gettop(L);
        break;
    case LUA_TLIGHTUSERDATA:
    case LUA_TUSERDATA:
        lua_pushlightuserdata(L, (void*)lua_touserdata(L, n));
        copyIndex = lua_gettop(L);
        break;
    case LUA_TFUNCTION:
        lua_pushvalue(L, n);
        copyIndex = lua_gettop(L);
        break;
    case LUA_TTHREAD:
        lua_pushvalue(L, n);
        copyIndex = lua_gettop(L);
        break;
    case LUA_TTABLE:
    {

            //push key
            lua_pushvalue(L, n);
            //try to get cached obj(should pop key from stack and push get value onto stack)
            int32 type = lua_gettable(L, CacheT);
            if (type == LUA_TTABLE)
            {
                //just return
                copyIndex = lua_gettop(L);//push 1
            }
            else 
            {
                //pop the pushed get table return value
                lua_pop(L, 1);
                {
                    lua_newtable(L);
                    copyIndex = lua_gettop(L);

                    //push key
                    lua_pushvalue(L, n);
                    //push value
                    lua_pushvalue(L, copyIndex);
                    //save created table into cacheT
                    lua_settable(L, CacheT);

                    /* table is in the stack at index 't' */
                    lua_pushnil(L);  /* first key */
                    while (lua_next(L, n) != 0) {
                        /* uses 'key' (at index -2) and 'value' (at index -1) */
                        int keyIndex = lua_absindex(L, -2);//1
                        int valueIndex = lua_absindex(L, -1);//2
                        int copyedKey = deepCopy(L, keyIndex, CacheT);//3
                        int copyedValue = deepCopy(L, valueIndex, CacheT);//4
                        //push key
                        lua_pushvalue(L, copyedKey);
                        //push value
                        lua_pushvalue(L, copyedValue);
                        lua_settable(L, copyIndex);
                        /* removes 'value'; keeps 'key' for next iteration */
                        lua_pop(L, 3);
                    }

                    if (1 == lua_getmetatable(L, n))//try to get metatable of n(push onto stack if return 1)
                    {
                        int metaIndex = lua_gettop(L);
                        metaIndex = lua_absindex(L, -1);
                        //push 1
                        int copyedMeta = deepCopy(L, metaIndex, CacheT);//try to copy meta table push onto stack
                        lua_setmetatable(L, copyIndex);//set meta table and pop copyedMeta
                        lua_pop(L, 1);//pop lua_getmetatable pushed value
                    }
                    else
                    {
                        ;//do nothing
                    }
                }
            }
        break;
    }

    }
    return copyIndex;
}

//following c++ equals lua logic like this:
/*
function _G.tclone(value)
    local function __tclone(value,cached)
        local copy
        local cacheT = cached or {}
        if type(value) == 'table' then
            --if has been already cloned just return handle recursive
            if nil ~= cacheT[value] then
                copy =   cacheT[value]
            else
                copy = {}
                cacheT[value] = copy
                for k,v in pairs(value) do
                    --clone key                --clone value
                    copy[__tclone(k,cacheT)] = __tclone(v,cacheT)
                end
                --clone metatable
                setmetatable(copy, __tclone(getmetatable(value), cacheT))
            end
        else
            copy = value
        end
        return copy
    end
    return __tclone(value,nil)
end
---
*/
static int tClone(lua_State* L, int n)
{
    int cacheT;
    int copy;
    lua_newtable(L);
    cacheT = lua_gettop(L);
    copy = deepCopy(L, n, cacheT);
    lua_remove(L, cacheT);
    return copy;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X