diff --git a/README.md b/README.md index 609050f5..97858699 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,34 @@ -[MessagePack](http://msgpack.org/) -================================== +[MessagePack](http://msgpack.org/) with key extension +===================================================== Space-efficient binary serialization format. +This includes an extension to remove xtra space for duplicate keys: + + + + + +
format namefirst byte (in binary)first byte (in hex)
fixext 1110101000xd4
fixext 2110101010xd5
+ +where: + + Y: 1-512 unit id of a map space + key: the string to save in that map space + +--------+--------+========+ + | 0xd4 |YYYYYYYY| key | + +--------+--------+========+ + + Z: lookup the previously assigned key + +--------+--------+ + | 0xd5 |ZZZZZZZZ| + +--------+--------+ + +this allows reused keys (i.e. for object serialization) to use up much less space. + +I.e. if you have a list of objects like {id:1,name:"test"} you will save 4 bytes per iteration (one from id, and 3 from name) + + Quick start =========== diff --git a/msgpack.js b/msgpack.js index 7d09c846..ed9b3196 100644 --- a/msgpack.js +++ b/msgpack.js @@ -39,7 +39,7 @@ self.importScripts && (onmessage = function(event) { // msgpack.pack function msgpackpack(data) { // @param Mix: // @return ArrayBuffer: - return new Uint8Array( encode( [], data, { i: -1, d: msgpack.MAX_DEPTH } ) ).buffer; + return new Uint8Array( encode( [], data, { i: -1, d: msgpack.MAX_DEPTH, k: {}, l: 1 } ) ).buffer; } // msgpack.unpack @@ -50,7 +50,26 @@ function msgpackunpack(data) { // @param ArrayBuffer: } else if ( !(data instanceof Uint8Array) ) { throw new SyntaxError("ArrayBuffer or Uint8Array expected"); } - return decode( data, { i: -1, d: msgpack.MAX_DEPTH } ); // mix or undefined + return decode( data, { i: -1, d: msgpack.MAX_DEPTH, k: {} } ); // mix or undefined +} + +// key encoding: 0xd4+id+string +// 0xd5+id +function encodeKey(rv, // @param ByteArray: result + mix, // @param Mix: source data (string in that case) + ctx) { // @param Object: context + var id = ctx.k[mix]; + if(id) { + rv.push(0xd5, id); + } else if(ctx.l < 512) { + id = ctx.l++; // next id + ctx.k[mix] = id; // lookup + rv.push(0xd4, id); // field + 0 + id + encode(rv, mix, ctx); // name + } else { + // just encode + encode(rv, mix, ctx); // name + } } // inner - encoder @@ -344,6 +363,12 @@ function decode(buf, // @param source buffer hash[decode(buf, ctx)] = decode(buf, ctx); } return hash; + case 0xd4: num += buf[++ctx.i]; + str = decode(buf, ctx); + ctx.k[num] = str; + return str; + case 0xd5: num += buf[++ctx.i]; + return ctx.k[num]; // 0xdd: array32, 0xdc: array16, 0x90: array case 0xdd: num += buf[++ctx.i] * 0x1000000 + (buf[++ctx.i] << 16); case 0xdc: num += (buf[++ctx.i] << 8) + buf[++ctx.i];