UNPKG

@hpx7/delta-pack

Version:

A TypeScript code generator and runtime for binary serialization based on schemas.

104 lines (103 loc) 3.23 kB
export function rleEncode(bits) { let last = bits[0]; let count = 1; const rleBits = [last]; for (let i = 1; i <= bits.length; i++) { if (i < bits.length && bits[i] === last) { count++; } else { // Variable-length unary coding for run lengths if (count === 1) { rleBits.push(false); } else if (count <= 3) { rleBits.push(true, false); rleBits.push(...uintToBits(count - 2, 1)); // 0-1 for values 2-3 } else if (count <= 5) { rleBits.push(true, true, false); rleBits.push(...uintToBits(count - 4, 1)); // 0-1 for values 4-5 } else if (count <= 13) { rleBits.push(true, true, true, false); rleBits.push(...uintToBits(count - 6, 3)); // 0-7 for values 6-13 } else if (count <= 269) { rleBits.push(true, true, true, true); rleBits.push(...uintToBits(count - 14, 8)); // 0-255 for values 14-269 } else { throw new Error("RLE count too large: " + count); } last = bits[i]; count = 1; } } return rleBits; } export function rleDecode(rleBits) { const bits = []; let idx = 0; let last = rleBits[idx++]; while (idx < rleBits.length) { // Variable-length unary decoding if (!rleBits[idx++]) { // '0' = run of 1 bits.push(last); } else if (!rleBits[idx++]) { // '10' + 1 bit = run of 2-3 const count = bitsToUint([rleBits[idx++]]) + 2; for (let i = 0; i < count; i++) { bits.push(last); } } else if (!rleBits[idx++]) { // '110' + 1 bit = run of 4-5 const count = bitsToUint([rleBits[idx++]]) + 4; for (let i = 0; i < count; i++) { bits.push(last); } } else if (!rleBits[idx++]) { // '1110' + 3 bits = run of 6-13 const count = bitsToUint([rleBits[idx++], rleBits[idx++], rleBits[idx++]]) + 6; for (let i = 0; i < count; i++) { bits.push(last); } } else { // '1111' + 8 bits = run of 14-269 const count = bitsToUint([ rleBits[idx++], rleBits[idx++], rleBits[idx++], rleBits[idx++], rleBits[idx++], rleBits[idx++], rleBits[idx++], rleBits[idx++], ]) + 14; for (let i = 0; i < count; i++) { bits.push(last); } } last = !last; } return bits; } function uintToBits(val, numBits) { const bits = []; for (let i = 0; i < numBits; i++) { bits.push((val & (1 << (numBits - 1 - i))) > 0); } return bits; } function bitsToUint(bits) { let val = 0; for (let i = 0; i < bits.length; i++) { val |= (bits[i] ? 1 : 0) << (bits.length - 1 - i); } return val; }