webmcp
changeset 145:0edc2f05c66a
Use lightuserdata directly to store JSON null values in JSON library
author | jbe |
---|---|
date | Wed Jul 30 19:59:11 2014 +0200 (2014-07-30) |
parents | 0690fe79b673 |
children | 7912a05ebc3f |
files | libraries/json/json.c |
line diff
1.1 --- a/libraries/json/json.c Wed Jul 30 19:24:06 2014 +0200 1.2 +++ b/libraries/json/json.c Wed Jul 30 19:59:11 2014 +0200 1.3 @@ -8,46 +8,56 @@ 1.4 1.5 // macros for usage of Lua registry: 1.6 #define JSON_REGENT char 1.7 -#define JSON_REGREF void * 1.8 -#define json_regref(x) (&json_registry.x) 1.9 -#define json_regfetchref(L, x) (lua_pushlightuserdata((L), (x)), lua_rawget((L), LUA_REGISTRYINDEX)) 1.10 -#define json_regfetch(L, x) (json_regfetchref(L, json_regref(x))) 1.11 -#define json_regstore(L, x) (lua_pushlightuserdata(L, json_regref(x)), lua_pushvalue(L, -2), lua_rawset(L, LUA_REGISTRYINDEX)); 1.12 +#define JSON_REGPOINTER void * 1.13 +#define json_pushlightref(L, x) (lua_pushlightuserdata((L), &json_reference.x)) 1.14 +#define json_regpointer(x) (&json_registry.x) 1.15 +#define json_regfetchpointer(L, x) (lua_pushlightuserdata((L), (x)), lua_rawget((L), LUA_REGISTRYINDEX)) 1.16 +#define json_regfetch(L, x) (json_regfetchpointer(L, json_regpointer(x))) 1.17 +#define json_regstore(L, x) (lua_pushlightuserdata(L, json_regpointer(x)), lua_pushvalue(L, -2), lua_rawset(L, LUA_REGISTRYINDEX)); 1.18 + 1.19 +// generate dummy memory addresses that represent Lua objects 1.20 +// directly via lightuserdata values (not using the Lua registry): 1.21 +static struct { 1.22 + JSON_REGENT nullmark; // magic value to indicate JSON null value 1.23 +} json_reference; 1.24 + 1.25 1.26 // generate dummy memory addresses that represent Lua objects 1.27 -// (via lightuserdata keys and LUA_REGISTRYINDEX): 1.28 +// via lightuserdata keys and LUA_REGISTRYINDEX: 1.29 static struct { 1.30 - JSON_REGENT nullmark; 1.31 - JSON_REGENT shadowtbl; 1.32 - JSON_REGENT unknownmt; 1.33 - JSON_REGENT objectmt; 1.34 - JSON_REGENT arraymt; 1.35 + JSON_REGENT shadowtbl; // ephemeron table that maps tables to their corresponding shadow table 1.36 + JSON_REGENT unknownmt; // metatable for tables that may be either JSON objects or JSON arrays 1.37 + JSON_REGENT objectmt; // metatable for JSON objects 1.38 + JSON_REGENT arraymt; // metatable for JSON arrays 1.39 } json_registry; 1.40 1.41 -// marks a table as JSON object or JSON array: 1.42 +// marks a Lua table as JSON object or JSON array: 1.43 // (returns its modified argument or a new table if argument is nil) 1.44 -static int json_mark(lua_State *L, JSON_REGREF mt) { 1.45 - // if argument is nil, then create new table: 1.46 +static int json_mark(lua_State *L, JSON_REGPOINTER mt) { 1.47 + // check if argument is nil 1.48 if (lua_isnoneornil(L, 1)) { 1.49 + // create new table at stack position 1: 1.50 lua_settop(L, 0); 1.51 lua_newtable(L); 1.52 - // set shadow table: 1.53 + // create shadow table (leaving previously created table on stack position 1): 1.54 json_regfetch(L, shadowtbl); 1.55 lua_pushvalue(L, 1); 1.56 lua_newtable(L); 1.57 lua_rawset(L, -3); 1.58 } else { 1.59 - // check if shadow table already exists: 1.60 + // push shadow table on top of stack: 1.61 json_regfetch(L, shadowtbl); 1.62 lua_pushvalue(L, 1); 1.63 lua_rawget(L, -2); 1.64 + // if shadow table does not exist: 1.65 if (lua_isnil(L, -1)) { 1.66 - // set shadow table and leave it on top of stack: 1.67 + // create shadow table and leave it on top of stack: 1.68 lua_newtable(L); 1.69 lua_pushvalue(L, 1); 1.70 lua_pushvalue(L, -2); 1.71 lua_rawset(L, -5); 1.72 } 1.73 + // move elements from original table to shadow table (that's expected on top of stack): 1.74 for(lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { 1.75 lua_pushvalue(L, -2); 1.76 lua_pushnil(L); 1.77 @@ -60,7 +70,7 @@ 1.78 // discard everything but table to return: 1.79 lua_settop(L, 1); 1.80 // set metatable: 1.81 - json_regfetchref(L, mt); 1.82 + json_regfetchpointer(L, mt); 1.83 lua_setmetatable(L, 1); 1.84 // return table: 1.85 return 1; 1.86 @@ -69,15 +79,16 @@ 1.87 // marks a table as JSON object: 1.88 // (returns its modified argument or a new table if argument is nil) 1.89 static int json_object(lua_State *L) { 1.90 - return json_mark(L, json_regref(objectmt)); 1.91 + return json_mark(L, json_regpointer(objectmt)); 1.92 } 1.93 1.94 // marks a table as JSON array: 1.95 // (returns its modified argument or a new table if argument is nil) 1.96 static int json_array(lua_State *L) { 1.97 - return json_mark(L, json_regref(arraymt)); 1.98 + return json_mark(L, json_regpointer(arraymt)); 1.99 } 1.100 1.101 +// internal states of JSON parser: 1.102 #define JSON_STATE_VALUE 0 1.103 #define JSON_STATE_OBJECT_KEY 1 1.104 #define JSON_STATE_OBJECT_KEY_TERMINATOR 2 1.105 @@ -87,6 +98,7 @@ 1.106 #define JSON_STATE_ARRAY_SEPARATOR 6 1.107 #define JSON_STATE_END 7 1.108 1.109 +// special Lua stack indicies for json_import function: 1.110 #define json_import_objectmt_idx 2 1.111 #define json_import_arraymt_idx 3 1.112 #define json_import_shadowtbl_idx 4 1.113 @@ -98,21 +110,21 @@ 1.114 size_t total; // total length of string to parse 1.115 size_t pos = 0; // current position in string to parse 1.116 size_t level = 0; // nested levels of objects/arrays currently being processed 1.117 - int mode = JSON_STATE_VALUE; // state of parser 1.118 + int mode = JSON_STATE_VALUE; // state of parser (i.e. "what's expected next?") 1.119 char c; // variable to store a single character to be processed 1.120 - luaL_Buffer luabuf; // Lua buffer to decode (possibly escaped) strings 1.121 - char *cbuf; // C buffer to decode (possibly escaped) strings 1.122 + luaL_Buffer luabuf; // Lua buffer to decode JSON string values 1.123 + char *cbuf; // C buffer to decode JSON string values 1.124 size_t writepos; // write position of decoded strings in C buffer 1.125 - // limit stack to 1 element: 1.126 + // stack shall only contain one function argument: 1.127 lua_settop(L, 1); 1.128 - // push json_objectmt on stack position 2: 1.129 + // push objectmt on stack position 2: 1.130 json_regfetch(L, objectmt); 1.131 - // push json_arraymt on stack position 3: 1.132 + // push arraymt on stack position 3: 1.133 json_regfetch(L, arraymt); 1.134 - // push json_shadowtbl on stack position 4: 1.135 + // push shadowtbl on stack position 4: 1.136 json_regfetch(L, shadowtbl); 1.137 - // push json_nullmark on stack position 5: 1.138 - json_regfetch(L, nullmark); 1.139 + // push nullmark on stack position 5: 1.140 + json_pushlightref(L, nullmark); 1.141 // require string as first argument: 1.142 str = luaL_checklstring(L, 1, &total); 1.143 // if string contains a NULL byte, this is a syntax error 1.144 @@ -402,7 +414,7 @@ 1.145 json_regfetch(L, shadowtbl); 1.146 lua_insert(L, 1); 1.147 // insert json_nullmark on stack at position 2: 1.148 - json_regfetch(L, nullmark); 1.149 + json_pushlightref(L, nullmark); 1.150 lua_insert(L, 2); 1.151 // store number of arguments: 1.152 stacktop = lua_gettop(L); 1.153 @@ -536,7 +548,7 @@ 1.154 lua_rawset(L, json_setnull_shadowtbl_idx); 1.155 } 1.156 lua_pushvalue(L, 2); 1.157 - json_regfetch(L, nullmark); 1.158 + json_pushlightref(L, nullmark); 1.159 lua_rawset(L, -3); 1.160 return 0; 1.161 } 1.162 @@ -555,7 +567,7 @@ 1.163 1.164 static int json_index(lua_State *L) { 1.165 lua_settop(L, 2); 1.166 - json_regfetch(L, nullmark); // on stack position 3 1.167 + json_pushlightref(L, nullmark); // on stack position 3 1.168 json_regfetch(L, shadowtbl); 1.169 lua_pushvalue(L, 1); 1.170 lua_rawget(L, json_index_shadowtbl_idx); 1.171 @@ -583,7 +595,7 @@ 1.172 1.173 static int json_pairs_iterfunc(lua_State *L) { 1.174 lua_settop(L, 2); 1.175 - json_regfetch(L, nullmark); // on stack position 3 1.176 + json_pushlightref(L, nullmark); // on stack position 3 1.177 json_regfetch(L, shadowtbl); 1.178 lua_pushvalue(L, 1); 1.179 lua_rawget(L, json_pairs_iterfunc_shadowtbl_idx); 1.180 @@ -610,7 +622,7 @@ 1.181 static int json_ipairs_iterfunc(lua_State *L) { 1.182 int idx; 1.183 lua_settop(L, 2); 1.184 - json_regfetch(L, nullmark); // on stack position 3 1.185 + json_pushlightref(L, nullmark); // on stack position 3 1.186 json_regfetch(L, shadowtbl); 1.187 idx = lua_tointeger(L, 2) + 1; 1.188 lua_pushvalue(L, 1); 1.189 @@ -673,8 +685,6 @@ 1.190 lua_rawset(L, -3); 1.191 lua_setmetatable(L, -2); 1.192 json_regstore(L, shadowtbl); 1.193 - lua_newtable(L); 1.194 - json_regstore(L, nullmark); 1.195 lua_settop(L, 1); 1.196 luaL_setfuncs(L, json_module_functions, 0); 1.197 return 1;