// Fast CRC32 in JavaScript
// 101arrowz (https://github.com/101arrowz)
// License: MIT
// Modified from 101arrowz's gist:
// https://gist.github.com/101arrowz/e58695f7ccfdf74f60ba22018093edea
// This code uses the Slice-by-16 algorithm to achieve performance
// roughly 2x greater than all other JS CRC32 implementations (e.g.
// crc32-js).
// Per local testing, Slice-by-16 outperforms Slice-by-4 by around 50%
// and Slice-by-8/Slice-by-32/Slice-by-64 by 10-30%
// This CRC implementation can compete with WASM CRC implementations
// as well, and it tends to perform between 30% faster and 10% slower
// than WASM CRC32 (>1MB input chunks is faster on WASM).
// CRC32 table
// perf: signed integers are 2x more likely to be Smi
// Smi is a V8 datatype in (-2**30, 2**30-1)
// Smi operations are much faster
function CRC32() {
const crct = new Int32Array(4096);
for (let i = 0; i < 256; ++i) {
let c = i,
k = 9;
while (--k) c = (c & 1 && -306674912) ^ (c >>> 1);
crct[i] = c;
}
for (let i = 0; i < 256; ++i) {
let lv = crct[i];
for (let j = 256; j < 4096; j += 256)
lv = crct[i | j] = (lv >>> 8) ^ crct[lv & 255];
}
const crcts = [];
for (let i = 0; i < 16; ) {
crcts[i] = crct.subarray(i << 8, ++i << 8);
}
// prettier-ignore
const [t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16] =
crcts;
// raw CRC function
// stream by passing in previous CRC output as second parameter
return function crc32(d, c = -1) {
let i = 0;
const len = d.length;
const max = len - 16;
for (; i < max; ) {
c =
t16[d[i++] ^ (c & 255)] ^
t15[d[i++] ^ ((c >> 8) & 255)] ^
t14[d[i++] ^ ((c >> 16) & 255)] ^
t13[d[i++] ^ (c >>> 24)] ^
t12[d[i++]] ^
t11[d[i++]] ^
t10[d[i++]] ^
t9[d[i++]] ^
t8[d[i++]] ^
t7[d[i++]] ^
t6[d[i++]] ^
t5[d[i++]] ^
t4[d[i++]] ^
t3[d[i++]] ^
t2[d[i++]] ^
t1[d[i++]];
}
for (; i < len; ++i) {
c = t1[(c & 255) ^ d[i]] ^ (c >>> 8);
}
return ~c;
};
}
/**
* Calculate the CRC32 checksum of an array-like buffer.
* @function crc32
* @param {ArrayLike} buf the array-like buffer to calculate the CRC32 of
* @param {number} [c=-1] the initial CRC32 value
* @returns {number} the CRC32 checksum
*/
export default (() => {
// Avoid allocating global memory unless necessary
let init = false;
let crc32_instance;
return function crc32(d, c = -1) {
if (!init) {
crc32_instance = CRC32();
init = true;
}
return crc32_instance(d, c);
};
})();