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
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;
|
|
}
|
|
};
|
|
};
|