Skip to content

Instantly share code, notes, and snippets.

@cloudwu
Last active May 21, 2021 08:42
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save cloudwu/a48200653b6597de0446ddb7139f62e3 to your computer and use it in GitHub Desktop.
Save cloudwu/a48200653b6597de0446ddb7139f62e3 to your computer and use it in GitHub Desktop.
Clone a lua table
// gcc -o clonetable.so --shared lclonetable.c -I$(LUAINCLUDE)
#include <lobject.h>
#include <ltable.h>
#include <lgc.h>
#include <lstate.h>
#include <lauxlib.h>
#include <lualib.h>
#include <lua.h>
#include <string.h>
#define black2gray(x) resetbit(x->marked, BLACKBIT)
#define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o))
static void
barrierback(lua_State *L, Table *t) {
if (isblack(t)) {
global_State *g = G(L);
black2gray(t); /* make table gray (again) */
linkgclist(t, g->grayagain);
}
}
// table.clone(to, from)
static int
lclonetable(lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checktype(L, 2, LUA_TTABLE);
Table * to = (Table *)lua_topointer(L, 1);
const Table * from = lua_topointer(L, 2);
void *ud;
lua_Alloc alloc = lua_getallocf(L, &ud);
if (from->lsizenode != to->lsizenode) {
if (isdummy(from)) {
// free to->node
if (!isdummy(to))
alloc(ud, to->node, sizenode(to) * sizeof(Node), 0);
to->node = from->node;
} else {
unsigned int size = sizenode(from) * sizeof(Node);
Node *node = alloc(ud, NULL, 0, size);
if (node == NULL)
luaL_error(L, "Out of memory");
memcpy(node, from->node, size);
// free to->node
if (!isdummy(to))
alloc(ud, to->node, sizenode(to) * sizeof(Node), 0);
to->node = node;
}
to->lsizenode = from->lsizenode;
} else if (!isdummy(from)) {
unsigned int size = sizenode(from) * sizeof(Node);
if (isdummy(to)) {
Node *node = alloc(ud, NULL, 0, size);
if (node == NULL)
luaL_error(L, "Out of memory");
to->node = node;
}
memcpy(to->node, from->node, size);
}
if (from->lastfree) {
int lastfree = from->lastfree - from->node;
to->lastfree = to->node + lastfree;
} else {
to->lastfree = NULL;
}
if (from->sizearray != to->sizearray) {
if (from->sizearray) {
TValue *array = alloc(ud, NULL, 0, from->sizearray * sizeof(TValue));
if (array == NULL)
luaL_error(L, "Out of memory");
alloc(ud, to->array, to->sizearray * sizeof(TValue), 0);
to->array = array;
} else {
alloc(ud, to->array, to->sizearray * sizeof(TValue), 0);
to->array = NULL;
}
to->sizearray = from->sizearray;
}
memcpy(to->array, from->array, from->sizearray * sizeof(TValue));
barrierback(L,to);
lua_settop(L, 1);
return 1;
}
LUAMOD_API int
luaopen_clonetable(lua_State *L) {
luaL_checkversion(L);
luaL_requiref(L, "table", luaopen_table, 0);
lua_pushcfunction(L, lclonetable);
lua_setfield(L, -2, "clone");
return 1;
}
/*
local table = require "clonetable"
a = {x=1,y=2, 5,6,7}
table.clone(a, {1,2,3, z=4})
for k,v in pairs(a) do
print(k,v)
end
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment