UNPKG

joyson2

Version:

JOYFUL JSON | A smarter approach to serialize more than JSON, faster than ever!

131 lines (112 loc) 3.84 kB
class SnappyLiteTypedCompressor { constructor(arrayType) { this.arrayType = arrayType; this.bytesPerElement = arrayType.BYTES_PER_ELEMENT; this.bitMask = (1 << (this.bytesPerElement * 8)) - 1; } deltaEncode(data) { let out = new this.arrayType(data.length); out[0] = data[0]; for (let i = 1; i < data.length; i++) { out[i] = (data[i] - data[i - 1]) & this.bitMask; } return out; } deltaDecode(delta) { let out = new this.arrayType(delta.length); out[0] = delta[0]; for (let i = 1; i < delta.length; i++) { out[i] = (out[i - 1] + delta[i]) & this.bitMask; } return out; } compress(data) { const delta = this.deltaEncode(data); const view = new DataView(delta.buffer); const output = []; let i = 0; while (i < delta.length) { const start = i; const val = delta[i]; let run = 1; // Check for repeat run while (i + run < delta.length && delta[i + run] === val && run < 255) run++; if (run >= 4) { output.push(0b01000000); // repeat tag this._writeValue(output, val); output.push(run); i += run; continue; } // Check for zero run if (val === 0) { run = 1; while (i + run < delta.length && delta[i + run] === 0 && run < 255) run++; if (run >= 4) { output.push(0b10000000); // zero tag output.push(run); i += run; continue; } } // Otherwise, literal let litStart = i; let litRun = 1; while ( litStart + litRun < delta.length && (delta[litStart + litRun] !== delta[litStart + litRun - 1] || litRun < 4) && litRun < 60 ) litRun++; output.push(0b00000000 | litRun); for (let j = 0; j < litRun; j++) { this._writeValue(output, delta[i + j]); } i += litRun; } return new Uint8Array(output); } decompress(compressed) { const data = []; const bytes = compressed; let i = 0; while (i < bytes.length) { const tag = bytes[i++]; const type = tag >> 6; if (type === 0) { // Literal const length = tag & 0x3F; for (let j = 0; j < length; j++) { data.push(this._readValue(bytes, i)); i += this.bytesPerElement; } } else if (type === 1) { // Repeat const value = this._readValue(bytes, i); i += this.bytesPerElement; const count = bytes[i++]; for (let j = 0; j < count; j++) data.push(value); } else if (type === 2) { // Zero run const count = bytes[i++]; for (let j = 0; j < count; j++) data.push(0); } else { throw new Error("Unknown control type"); } } return this.deltaDecode(new this.arrayType(data)); } _writeValue(out, val) { for (let b = 0; b < this.bytesPerElement; b++) { out.push((val >> (8 * b)) & 0xFF); } } _readValue(bytes, index) { let val = 0; for (let b = 0; b < this.bytesPerElement; b++) { val |= bytes[index + b] << (8 * b); } return val; } } var engine = new SnappyLiteTypedCompressor(); export default engine;