You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

68 lines
1.4 KiB
JavaScript

"use strict";
const createArithmeticCoder = require("../arithmetic-coder");
function encodeBooleans(booleans) {
let n = 1n;
let bitmask = 0n;
for (let boolean of booleans) {
if (boolean === true) {
bitmask |= n;
}
n *= 2n;
}
return bitmask;
}
function decodeBooleans(bitmask, count) {
let n = 1n;
let booleans = [];
for (let i = 0; i < count; i++) {
booleans.push((bitmask & n) !== 0n);
n *= 2n;
}
return booleans;
}
module.exports = function createBitmaskArithmeticCoder(fields) {
// NOTE: We *always* store the bitmask as the very first field, to ensure that it doesn't interfere with binary sorting order
let fieldCount = BigInt(fields.length);
let maximumBitmaskValue = 2n ** fieldCount; // NOTE: Exclusive
let coder = createArithmeticCoder([
{ name: "__bitmask", minimum: 0, maximum: maximumBitmaskValue },
... fields
]);
return {
bits: coder.bits,
encode: function (data) {
let fieldPresence = fields.map((field) => data[field.name] != null);
return coder.encode({
... data,
__bitmask: encodeBooleans(fieldPresence)
});
},
decode: function (data) {
let decoded = coder.decode(data);
let fieldPresence = decodeBooleans(decoded.__bitmask, fields.length);
fields.forEach((field, i) => {
if (fieldPresence[i] === false) {
decoded[field.name] = undefined;
}
});
delete decoded.__bitmask;
return decoded;
}
};
};