# HG changeset patch # User jbe # Date 1406743151 -7200 # Node ID 0edc2f05c66ab52201c0f15a800e84770337a82c # Parent 0690fe79b673129cc4b567a59c8bc0091b4df646 Use lightuserdata directly to store JSON null values in JSON library diff -r 0690fe79b673 -r 0edc2f05c66a libraries/json/json.c --- a/libraries/json/json.c Wed Jul 30 19:24:06 2014 +0200 +++ b/libraries/json/json.c Wed Jul 30 19:59:11 2014 +0200 @@ -8,46 +8,56 @@ // macros for usage of Lua registry: #define JSON_REGENT char -#define JSON_REGREF void * -#define json_regref(x) (&json_registry.x) -#define json_regfetchref(L, x) (lua_pushlightuserdata((L), (x)), lua_rawget((L), LUA_REGISTRYINDEX)) -#define json_regfetch(L, x) (json_regfetchref(L, json_regref(x))) -#define json_regstore(L, x) (lua_pushlightuserdata(L, json_regref(x)), lua_pushvalue(L, -2), lua_rawset(L, LUA_REGISTRYINDEX)); +#define JSON_REGPOINTER void * +#define json_pushlightref(L, x) (lua_pushlightuserdata((L), &json_reference.x)) +#define json_regpointer(x) (&json_registry.x) +#define json_regfetchpointer(L, x) (lua_pushlightuserdata((L), (x)), lua_rawget((L), LUA_REGISTRYINDEX)) +#define json_regfetch(L, x) (json_regfetchpointer(L, json_regpointer(x))) +#define json_regstore(L, x) (lua_pushlightuserdata(L, json_regpointer(x)), lua_pushvalue(L, -2), lua_rawset(L, LUA_REGISTRYINDEX)); + +// generate dummy memory addresses that represent Lua objects +// directly via lightuserdata values (not using the Lua registry): +static struct { + JSON_REGENT nullmark; // magic value to indicate JSON null value +} json_reference; + // generate dummy memory addresses that represent Lua objects -// (via lightuserdata keys and LUA_REGISTRYINDEX): +// via lightuserdata keys and LUA_REGISTRYINDEX: static struct { - JSON_REGENT nullmark; - JSON_REGENT shadowtbl; - JSON_REGENT unknownmt; - JSON_REGENT objectmt; - JSON_REGENT arraymt; + JSON_REGENT shadowtbl; // ephemeron table that maps tables to their corresponding shadow table + JSON_REGENT unknownmt; // metatable for tables that may be either JSON objects or JSON arrays + JSON_REGENT objectmt; // metatable for JSON objects + JSON_REGENT arraymt; // metatable for JSON arrays } json_registry; -// marks a table as JSON object or JSON array: +// marks a Lua table as JSON object or JSON array: // (returns its modified argument or a new table if argument is nil) -static int json_mark(lua_State *L, JSON_REGREF mt) { - // if argument is nil, then create new table: +static int json_mark(lua_State *L, JSON_REGPOINTER mt) { + // check if argument is nil if (lua_isnoneornil(L, 1)) { + // create new table at stack position 1: lua_settop(L, 0); lua_newtable(L); - // set shadow table: + // create shadow table (leaving previously created table on stack position 1): json_regfetch(L, shadowtbl); lua_pushvalue(L, 1); lua_newtable(L); lua_rawset(L, -3); } else { - // check if shadow table already exists: + // push shadow table on top of stack: json_regfetch(L, shadowtbl); lua_pushvalue(L, 1); lua_rawget(L, -2); + // if shadow table does not exist: if (lua_isnil(L, -1)) { - // set shadow table and leave it on top of stack: + // create shadow table and leave it on top of stack: lua_newtable(L); lua_pushvalue(L, 1); lua_pushvalue(L, -2); lua_rawset(L, -5); } + // move elements from original table to shadow table (that's expected on top of stack): for(lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { lua_pushvalue(L, -2); lua_pushnil(L); @@ -60,7 +70,7 @@ // discard everything but table to return: lua_settop(L, 1); // set metatable: - json_regfetchref(L, mt); + json_regfetchpointer(L, mt); lua_setmetatable(L, 1); // return table: return 1; @@ -69,15 +79,16 @@ // marks a table as JSON object: // (returns its modified argument or a new table if argument is nil) static int json_object(lua_State *L) { - return json_mark(L, json_regref(objectmt)); + return json_mark(L, json_regpointer(objectmt)); } // marks a table as JSON array: // (returns its modified argument or a new table if argument is nil) static int json_array(lua_State *L) { - return json_mark(L, json_regref(arraymt)); + return json_mark(L, json_regpointer(arraymt)); } +// internal states of JSON parser: #define JSON_STATE_VALUE 0 #define JSON_STATE_OBJECT_KEY 1 #define JSON_STATE_OBJECT_KEY_TERMINATOR 2 @@ -87,6 +98,7 @@ #define JSON_STATE_ARRAY_SEPARATOR 6 #define JSON_STATE_END 7 +// special Lua stack indicies for json_import function: #define json_import_objectmt_idx 2 #define json_import_arraymt_idx 3 #define json_import_shadowtbl_idx 4 @@ -98,21 +110,21 @@ size_t total; // total length of string to parse size_t pos = 0; // current position in string to parse size_t level = 0; // nested levels of objects/arrays currently being processed - int mode = JSON_STATE_VALUE; // state of parser + int mode = JSON_STATE_VALUE; // state of parser (i.e. "what's expected next?") char c; // variable to store a single character to be processed - luaL_Buffer luabuf; // Lua buffer to decode (possibly escaped) strings - char *cbuf; // C buffer to decode (possibly escaped) strings + luaL_Buffer luabuf; // Lua buffer to decode JSON string values + char *cbuf; // C buffer to decode JSON string values size_t writepos; // write position of decoded strings in C buffer - // limit stack to 1 element: + // stack shall only contain one function argument: lua_settop(L, 1); - // push json_objectmt on stack position 2: + // push objectmt on stack position 2: json_regfetch(L, objectmt); - // push json_arraymt on stack position 3: + // push arraymt on stack position 3: json_regfetch(L, arraymt); - // push json_shadowtbl on stack position 4: + // push shadowtbl on stack position 4: json_regfetch(L, shadowtbl); - // push json_nullmark on stack position 5: - json_regfetch(L, nullmark); + // push nullmark on stack position 5: + json_pushlightref(L, nullmark); // require string as first argument: str = luaL_checklstring(L, 1, &total); // if string contains a NULL byte, this is a syntax error @@ -402,7 +414,7 @@ json_regfetch(L, shadowtbl); lua_insert(L, 1); // insert json_nullmark on stack at position 2: - json_regfetch(L, nullmark); + json_pushlightref(L, nullmark); lua_insert(L, 2); // store number of arguments: stacktop = lua_gettop(L); @@ -536,7 +548,7 @@ lua_rawset(L, json_setnull_shadowtbl_idx); } lua_pushvalue(L, 2); - json_regfetch(L, nullmark); + json_pushlightref(L, nullmark); lua_rawset(L, -3); return 0; } @@ -555,7 +567,7 @@ static int json_index(lua_State *L) { lua_settop(L, 2); - json_regfetch(L, nullmark); // on stack position 3 + json_pushlightref(L, nullmark); // on stack position 3 json_regfetch(L, shadowtbl); lua_pushvalue(L, 1); lua_rawget(L, json_index_shadowtbl_idx); @@ -583,7 +595,7 @@ static int json_pairs_iterfunc(lua_State *L) { lua_settop(L, 2); - json_regfetch(L, nullmark); // on stack position 3 + json_pushlightref(L, nullmark); // on stack position 3 json_regfetch(L, shadowtbl); lua_pushvalue(L, 1); lua_rawget(L, json_pairs_iterfunc_shadowtbl_idx); @@ -610,7 +622,7 @@ static int json_ipairs_iterfunc(lua_State *L) { int idx; lua_settop(L, 2); - json_regfetch(L, nullmark); // on stack position 3 + json_pushlightref(L, nullmark); // on stack position 3 json_regfetch(L, shadowtbl); idx = lua_tointeger(L, 2) + 1; lua_pushvalue(L, 1); @@ -673,8 +685,6 @@ lua_rawset(L, -3); lua_setmetatable(L, -2); json_regstore(L, shadowtbl); - lua_newtable(L); - json_regstore(L, nullmark); lua_settop(L, 1); luaL_setfuncs(L, json_module_functions, 0); return 1;