Skip to content

Commit 264bd02

Browse files
committed
http://d.hatena.ne.jp/uupaa/20101128
Signed-off-by: uupaa <uupaa.js@gmail.com>
1 parent 45de17e commit 264bd02

File tree

2 files changed

+64
-18
lines changed

2 files changed

+64
-18
lines changed

msgpack.js

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*!{id:msgpack.js,ver:1.01,license:"MIT",author:"uupaa.js@gmail.com"}*/
1+
/*!{id:msgpack.js,ver:1.02,license:"MIT",author:"uupaa.js@gmail.com"}*/
22

33
// === msgpack ===
44
// MessagePack -> http://msgpack.sourceforge.net/
@@ -24,7 +24,7 @@ var _ie = /MSIE/.test(navigator.userAgent),
2424
_num2b64 = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
2525
"abcdefghijklmnopqrstuvwxyz0123456789+/").split(""),
2626
_sign = { 8: 0x80, 16: 0x8000, 32: 0x80000000 },
27-
_split8char = /.{8}/g;
27+
_8bits = /[01]{8}/g;
2828

2929
// for WebWorkers Code Block
3030
self.importScripts && (onmessage = function(event) {
@@ -42,10 +42,21 @@ function msgpackpack(data, // @param Mix:
4242
// [1][mix to String] msgpack.pack({}, true) -> "..."
4343
// [2][mix to ByteArray] msgpack.pack({}) -> [...]
4444

45-
var byteArray = encode([], data);
45+
var byteArray = encode([], data), rv, i, iz, num2bin = _num2bin;
4646

47-
return toString ? String.fromCharCode.apply(null, byteArray) // toString
48-
: byteArray;
47+
if (toString) {
48+
// http://d.hatena.ne.jp/uupaa/20101128
49+
try {
50+
return String.fromCharCode.apply(this, byteArray); // toString
51+
} catch(err) {
52+
; // avoid "Maximum call stack size exceeded"
53+
}
54+
for (rv = [], i = 0, iz = byteArray.length; i < iz; ++i) {
55+
rv[i] = num2bin[byteArray[i]];
56+
}
57+
return rv.join("");
58+
}
59+
return byteArray;
4960
}
5061

5162
// msgpack.unpack
@@ -62,7 +73,7 @@ function msgpackunpack(data) { // @param BinaryString/ByteArray:
6273
// inner - encoder
6374
function encode(rv, // @param ByteArray: result
6475
mix) { // @param Mix: source data
65-
var size = 0, i = 0, iz, c, ary, hash,
76+
var size = 0, i = 0, iz, c, hash, pos,
6677
high, low, i64 = 0, sign, exp, frac;
6778

6879
if (mix == null) { // null or undefined
@@ -77,7 +88,7 @@ function encode(rv, // @param ByteArray: result
7788
rv.push(0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); // quiet NaN
7889
} else if (mix === Infinity) {
7990
rv.push(0xcb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); // positive infinity
80-
} else if (Math.floor(mix) === mix) {
91+
} else if (Math.floor(mix) === mix) { // int or uint
8192
if (mix < 0) { // int
8293
if (mix >= -32) { // negative fixnum
8394
rv.push(0xe0 + mix + 32);
@@ -132,30 +143,52 @@ function encode(rv, // @param ByteArray: result
132143
toString(2).slice(1);
133144

134145
// exp is between 1 and 2047. make it 11 bits
135-
exp = ("000000000" + exp.toString(2)).slice(-11);
136-
137-
ary = (+sign + exp + frac).match(_split8char);
146+
// http://d.hatena.ne.jp/uupaa/20101128
147+
if (!sign) {
148+
ary = ((exp + 4096).toString(2).slice(1) + frac).match(_8bits);
149+
} else {
150+
ary = ((exp + 2048).toString(2) + frac).match(_8bits);
151+
}
138152
rv.push(0xcb, hash[ary[0]], hash[ary[1]],
139153
hash[ary[2]], hash[ary[3]],
140154
hash[ary[4]], hash[ary[5]],
141155
hash[ary[6]], hash[ary[7]]);
142156
}
143157
break;
144158
case "string":
159+
// http://d.hatena.ne.jp/uupaa/20101128
160+
iz = mix.length;
161+
pos = rv.length; // keep rewrite position
162+
163+
// set default type [0xa0 + ASCIIString.length]
164+
rv.push(0xa0 + iz);
165+
145166
// utf8.encode
146-
for (ary = [], iz = mix.length, i = 0; i < iz; ++i) {
167+
for (i = 0; i < iz; ++i) {
147168
c = mix.charCodeAt(i);
148169
if (c < 0x80) { // ASCII(0x00 ~ 0x7f)
149-
ary.push(c & 0x7f);
170+
rv.push(c & 0x7f);
150171
} else if (c < 0x0800) {
151-
ary.push(((c >>> 6) & 0x1f) | 0xc0, (c & 0x3f) | 0x80);
172+
rv.push(((c >>> 6) & 0x1f) | 0xc0, (c & 0x3f) | 0x80);
152173
} else if (c < 0x10000) {
153-
ary.push(((c >>> 12) & 0x0f) | 0xe0,
174+
rv.push(((c >>> 12) & 0x0f) | 0xe0,
154175
((c >>> 6) & 0x3f) | 0x80, (c & 0x3f) | 0x80);
155176
}
156177
}
157-
setType(rv, 32, ary.length, [0xa0, 0xda, 0xdb]);
158-
Array.prototype.push.apply(rv, ary);
178+
size = rv.length - pos - 1; // -1 = default type(0xa0 + length)
179+
180+
// rewrite string type.
181+
if (iz !== size) {
182+
// has none ascii string or length >= 32
183+
if (size < 32) {
184+
rv[pos] = 0xa0 + size;
185+
} else if (size < 0x10000) { // 16
186+
rv.splice(pos, 1, 0xda, size >> 8, size & 0xff);
187+
} else if (size < 0x100000000) { // 32
188+
rv.splice(pos, 1, 0xdb, size >>> 24, (size >> 16) & 0xff,
189+
(size >> 8) & 0xff, size & 0xff);
190+
}
191+
}
159192
break;
160193
default: // array or hash
161194
if (Object.prototype.toString.call(mix) === "[object Array]") { // array

test/bench.htm

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,30 @@
2323

2424
function times() {
2525
var perf = +new Date;
26+
var perfPoint;
2627
if (json) {
2728
if (window.JSON) {
2829
encoded = JSON.stringify(mix); // NativeJSON
29-
decoded = JSON.parse(encoded); // NativeJSON
30+
31+
perfPoint = +new Date;
32+
uu.log("JSON.stringify = @ms", perfPoint - perf);
33+
34+
decoded = JSON.parse(encoded);
35+
36+
uu.log("JSON.parse = @ms", (+new Date) - perfPoint);
3037
} else {
3138
encoded = uu.json(mix);
3239
decoded = uu.json.decode(encoded);
3340
}
3441
} else {
3542
encoded = msgpack.pack(mix);
43+
44+
perfPoint = +new Date;
45+
uu.log("msgpack.pack = @ms", perfPoint - perf);
46+
3647
decoded = msgpack.unpack(encoded);
48+
49+
uu.log("msgpack.unpack = @ms", (+new Date) - perfPoint);
3750
}
3851
return (+new Date) - perf;
3952
}
@@ -46,7 +59,7 @@
4659
// rv.shift();
4760

4861
if (json) {
49-
uu.log("json = @ms", rv[0]);
62+
uu.log("JSON = @ms", rv[0]);
5063
} else {
5164
uu.log("msgpack = @ms", rv[0]);
5265
}

0 commit comments

Comments
 (0)