@@ -51,20 +51,16 @@ local function escape_char(c)
51
51
end
52
52
53
53
54
- local function encode_nil (val )
55
- return " null"
54
+ local function encode_nil (rope )
55
+ rope [ # rope + 1 ] = " null"
56
56
end
57
57
58
58
59
- local function encode_table (val , stack )
60
- local res = {}
61
- stack = stack or {}
62
-
59
+ local function encode_table (rope , val , stack )
63
60
-- Circular reference?
64
61
if stack [val ] then error (" circular reference" ) end
65
62
66
63
stack [val ] = true
67
-
68
64
if rawget (val , 1 ) ~= nil or next (val ) == nil then
69
65
-- Treat as array -- check keys are valid and it is not sparse
70
66
local n = 0
@@ -78,61 +74,80 @@ local function encode_table(val, stack)
78
74
error (" invalid table: sparse array" )
79
75
end
80
76
-- Encode
77
+ rope [# rope + 1 ] = " ["
81
78
for i , v in ipairs (val ) do
82
- table.insert (res , encode (v , stack ))
79
+ if i > 1 then
80
+ rope [# rope + 1 ] = " ,"
81
+ end
82
+ encode (rope , v , stack )
83
83
end
84
- stack [val ] = nil
85
- return " [" .. table.concat (res , " ," ) .. " ]"
86
-
84
+ rope [# rope + 1 ] = " ]"
87
85
else
88
86
-- Treat as an object
87
+ rope [# rope + 1 ] = " {"
88
+ local first = true
89
89
for k , v in pairs (val ) do
90
90
if type (k ) ~= " string" then
91
91
error (" invalid table: mixed or invalid key types" )
92
92
end
93
- table.insert (res , encode (k , stack ) .. " :" .. encode (v , stack ))
93
+ if not first then
94
+ rope [# rope + 1 ] = " ,"
95
+ end
96
+ encode (rope , k , stack )
97
+ rope [# rope + 1 ] = " :"
98
+ encode (rope , v , stack )
99
+ first = false
94
100
end
95
- stack [val ] = nil
96
- return " {" .. table.concat (res , " ," ) .. " }"
101
+ rope [# rope + 1 ] = " }"
97
102
end
103
+ stack [val ] = nil
98
104
end
99
105
100
106
101
- local function encode_string (val )
102
- return ' "' .. val :gsub (' [%z\1 -\31 \\ "]' , escape_char ) .. ' "'
107
+ local function encode_string (rope , val )
108
+ rope [# rope + 1 ] = ' "'
109
+ rope [# rope + 1 ] = val :gsub (' [%z\1 -\31 \\ "]' , escape_char )
110
+ rope [# rope + 1 ] = ' "'
103
111
end
104
112
105
113
106
- local function encode_number (val )
114
+ local function encode_number (rope , val )
107
115
-- Check for NaN, -inf and inf
108
116
if val ~= val or val <= - math.huge or val >= math.huge then
109
117
error (" unexpected number value '" .. tostring (val ) .. " '" )
110
118
end
111
- return string.format (" %.14g" , val )
119
+ -- See www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF
120
+ -- 17 digits suffice to losslessly represent 64-bit IEEE754 floats
121
+ rope [# rope + 1 ] = (" %.17g" ):format (val )
112
122
end
113
123
124
+ local function encode_boolean (rope , val )
125
+ rope [# rope + 1 ] = val and " true" or " false"
126
+ end
114
127
115
128
local type_func_map = {
116
129
[ " nil" ] = encode_nil ,
117
130
[ " table" ] = encode_table ,
118
131
[ " string" ] = encode_string ,
119
132
[ " number" ] = encode_number ,
120
- [ " boolean" ] = tostring ,
133
+ [ " boolean" ] = encode_boolean ,
121
134
}
122
135
123
136
124
- encode = function ( val , stack )
137
+ function encode ( rope , val , stack )
125
138
local t = type (val )
126
- local f = type_func_map [t ]
127
- if f then
128
- return f ( val , stack )
139
+ local encoder = type_func_map [t ]
140
+ if encoder then
141
+ return encoder ( rope , val , stack )
129
142
end
130
143
error (" unexpected type '" .. t .. " '" )
131
144
end
132
145
133
146
134
147
function json .encode (val )
135
- return ( encode (val ) )
148
+ local rope = {}
149
+ encode (rope , val , {})
150
+ return table.concat (rope )
136
151
end
137
152
138
153
0 commit comments