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.

96 lines
2.3 KiB
JavaScript

"use strict";
const assert = require("assert");
const bigintBuffer = require("../bigint-buffer");
const createArithmeticCoder = require("./bitmask-arithmetic");
module.exports = function createDurationEncoder() {
// 55 bits for value + 1 bit for sign = 56 bits = 7 bytes
// NOTE: Maximums are exclusive!
let coder = createArithmeticCoder([
{ name: "milliseconds", minimum: 0, maximum: 1000 },
{ name: "seconds", minimum: 0, maximum: 64 }, // No, this is not a typo; leap seconds are a thing
{ name: "minutes", minimum: 0, maximum: 60 },
{ name: "hours", minimum: 0, maximum: 25 },
{ name: "days", minimum: 0, maximum: 31 },
{ name: "months", minimum: 0, maximum: 12 },
{ name: "years", minimum: 0, maximum: 8000 },
]);
let zeroPoint = 2n ** coder.bits; // first bit is a 1
return {
bits: coder.bits + 1n,
encode: function (value) {
let { negative, ... rest } = value;
let number = coder.encode(rest);
// NOTE: This approach ensures that values are correctly sorted even in their buffer representation!
let signedNumber = (negative)
? zeroPoint - number
: zeroPoint + number;
return {
value: bigintBuffer.toBuffer(signedNumber),
auxiliaryBlob: undefined
};
},
decode: function (bytes) {
let signedNumber = bigintBuffer.toBigint(bytes);
let negative = (signedNumber < zeroPoint);
let number = (negative)
? zeroPoint - signedNumber
: signedNumber - zeroPoint;
// FIXME: Update to new decode API
let decoded = coder.decode(number);
return {
... decoded,
negative: negative
};
}
};
};
// let coder = module.exports();
// let data1 = {
// negative: true,
// seconds: 1n
// };
// let data2 = {
// negative: false,
// seconds: 1n
// };
// let encoded1 = coder.encode(data1);
// let encoded2 = coder.encode(data2);
// console.log({ encoded1, encoded2 });
// let decoded1 = coder.decode(encoded1);
// let decoded2 = coder.decode(encoded2);
// console.log({ decoded1, decoded2 });
// assert(Buffer.compare(encoded1, encoded2) === -1);
// assert.deepStrictEqual(data1, stripUndefined(decoded1));
// assert.deepStrictEqual(data2, stripUndefined(decoded2));
// function stripUndefined(object) {
// let newObject = {};
// for (let [ key, value ] of Object.entries(object)) {
// if (value !== undefined) {
// newObject[key] = value;
// }
// }
// return newObject;
// }