Skip to content

Commit f30fad5

Browse files
committed
Use optimized rope implementation
Optimizes `json.encode` with rope technique and keep track of size with returned index.
1 parent 1576566 commit f30fad5

File tree

2 files changed

+62
-32
lines changed

2 files changed

+62
-32
lines changed

README.md

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Tiny, quick JSON encoding/decoding in pure Lua.
77
## Features
88
* Pure lua, should work on every version (5.1-5.4, JIT)
99
* Quick, focused on performance. (See benchmarks below)
10-
* Actually tiny, ~150 sloc.
10+
* Very small, ~180 sloc.
1111
* Decent error handling: `Expected : to follow key for object at char 39`
1212

1313
## Usage
@@ -32,24 +32,24 @@ print(json.decode([[
3232
* This does not guarantee 100% compatibility with the more niche parts of the JSON spec (like unicode escapes)
3333

3434
## Benchmarks
35-
Using benchmarks/bench.lua:
35+
Using benchmarks/bench.lua [(which tests the simdjson twitter example)](https://raw.githubusercontent.com/simdjson/simdjson/master/jsonexamples/twitter.json) through WSL:
3636

3737
```
3838
LuaJIT 2.1.0-beta3
3939
11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
4040
4141
Running benchmarks...
4242
| Name (Decode) | Min | Max | Avg | Avg / Best |
43-
| vurv78/qjson | 0.0091 | 0.012012 | 0.00968749 | x1.75539 |
44-
| rxi/json | 0.004745 | 0.006889 | 0.0055187 | x1 |
45-
| actboy168/json | 0.010586 | 0.012723 | 0.0113411 | x2.05503 |
46-
| luadist/dkjson | 0.011112 | 0.016785 | 0.0134858 | x2.44366 |
43+
| vurv78/qjson | 0.008763 | 0.010837 | 0.00939495 | x1.72715 |
44+
| rxi/json | 0.00475 | 0.007055 | 0.00543957 | x1 |
45+
| actboy168/json | 0.010547 | 0.013259 | 0.0112183 | x2.06235 |
46+
| luadist/dkjson | 0.011222 | 0.014534 | 0.0126976 | x2.3343 |
4747
4848
| Name (Encode) | Min | Max | Avg | Avg / Best |
49-
| vurv78/qjson | 0.003788 | 0.004491 | 0.004021 | x1 |
50-
| rxi/json | 0.0104 | 0.014977 | 0.0108013 | x2.68623 |
51-
| actboy168/json | 0.010361 | 0.012899 | 0.0110817 | x2.75596 |
52-
| luadist/dkjson | 0.014438 | 0.017056 | 0.0153153 | x3.80883 |
49+
| vurv78/qjson | 0.001677 | 0.002637 | 0.00189174 | x1 |
50+
| rxi/json | 0.010513 | 0.011322 | 0.010924 | x5.77459 |
51+
| actboy168/json | 0.009892 | 0.012293 | 0.0104864 | x5.54327 |
52+
| luadist/dkjson | 0.014829 | 0.01985 | 0.0157059 | x8.30237 |
5353
```
5454

5555
```
@@ -58,18 +58,19 @@ Lua 5.3
5858
5959
Running benchmarks...
6060
| Name (Decode) | Min | Max | Avg | Avg / Best |
61-
| vurv78/qjson | 0.015195 | 0.018472 | 0.0159068 | x1 |
62-
| rxi/json | 0.045206 | 0.052624 | 0.048079 | x3.02255 |
63-
| actboy168/json | 0.019059 | 0.022751 | 0.0200545 | x1.26075 |
64-
| luadist/dkjson | 0.028623 | 0.034445 | 0.0307014 | x1.93009 |
61+
| luadist/dkjson | 0.028568 | 0.033705 | 0.0306484 | x1.94652 |
62+
| rxi/json | 0.045178 | 0.053548 | 0.0480421 | x3.05121 |
63+
| vurv78/qjson | 0.015006 | 0.018043 | 0.0157452 | x1 |
64+
| actboy168/json | 0.019061 | 0.023373 | 0.0200551 | x1.27372 |
6565
6666
| Name (Encode) | Min | Max | Avg | Avg / Best |
67-
| vurv78/qjson | 0.006012 | 0.017234 | 0.00760202 | x1 |
68-
| rxi/json | 0.015458 | 0.019752 | 0.0170518 | x2.24306 |
69-
| actboy168/json | 0.015981 | 0.021264 | 0.0169299 | x2.22703 |
70-
| luadist/dkjson | 0.02172 | 0.025274 | 0.0229826 | x3.02323 |
67+
| luadist/dkjson | 0.021639 | 0.024754 | 0.0226422 | x4.10556 |
68+
| rxi/json | 0.015463 | 0.019618 | 0.0166444 | x3.01802 |
69+
| vurv78/qjson | 0.005148 | 0.006336 | 0.00551502 | x1 |
70+
| actboy168/json | 0.016263 | 0.018331 | 0.0170535 | x3.09218 |
7171
```
7272

73-
From here, you can see this library is significantly faster on regular lua, and a bit slower than rxi/json on LuaJIT.
73+
From here, you can see this library is significantly faster for `json.encode` in comparison to `json.decode`.
74+
Additionally `decode` is faster on PUC-Lua than LuaJIT.
7475

7576
Currently working on making it faster for LuaJIT, but this is pretty hard to fix considering making it faster would require not using as many [lua patterns](https://www.lua.org/pil/20.2.html), which would slow down PUC-Lua.

qjson.lua

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -159,33 +159,62 @@ local function isarray(t)
159159
return true
160160
end
161161

162-
local encode
163-
local function value(v)
162+
local _encode
163+
local function value(v, buffer, nbuffer)
164164
local t = type(v)
165165
if t == "table" then
166-
return encode(v)
166+
return _encode(v, buffer, nbuffer)
167167
elseif t == "string" then
168-
return format("%q", v)
168+
buffer[nbuffer + 1] = format("%q", v)
169169
else
170-
return tostring(v)
170+
buffer[nbuffer + 1] = tostring(v)
171171
end
172+
return nbuffer + 1
172173
end
173174

174-
function encode(tbl --[[@param tbl table]]) ---@return string
175+
function _encode(tbl --[[@param tbl table]], buffer --[[@param buffer table]], nbuffer --[[@param nbuffer integer]])
175176
if isarray(tbl) then
176-
local strs, len = {}, #tbl
177+
nbuffer = nbuffer + 1
178+
buffer[nbuffer] = "["
179+
180+
local len = #tbl
177181
for i = 1, len do
178-
strs[i] = value(tbl[i])
182+
nbuffer = value(tbl[i], buffer, nbuffer) + 1
183+
buffer[nbuffer] = ","
184+
end
185+
186+
if len ~= 0 then
187+
buffer[nbuffer] = "]"
188+
else
189+
nbuffer = nbuffer + 1
190+
buffer[nbuffer] = "]"
179191
end
180-
return "[" .. concat(strs, ",", 1, len) .. "]"
181192
else
182-
local kvs, nkvs = {}, 0
193+
nbuffer = nbuffer + 1
194+
buffer[nbuffer] = "{"
195+
196+
local prev = nbuffer
183197
for k, v in pairs(tbl) do
184-
nkvs = nkvs + 1
185-
kvs[nkvs] = "\"" .. tostring(k) .. "\"" .. ":" .. value(v)
198+
nbuffer = nbuffer + 1
199+
buffer[nbuffer] = "\"" .. tostring(k) .. "\":"
200+
nbuffer = value(v, buffer, nbuffer) + 1
201+
buffer[nbuffer] = ","
202+
end
203+
204+
if nbuffer ~= prev then
205+
buffer[nbuffer] = "}"
206+
else
207+
nbuffer = nbuffer + 1
208+
buffer[nbuffer] = "}"
186209
end
187-
return "{" .. concat(kvs, ",", 1, nkvs) .. "}";
188210
end
211+
212+
return nbuffer
213+
end
214+
215+
local function encode(tbl --[[@param tbl table]]) ---@return string
216+
local buffer = {}
217+
return concat(buffer, "", 1, _encode(tbl, buffer, 0))
189218
end
190219

191220
return {

0 commit comments

Comments
 (0)