Skip to content

Commit

Permalink
🎉 now outperforms JSON on size *and* speed!
Browse files Browse the repository at this point in the history
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
  • Loading branch information
wmertens committed Apr 2, 2017
1 parent 5986de0 commit 745f054
Showing 1 changed file with 48 additions and 30 deletions.
78 changes: 48 additions & 30 deletions lib/jsurl2.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,7 @@
var out, k, t
var c = peek(a)
if (!c) {return EOS}
if (c === '~') {
eatOne(a)
out = true
} else if (c === '(') {
if (c === '(') {
eatOne(a)
out = {}
while (c = peek(a), c && c !== ')') {
Expand Down Expand Up @@ -130,6 +127,9 @@
} else if (c === '*') {
eatOne(a)
out = unescape(eat(a))
} else if (c === '~') {
eatOne(a)
out = true
} else if (numRE.test(c)) {
out = Number(eat(a))
} else if (stringRE.test(c)) {
Expand All @@ -141,64 +141,82 @@
}

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

if (T === 'number') {
out = isFinite(v) ? v : NULL
out.push(isFinite(v) ? v.toString() : NULL)
} else if (T === 'boolean') {
out = v ? '' : FALSE
out.push(v ? '' : FALSE)
} else if (T === 'string') {
t = escape(v)
if (stringRE.test(t)) {
out = t
out.push(t)
} else {
out = '*' + t
out.push('*' + t)
}
} else if (T === 'object') {
if (!v) {
out = NULL
out.push(NULL)
} else if (v instanceof Date) {
out = '_D' + v.toJSON().replace('T00:00:00.000Z', '')
out.push('_D' + v.toJSON().replace('T00:00:00.000Z', ''))
} else if (Array.isArray(v)) {
a = []
out.push('!')
for (var i = 0; i < v.length; i++) {
t = v[i]
// Special case: only use full -T~ in arrays
a[i] = t === true ? TRUEt : encode(t)
if (t === true) {
out.push(TRUE)
} else {
encode(t, out)
}
}

out = '!' + a.join('')
out.push('')
} else {
a = []
out.push('(')
for (var key in v) {
if (v.hasOwnProperty(key)) {
t = v[key]
if (t !== undefined && typeof t !== 'function') {
val = encode(t)
a.push(escape(key) + '~', val)
out.push(escape(key))
encode(t, out)
}
}
}
t = a.join('').replace(endTildesRE, '')

return '(' + t + ')'
while(out[out.length - 1] === '') {
out.pop()
}
out.push(')')
}
} else {
// function, undefined
out = UNDEF
out.push(UNDEF)
}
return out + '~'
}

var allTerminatorsRE = /\)*~*$/
const closeObjRE = /\)+$/g
const noTilde = {'!': true, '(': true, ')': true}
exports.stringify = function (v, options) {
var r = encode(v)
if (options && options.short) {
return r.replace(allTerminatorsRE, '')
var out = [], t, str = '', len, sep = false, short = options && options.short
encode(v, out)
len = out.length - 1
// until where we have to stringify
while(t = out[len], t === '' || (short && t === ')')) {
len--
}
// extended join('~')
for (var i = 0; i <= len; i++) {
t = out[i]
if (sep && t !== ')') {
str += '~'
}
str += t
sep = !(t === '!' || t === '(' || t === ')')
}
if (!short) {
str += '~'
}
return r.replace(endTildesRE, '~')
return str
}

exports.parse = function (s, options) {
Expand Down

0 comments on commit 745f054

Please sign in to comment.