From f6a88e1ee6d62dc447a8d8b1d77d63f1ab9b5ade Mon Sep 17 00:00:00 2001 From: ubq323 Date: Sun, 19 Mar 2023 20:39:32 +0000 Subject: add support for lua 5.1 uses a weak-keyed table in the registry to store parent-child mappings, instead of associated uservalues, which were only added in 5.2. --- Makefile | 6 +++++- lmdb.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 4b4860a..21d3629 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,11 @@ LUA_VER=5.3 CC = cc LD = ld -CFLAGS = -std=c99 -Wall -O2 -fPIC -I/usr/include/lua$(LUA_VER) +MORE_CFLAGS= +ifeq ($(LUA_VER),5.1) + MORE_CFLAGS=-DLUA_5_1 +endif +CFLAGS = $(MORE_CFLAGS) -std=c99 -Wall -O2 -fPIC -I/usr/include/lua$(LUA_VER) LFLAGS = -shared -llmdb lmdb.so: lmdb.o diff --git a/lmdb.c b/lmdb.c index d85ce4f..41bb2cf 100644 --- a/lmdb.c +++ b/lmdb.c @@ -26,6 +26,10 @@ struct handle { luaL_error(L, "%s", mdb_strerror(__res)); \ } while (0) +static void get_parent(lua_State *L, int index); +static void set_parent(lua_State *L, int index); + + static void check_valid(lua_State *L, struct handle *h) { if (h->closed) luaL_error(L, "attempt to use expired handle"); } @@ -49,6 +53,14 @@ static int version(lua_State *L) { return 3; } +#ifdef LUA_5_1 +lua_Integer lua_tointegerx(lua_State *L, int index, int *isnum) { + if (isnum != NULL) + *isnum = lua_isnumber(L,index); + return lua_tointeger(L, index); +} +#endif + static int env_open(lua_State *L) { lua_settop(L, 2); luaL_argcheck(L, lua_isstring(L, 1), 1, "expected string"); @@ -118,7 +130,7 @@ static int env_copy(lua_State *L) { static MDB_env *get_env(lua_State *L, int idx) { lua_pushvalue(L, idx); struct handle *ud = NULL; - while (lua_getuservalue(L, -1) == LUA_TUSERDATA) { + while (get_parent(L, -1), lua_type(L, -1) == LUA_TUSERDATA) { ud = lua_touserdata(L, -1); if (ud->closed) return NULL; check_valid(L, ud); @@ -161,7 +173,7 @@ static int txn_begin(lua_State *L, bool nested) { lua_setmetatable(L, -2); // store the supplied transaction/env as the parent lua_pushvalue(L, 1); - lua_setuservalue(L, -2); + set_parent(L, -2); ud->has_child = true; return 1; @@ -185,7 +197,7 @@ static int txn_abort(lua_State *L) { mdb_txn_abort(ud->obj); ud->closed = true; - lua_getuservalue(L, 1); + get_parent(L, 1); struct handle *pud = lua_touserdata(L, -1); pud->has_child = false; @@ -200,7 +212,7 @@ static int txn_commit(lua_State *L) { check_env(L, 1); ud->closed = true; - lua_getuservalue(L, 1); + get_parent(L, 1); struct handle *pud = lua_touserdata(L, -1); pud->has_child = false; @@ -225,7 +237,7 @@ static int db_open(lua_State *L) { lua_setmetatable(L, -2); // transaction is parent of DB handle lua_pushvalue(L, 1); - lua_setuservalue(L, -2); + set_parent(L, -2); return 1; } @@ -245,7 +257,7 @@ static int db_get(lua_State *L) { check_env(L, 1); luaL_argcheck(L, lua_isstring(L, 2), 2, "expected string"); - lua_getuservalue(L, 1); + get_parent(L, 1); struct handle *tud = lua_touserdata(L, -1); MDB_val key = toval(L, 2); MDB_val data; @@ -266,7 +278,7 @@ static int db_put(lua_State *L) { luaL_argcheck( L, lua_isnil(L, 3) || lua_isstring(L, 3), 3, "expected string or nil"); - lua_getuservalue(L, 1); + get_parent(L, 1); struct handle *tud = lua_touserdata(L, -1); MDB_val key = toval(L, 2); if (!lua_isnil(L, 3)) { @@ -283,7 +295,7 @@ static int db_next(lua_State *L) { luaL_argcheck( L, lua_isnil(L, 2) || lua_isstring(L, 2), 2, "expected string or nil"); - lua_getuservalue(L, 1); + get_parent(L, 1); struct handle *tud = lua_touserdata(L, -1); MDB_cursor *curs; asserr(mdb_cursor_open(tud->obj, dbi, &curs)); @@ -370,7 +382,11 @@ static const struct luaL_Reg lmdb_db[] = { static void mt(lua_State *L, const char *name, const struct luaL_Reg l[]) { luaL_newmetatable(L, name); +#ifdef LUA_5_1 + luaL_register(L, NULL, l); +#else luaL_setfuncs(L, l, 0); +#endif lua_getfield(L, -1, "__index"); if (lua_isnil(L, -1)){ lua_pop(L, 1); @@ -379,11 +395,47 @@ static void mt(lua_State *L, const char *name, const struct luaL_Reg l[]) { lua_pop(L, 2); } +static void parentmap(lua_State *L) { + lua_getfield(L, LUA_REGISTRYINDEX, "lmdb.parentmap"); +} + +static void get_parent(lua_State *L, int index) { + lua_pushvalue(L, index); // k ... k + parentmap(L); // k ... k t + lua_insert(L, -2); // k ... t k + lua_gettable(L, -2); // k ... t v + lua_remove(L, -2); // k ... v +} +static void set_parent(lua_State *L, int index) { + // references to `index` need to be before anything changes the stack, + // otherwise indices will be off + // k ... v + lua_pushvalue(L, index); // k ... v k + parentmap(L); // k ... v k t + lua_insert(L, -3); // k ... t v k + lua_insert(L, -2); // k ... t k v + lua_settable(L, -3); // k ... t + lua_pop(L, 1); // k ... +} + + int luaopen_lmdb(lua_State *L) { mt(L, "lmdb.env", lmdb_env); mt(L, "lmdb.txn", lmdb_txn); mt(L, "lmdb.db", lmdb_db); + lua_newtable(L); + lua_newtable(L); + lua_pushliteral(L, "k"); + lua_setfield(L, -2, "__mode"); + lua_setmetatable(L, -2); + lua_setfield(L, LUA_REGISTRYINDEX, "lmdb.parentmap"); + +#ifdef LUA_5_1 + lua_newtable(L); + luaL_register(L, NULL, lmdb); +#else luaL_newlib(L, lmdb); +#endif return 1; } -- cgit v1.2.3