Skip to content

Commit 745f054

Browse files
committed
🎉 now outperforms JSON on size *and* speed!
rewrote stringifier to keep intermediate results in array and replaced join('~') with smart join performance.html:15 JSON: 200000 parsed in 731ms, 0.003655ms/item performance.html:23 JSON: 200000 stringified in 448ms, 0.00224ms/item performance.html:32 v1: 200000 parsed in 1337ms, 0.006685ms/item performance.html:40 v1: 200000 stringified in 934ms, 0.00467ms/item performance.html:49 v2: 200000 parsed in 601ms, 0.003005ms/item performance.html:57 v2: 200000 stringified in 403ms, 0.002015ms/item
1 parent 5986de0 commit 745f054

File tree

1 file changed

+48
-30
lines changed

1 file changed

+48
-30
lines changed

lib/jsurl2.js

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,7 @@
8989
var out, k, t
9090
var c = peek(a)
9191
if (!c) {return EOS}
92-
if (c === '~') {
93-
eatOne(a)
94-
out = true
95-
} else if (c === '(') {
92+
if (c === '(') {
9693
eatOne(a)
9794
out = {}
9895
while (c = peek(a), c && c !== ')') {
@@ -130,6 +127,9 @@
130127
} else if (c === '*') {
131128
eatOne(a)
132129
out = unescape(eat(a))
130+
} else if (c === '~') {
131+
eatOne(a)
132+
out = true
133133
} else if (numRE.test(c)) {
134134
out = Number(eat(a))
135135
} else if (stringRE.test(c)) {
@@ -141,64 +141,82 @@
141141
}
142142

143143
var endTildesRE = /~*$/
144-
var TRUEt = TRUE + '~'
145-
function encode (v) {
146-
var t, a, out, T = typeof v, val
144+
function encode (v, out) {
145+
var t, a, T = typeof v, val, prefix
147146

148147
if (T === 'number') {
149-
out = isFinite(v) ? v : NULL
148+
out.push(isFinite(v) ? v.toString() : NULL)
150149
} else if (T === 'boolean') {
151-
out = v ? '' : FALSE
150+
out.push(v ? '' : FALSE)
152151
} else if (T === 'string') {
153152
t = escape(v)
154153
if (stringRE.test(t)) {
155-
out = t
154+
out.push(t)
156155
} else {
157-
out = '*' + t
156+
out.push('*' + t)
158157
}
159158
} else if (T === 'object') {
160159
if (!v) {
161-
out = NULL
160+
out.push(NULL)
162161
} else if (v instanceof Date) {
163-
out = '_D' + v.toJSON().replace('T00:00:00.000Z', '')
162+
out.push('_D' + v.toJSON().replace('T00:00:00.000Z', ''))
164163
} else if (Array.isArray(v)) {
165-
a = []
164+
out.push('!')
166165
for (var i = 0; i < v.length; i++) {
167166
t = v[i]
168167
// Special case: only use full -T~ in arrays
169-
a[i] = t === true ? TRUEt : encode(t)
168+
if (t === true) {
169+
out.push(TRUE)
170+
} else {
171+
encode(t, out)
172+
}
170173
}
171-
172-
out = '!' + a.join('')
174+
out.push('')
173175
} else {
174-
a = []
176+
out.push('(')
175177
for (var key in v) {
176178
if (v.hasOwnProperty(key)) {
177179
t = v[key]
178180
if (t !== undefined && typeof t !== 'function') {
179-
val = encode(t)
180-
a.push(escape(key) + '~', val)
181+
out.push(escape(key))
182+
encode(t, out)
181183
}
182184
}
183185
}
184-
t = a.join('').replace(endTildesRE, '')
185-
186-
return '(' + t + ')'
186+
while(out[out.length - 1] === '') {
187+
out.pop()
188+
}
189+
out.push(')')
187190
}
188191
} else {
189192
// function, undefined
190-
out = UNDEF
193+
out.push(UNDEF)
191194
}
192-
return out + '~'
193195
}
194196

195-
var allTerminatorsRE = /\)*~*$/
197+
const closeObjRE = /\)+$/g
198+
const noTilde = {'!': true, '(': true, ')': true}
196199
exports.stringify = function (v, options) {
197-
var r = encode(v)
198-
if (options && options.short) {
199-
return r.replace(allTerminatorsRE, '')
200+
var out = [], t, str = '', len, sep = false, short = options && options.short
201+
encode(v, out)
202+
len = out.length - 1
203+
// until where we have to stringify
204+
while(t = out[len], t === '' || (short && t === ')')) {
205+
len--
206+
}
207+
// extended join('~')
208+
for (var i = 0; i <= len; i++) {
209+
t = out[i]
210+
if (sep && t !== ')') {
211+
str += '~'
212+
}
213+
str += t
214+
sep = !(t === '!' || t === '(' || t === ')')
215+
}
216+
if (!short) {
217+
str += '~'
200218
}
201-
return r.replace(endTildesRE, '~')
219+
return str
202220
}
203221

204222
exports.parse = function (s, options) {

0 commit comments

Comments
 (0)