Rewritten utils unterfaces & internals

This commit is contained in:
Vitaly Puzrin 2014-03-13 10:45:14 +04:00
parent ccf2586dba
commit 7b2e5da8a9
9 changed files with 89 additions and 128 deletions

View file

@ -4,9 +4,9 @@ var pako = require('../../../');
var utils = require('../../../lib/zlib/utils'); var utils = require('../../../lib/zlib/utils');
exports.run = function(data, level) { exports.run = function(data, level) {
utils.forceUntyped = true; utils.setTyped(false);
pako.deflate(data.typed, { pako.deflate(data.typed, {
level: level level: level
}); });
utils.forceUntyped = false; utils.setTyped(true);
} }

View file

@ -4,8 +4,8 @@ var pako = require('../../../');
var utils = require('../../../lib/zlib/utils'); var utils = require('../../../lib/zlib/utils');
exports.run = function(data, level) { exports.run = function(data, level) {
utils.forceUntyped = true; utils.setTyped(false);
pako.inflate(data.deflateTyped, { pako.inflate(data.deflateTyped, {
}); });
utils.forceUntyped = false; utils.setTyped(true);
} }

View file

@ -25,14 +25,6 @@ var Z_DEFLATED = 8;
/* ===========================================================================*/ /* ===========================================================================*/
// return sliced buffer, trying to avoid new objects creation and mem copy
function sliceBuf(buf, size) {
if (buf.length === size) { return buf; }
if (utils.typedOk()) { return buf.subarray(0, size); }
buf.length = size;
return buf;
}
/** /**
* class Deflate * class Deflate
* *
@ -190,7 +182,7 @@ Deflate.prototype.push = function(data, mode) {
strm.next_in = data; strm.next_in = data;
strm.next_in_index = 0; strm.next_in_index = 0;
strm.avail_in = strm.next_in.length; strm.avail_in = strm.next_in.length;
strm.next_out = utils.arrayCreate(chunkSize); strm.next_out = new utils.Buf8(chunkSize);
do { do {
strm.avail_out = this.options.chunkSize; strm.avail_out = this.options.chunkSize;
@ -203,10 +195,10 @@ Deflate.prototype.push = function(data, mode) {
return false; return false;
} }
if(strm.next_out_index) { if(strm.next_out_index) {
this.onData(sliceBuf(strm.next_out, strm.next_out_index)); this.onData(utils.shrinkBuf(strm.next_out, strm.next_out_index));
// Allocate buffer for next chunk, if not last // Allocate buffer for next chunk, if not last
if (strm.avail_in > 0 || strm.avail_out === 0) { if (strm.avail_in > 0 || strm.avail_out === 0) {
strm.next_out = utils.arrayCreate(this.options.chunkSize); strm.next_out = new utils.Buf8(this.options.chunkSize);
} }
} }
} while (strm.avail_in > 0 || strm.avail_out === 0); } while (strm.avail_in > 0 || strm.avail_out === 0);

View file

@ -7,13 +7,6 @@ var c = require('./zlib/constants');
var msg = require('./zlib/messages'); var msg = require('./zlib/messages');
var zstream = require('./zlib/zstream'); var zstream = require('./zlib/zstream');
// return sliced buffer, trying to avoid new objects creation and mem copy
function sliceBuf(buf, size) {
if (buf.length === size) { return buf; }
if (utils.typedOk()) { return buf.subarray(0, size); }
buf.length = size;
return buf;
}
/** /**
* class Inflate * class Inflate
@ -162,7 +155,7 @@ Inflate.prototype.push = function(data, mode) {
strm.next_in = data; strm.next_in = data;
strm.next_in_index = 0; strm.next_in_index = 0;
strm.avail_in = strm.next_in.length; strm.avail_in = strm.next_in.length;
strm.next_out = utils.arrayCreate(chunkSize); strm.next_out = new utils.Buf8(chunkSize);
do { do {
strm.avail_out = this.options.chunkSize; strm.avail_out = this.options.chunkSize;
@ -175,10 +168,10 @@ Inflate.prototype.push = function(data, mode) {
return false; return false;
} }
if(strm.next_out_index) { if(strm.next_out_index) {
this.onData(sliceBuf(strm.next_out, strm.next_out_index)); this.onData(utils.shrinkBuf(strm.next_out, strm.next_out_index));
// Allocate buffer for next chunk, if not last // Allocate buffer for next chunk, if not last
if (strm.avail_in > 0 || strm.avail_out === 0) { if (strm.avail_in > 0 || strm.avail_out === 0) {
strm.next_out = utils.arrayCreate(this.options.chunkSize); strm.next_out = new utils.Buf8(this.options.chunkSize);
} }
} }
} while (strm.avail_in > 0 || strm.avail_out === 0); } while (strm.avail_in > 0 || strm.avail_out === 0);

View file

@ -1167,9 +1167,9 @@ function DeflateState() {
// Use flat array of DOUBLE size, with interleaved fata, // Use flat array of DOUBLE size, with interleaved fata,
// because JS does not support effective // because JS does not support effective
this.dyn_ltree = utils.array16Create(HEAP_SIZE * 2); this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2);
this.dyn_dtree = utils.array16Create((2*D_CODES+1) * 2); this.dyn_dtree = new utils.Buf16((2*D_CODES+1) * 2);
this.bl_tree = utils.array16Create((2*BL_CODES+1) * 2); this.bl_tree = new utils.Buf16((2*BL_CODES+1) * 2);
zero(this.dyn_ltree); zero(this.dyn_ltree);
zero(this.dyn_dtree); zero(this.dyn_dtree);
zero(this.bl_tree); zero(this.bl_tree);
@ -1186,11 +1186,11 @@ function DeflateState() {
this.bl_desc = null; /* desc. for bit length tree */ this.bl_desc = null; /* desc. for bit length tree */
//ush bl_count[MAX_BITS+1]; //ush bl_count[MAX_BITS+1];
this.bl_count = utils.array16Create(MAX_BITS+1); this.bl_count = new utils.Buf16(MAX_BITS+1);
/* number of codes at each bit length for an optimal tree */ /* number of codes at each bit length for an optimal tree */
//int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
this.heap = utils.array16Create(2*L_CODES+1); /* heap used to build the Huffman trees */ this.heap = new utils.Buf16(2*L_CODES+1); /* heap used to build the Huffman trees */
zero(this.heap); zero(this.heap);
this.heap_len = 0; /* number of elements in the heap */ this.heap_len = 0; /* number of elements in the heap */
@ -1199,7 +1199,7 @@ function DeflateState() {
* The same heap array is used to build all trees. * The same heap array is used to build all trees.
*/ */
this.depth = utils.array16Create(2*L_CODES+1); //uch depth[2*L_CODES+1]; this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1];
zero(this.depth); zero(this.depth);
/* Depth of each subtree used as tie breaker for trees of equal frequency /* Depth of each subtree used as tie breaker for trees of equal frequency
*/ */
@ -1342,16 +1342,16 @@ function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
s.hash_mask = s.hash_size - 1; s.hash_mask = s.hash_size - 1;
s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
s.window = utils.arrayCreate(s.w_size * 2); s.window = new utils.Buf8(s.w_size * 2);
s.head = utils.array16Create(s.hash_size); s.head = new utils.Buf16(s.hash_size);
s.prev = utils.array16Create(s.w_size); s.prev = new utils.Buf16(s.w_size);
s.high_water = 0; /* nothing written to s->window yet */ s.high_water = 0; /* nothing written to s->window yet */
s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
s.pending_buf_size = s.lit_bufsize * 4; s.pending_buf_size = s.lit_bufsize * 4;
s.pending_buf = utils.arrayCreate(s.pending_buf_size); s.pending_buf = new utils.Buf8(s.pending_buf_size);
s.d_buf = s.lit_bufsize >> 1; s.d_buf = s.lit_bufsize >> 1;
s.l_buf = (1 + 2) * s.lit_bufsize; s.l_buf = (1 + 2) * s.lit_bufsize;

View file

@ -146,11 +146,11 @@ function InflateState() {
//unsigned short array //unsigned short array
//todo: test later with Uint16Array //todo: test later with Uint16Array
this.lens = utils.array16Create(320); /* temporary storage for code lengths */ this.lens = new utils.Buf16(320); /* temporary storage for code lengths */
this.work = utils.array16Create(280); /* work area for code table building */ this.work = new utils.Buf16(280); /* work area for code table building */
// TODO: 8 or 16 bits? // TODO: 8 or 16 bits?
this.codes = utils.array32Create(ENOUGH); /* space for code tables */ this.codes = new utils.Buf32(ENOUGH); /* space for code tables */
this.sane = 0; /* if false, allow invalid distance too far */ this.sane = 0; /* if false, allow invalid distance too far */
this.back = 0; /* bits back of last unprocessed length/lit */ this.back = 0; /* bits back of last unprocessed length/lit */
this.was = 0; /* initial length of match */ this.was = 0; /* initial length of match */
@ -188,8 +188,8 @@ function inflateResetKeep(strm) {
//state.lencode = state.distcode = state.next = state.codes; //state.lencode = state.distcode = state.next = state.codes;
//utils.arraySet(state.lencode,state.codes,0,state.codes.length,0); //utils.arraySet(state.lencode,state.codes,0,state.codes.length,0);
//utils.arraySet(state.distcode,state.codes,0,state.codes.length,0); //utils.arraySet(state.distcode,state.codes,0,state.codes.length,0);
state.lencode = utils.array32Create(ENOUGH); state.lencode = new utils.Buf32(ENOUGH);
state.distcode = utils.array32Create(ENOUGH); state.distcode = new utils.Buf32(ENOUGH);
state.sane = 1; state.sane = 1;
state.back = -1; state.back = -1;
@ -305,8 +305,8 @@ function fixedtables(state) {
if (virgin) { if (virgin) {
var sym, bits; var sym, bits;
lenfix = utils.array32Create(512); lenfix = new utils.Buf32(512);
distfix = utils.array32Create(32); distfix = new utils.Buf32(32);
/* literal/length table */ /* literal/length table */
sym = 0; sym = 0;
@ -360,7 +360,7 @@ function updatewindow(strm, src, end, copy) {
state.wnext = 0; state.wnext = 0;
state.whave = 0; state.whave = 0;
state.window = utils.arrayCreate(state.wsize); state.window = new utils.Buf8(state.wsize);
} }
/* copy state->wsize or less output bytes into the circular window */ /* copy state->wsize or less output bytes into the circular window */
@ -410,7 +410,7 @@ function inflate(strm, flush) {
var last_bits, last_op, last_val; // paked "last" denormalized var last_bits, last_op, last_val; // paked "last" denormalized
var len; /* length to copy for repeats, bits to drop */ var len; /* length to copy for repeats, bits to drop */
var ret; /* return code */ var ret; /* return code */
var hbuf = utils.arrayCreate(4); /* buffer for gzip header crc calculation */ var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */
var opts; var opts;
var n; // temporary var for NEED_BITS var n; // temporary var for NEED_BITS

View file

@ -62,8 +62,8 @@ module.exports = function inflate_table(opts)
var base_index = 0; var base_index = 0;
// var shoextra; /* extra bits table to use */ // var shoextra; /* extra bits table to use */
var end; /* use base and extra for symbol > end */ var end; /* use base and extra for symbol > end */
var count = utils.array16Create(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */ var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */
var offs = utils.array16Create(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */ var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */
var extra = null; var extra = null;
var extra_index = 0; var extra_index = 0;

View file

@ -3,18 +3,7 @@
var TYPED_OK = (typeof Uint8Array !== 'undefined') && var TYPED_OK = (typeof Uint8Array !== 'undefined') &&
(typeof Uint16Array !== 'undefined') && (typeof Uint16Array !== 'undefined') &&
(typeof Uint32Array !== 'undefined'); (typeof Int32Array !== 'undefined');
var isArray = Array.isArray || function (obj) { return Object.prototype.toString.call(obj) === '[object Array]'; };
// For debug/testing. Set true to force use untyped arrays
exports.forceUntyped = false;
function typedOk() {
return TYPED_OK && !exports.forceUntyped;
}
exports.typedOk = typedOk;
exports.assign = function (obj /*from1, from2, from3, ...*/) { exports.assign = function (obj /*from1, from2, from3, ...*/) {
@ -38,73 +27,32 @@ exports.assign = function (obj /*from1, from2, from3, ...*/) {
}; };
exports.arraySet = function (dest, src, src_offs, len, dest_offs) { // reduce buffer size, avoiding mem copy
exports.shrinkBuf = function (buf, size) {
// Suppose, that with typed array support destination is if (buf.length === size) { return buf; }
// always typed - don't check it if (buf.subarray) { return buf.subarray(0, size); }
if (typedOk() && (!isArray(src))) { buf.length = size;
return buf;
// optimize full copy
//if ((src_offs === 0) && (src.length === len)) {
// dest.set(src, dest_offs);
// return;
//}
dest.set(src.subarray(src_offs, src_offs+len), dest_offs);
return;
}
// Fallback to ordinary array
for(var i=0; i<len; i++) {
dest[dest_offs + i] = src[src_offs + i];
}
}; };
exports.arrayCreate = function (length) { var fnTyped = {
if (typedOk()) { arraySet: function (dest, src, src_offs, len, dest_offs) {
return new Uint8Array(length); // Suppose, that with typed array support destination is
} // always typed - don't check it
// Fallback to ordinary array if (src.subarray) {
return new Array(length); dest.set(src.subarray(src_offs, src_offs+len), dest_offs);
}; return;
}
// Fallback to ordinary array
for(var i=0; i<len; i++) {
dest[dest_offs + i] = src[src_offs + i];
}
},
// Join array of chunks to single array.
flattenChunks: function(chunks) {
var i, l, len, pos, chunk, result;
exports.array16Create = function (length) {
if (typedOk()) {
return new Uint16Array(length);
}
// Fallback to ordinary array
return new Array(length);
};
exports.array16Create = function (length) {
if (typedOk()) {
return new Uint16Array(length);
}
// Fallback to ordinary array
return new Array(length);
};
// (!) use signed ints for 32 bits, to avoid boxing
exports.array32Create = function (length) {
if (typedOk()) {
return new Int32Array(length);
}
// Fallback to ordinary array
return new Array(length);
};
// Join array of chunks to single array.
// Expect Array of (Array(Bytes) || Uint8Array).
//
exports.flattenChunks = function(chunks) {
var i, l, len, pos, chunk, result;
if (typedOk()) {
// calculate data length // calculate data length
len = 0; len = 0;
for (i=0, l=chunks.length; i<l; i++) { for (i=0, l=chunks.length; i<l; i++) {
@ -122,7 +70,35 @@ exports.flattenChunks = function(chunks) {
return result; return result;
} }
// Fallback for untyped arrays
return [].concat.apply([], chunks);
}; };
var fnUntyped = {
arraySet: function (dest, src, src_offs, len, dest_offs) {
for(var i=0; i<len; i++) {
dest[dest_offs + i] = src[src_offs + i];
}
},
// Join array of chunks to single array.
flattenChunks: function(chunks) {
return [].concat.apply([], chunks);
}
};
// Enable/Disable typed arrays use, for testing
//
exports.setTyped = function (on) {
if (on) {
exports.Buf8 = Uint8Array;
exports.Buf16 = Uint16Array;
exports.Buf32 = Int32Array;
exports.assign(exports, fnTyped);
} else {
exports.Buf8 = Array;
exports.Buf16 = Array;
exports.Buf32 = Array;
exports.assign(exports, fnUntyped);
}
};
exports.setTyped(TYPED_OK);

View file

@ -101,7 +101,7 @@ function testDeflate(zlib_factory, pako_deflate, samples, options, callback) {
_.forEach(samples, function(data, name) { _.forEach(samples, function(data, name) {
// with untyped arrays // with untyped arrays
queue.push(function (done) { queue.push(function (done) {
pako_utils.forceUntyped = true; pako_utils.setTyped(false);
testDeflateSingle(zlib_factory, pako_deflate, data, options, function (err) { testDeflateSingle(zlib_factory, pako_deflate, data, options, function (err) {
if (err) { if (err) {
@ -114,7 +114,7 @@ function testDeflate(zlib_factory, pako_deflate, samples, options, callback) {
// with typed arrays // with typed arrays
queue.push(function (done) { queue.push(function (done) {
pako_utils.forceUntyped = false; pako_utils.setTyped(true);
testDeflateSingle(zlib_factory, pako_deflate, data, options, function (err) { testDeflateSingle(zlib_factory, pako_deflate, data, options, function (err) {
if (err) { if (err) {
@ -145,9 +145,9 @@ function testInflate(samples, options, callback) {
deflated = pako.deflate(data, options); deflated = pako.deflate(data, options);
// with untyped arrays // with untyped arrays
pako_utils.forceUntyped = true; pako_utils.setTyped(false);
inflated = pako.inflate(deflated, inflate_options); inflated = pako.inflate(deflated, inflate_options);
pako_utils.forceUntyped = false; pako_utils.setTyped(true);
if (!cmpBuf(inflated, data)) { if (!cmpBuf(inflated, data)) {
callback('Error in "' + name + '" - inflate result != original'); callback('Error in "' + name + '" - inflate result != original');