json-joy
Version:
Collection of libraries for building collaborative editing apps.
251 lines (250 loc) • 11.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrdtWriter = void 0;
const Writer_1 = require("@jsonjoy.com/util/lib/buffers/Writer");
class CrdtWriter extends Writer_1.Writer {
/**
* In the below encoding diagrams bits are annotated as follows:
*
* - "x" - vector table index, reference to the logical clock.
* - "y" - time difference.
* - "?" - whether the next byte is used for encoding.
*
* If x is less than 8 and y is less than 16, the relative ID is encoded as a
* single byte:
*
* ```
* +--------+
* |0xxxyyyy|
* +--------+
* ```
*
* Otherwise the top bit of the first byte is set to 1; and x and y are encoded
* separately using b1vuint28 and vuint39, respectively.
*
* ```
* x y
* +===========+=========+
* | b1vuint28 | vuint39 |
* +===========+=========+
* ```
*
* The boolean flag of x b1vuint28 value is always set to 1.
*/
id(x, y) {
if (x <= 0b111 && y <= 0b1111) {
this.u8((x << 4) | y);
}
else {
this.b1vu56(1, x);
this.vu57(y);
}
}
/**
* #### `vu57`
*
* `vu57` stands for *variable length unsigned 57 bit integer*. It consumes
* up to 8 bytes. The maximum size of the decoded value is 57 bits.
*
* The high bit `?` of each octet indicates if the next byte should be
* consumed, up to 8 bytes. When `?` is set to `0`, it means that the current
* byte is the last byte of the encoded value.
*
* ```
* byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 byte 8
* +--------+........+........+........+........+........+........+········+
* |?zzzzzzz|?zzzzzzz|?zzzzzzz|?zzzzzzz|?zzzzzzz|?zzzzzzz|?zzzzzzz|zzzzzzzz|
* +--------+........+........+........+........+........+........+········+
*
* 11111 2211111 2222222 3333332 4443333 4444444 55555555
* 7654321 4321098 1098765 8765432 5432109 2109876 9876543 76543210
* | | | |
* 5th bit of z | | |
* 28th bit of z | 57th bit of z
* 39th bit of z
* ```
*
* @param num Number to encode as variable length unsigned 57 bit integer.
*/
vu57(num) {
if (num <= 0b1111111) {
this.u8(num);
}
else if (num <= 16383) {
this.ensureCapacity(2);
const uint8 = this.uint8;
uint8[this.x++] = 0b10000000 | (num & 0b01111111);
uint8[this.x++] = num >>> 7;
}
else if (num <= 2097151) {
this.ensureCapacity(3);
const uint8 = this.uint8;
uint8[this.x++] = 0b10000000 | (num & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 7) & 0b01111111);
uint8[this.x++] = num >>> 14;
}
else if (num <= 268435455) {
this.ensureCapacity(4);
const uint8 = this.uint8;
uint8[this.x++] = 0b10000000 | (num & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 7) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 14) & 0b01111111);
uint8[this.x++] = num >>> 21;
}
else {
let lo32 = num | 0;
if (lo32 < 0)
lo32 += 4294967296;
const hi32 = (num - lo32) / 4294967296;
if (num <= 34359738367) {
this.ensureCapacity(5);
const uint8 = this.uint8;
uint8[this.x++] = 0b10000000 | (num & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 7) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 14) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 21) & 0b01111111);
uint8[this.x++] = (hi32 << 4) | (num >>> 28);
}
else if (num <= 4398046511103) {
this.ensureCapacity(6);
const uint8 = this.uint8;
uint8[this.x++] = 0b10000000 | (num & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 7) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 14) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 21) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((hi32 & 0b111) << 4) | (num >>> 28);
uint8[this.x++] = hi32 >>> 3;
}
else if (num <= 562949953421311) {
this.ensureCapacity(7);
const uint8 = this.uint8;
uint8[this.x++] = 0b10000000 | (num & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 7) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 14) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 21) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((hi32 & 0b111) << 4) | (num >>> 28);
uint8[this.x++] = 0b10000000 | ((hi32 & 1016) >>> 3);
uint8[this.x++] = hi32 >>> 10;
}
else {
this.ensureCapacity(8);
const uint8 = this.uint8;
uint8[this.x++] = 0b10000000 | (num & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 7) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 14) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 21) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((hi32 & 0b111) << 4) | (num >>> 28);
uint8[this.x++] = 0b10000000 | ((hi32 & 1016) >>> 3);
uint8[this.x++] = 0b10000000 | ((hi32 & 130048) >>> 10);
uint8[this.x++] = hi32 >>> 17;
}
}
}
/**
* #### `b1vu56`
*
* `b1vu56` stands for: 1 bit flag followed by variable length unsigned 56 bit integer.
* It consumes up to 8 bytes.
*
* The high bit "?" of each byte indicates if the next byte should be
* consumed, up to 8 bytes.
*
* - f - flag
* - z - variable length unsigned 56 bit integer
* - ? - whether the next byte is used for encoding
*
* ```
* byte 1 byte 8
* +--------+........+........+........+........+........+........+········+
* |f?zzzzzz|?zzzzzzz|?zzzzzzz|?zzzzzzz|?zzzzzzz|?zzzzzzz|?zzzzzzz|zzzzzzzz|
* +--------+........+........+........+........+........+........+········+
*
* 1111 2111111 2222222 3333322 4433333 4444444 55555554
* 654321 3210987 0987654 7654321 4321098 1098765 8765432 65432109
* | | | |
* 5th bit of z | | |
* 27th bit of z | 56th bit of z
* 38th bit of z
* ```
*
* @param num Number to encode as variable length unsigned 56 bit integer.
*/
b1vu56(flag, num) {
if (num <= 0b111111) {
this.u8((flag << 7) | num);
}
else {
const firstByteMask = (flag << 7) | 0b1000000;
if (num <= 8191) {
this.ensureCapacity(2);
const uint8 = this.uint8;
uint8[this.x++] = firstByteMask | (num & 0b00111111);
uint8[this.x++] = num >>> 6;
}
else if (num <= 1048575) {
this.ensureCapacity(3);
const uint8 = this.uint8;
uint8[this.x++] = firstByteMask | (num & 0b00111111);
uint8[this.x++] = 0b10000000 | ((num >>> 6) & 0b01111111);
uint8[this.x++] = num >>> 13;
}
else if (num <= 134217727) {
this.ensureCapacity(4);
const uint8 = this.uint8;
uint8[this.x++] = firstByteMask | (num & 0b00111111);
uint8[this.x++] = 0b10000000 | ((num >>> 6) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 13) & 0b01111111);
uint8[this.x++] = num >>> 20;
}
else {
let lo32 = num | 0;
if (lo32 < 0)
lo32 += 4294967296;
const hi32 = (num - lo32) / 4294967296;
if (num <= 17179869183) {
this.ensureCapacity(5);
const uint8 = this.uint8;
uint8[this.x++] = firstByteMask | (num & 0b00111111);
uint8[this.x++] = 0b10000000 | ((num >>> 6) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 13) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 20) & 0b01111111);
uint8[this.x++] = (hi32 << 5) | (num >>> 27);
}
else if (num <= 2199023255551) {
this.ensureCapacity(6);
const uint8 = this.uint8;
uint8[this.x++] = firstByteMask | (num & 0b00111111);
uint8[this.x++] = 0b10000000 | ((num >>> 6) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 13) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 20) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((hi32 & 0b11) << 5) | (num >>> 27);
uint8[this.x++] = hi32 >>> 2;
}
else if (num <= 281474976710655) {
this.ensureCapacity(7);
const uint8 = this.uint8;
uint8[this.x++] = firstByteMask | (num & 0b00111111);
uint8[this.x++] = 0b10000000 | ((num >>> 6) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 13) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 20) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((hi32 & 0b11) << 5) | (num >>> 27);
uint8[this.x++] = 0b10000000 | ((hi32 & 508) >>> 2);
uint8[this.x++] = hi32 >>> 9;
}
else {
this.ensureCapacity(8);
const uint8 = this.uint8;
uint8[this.x++] = firstByteMask | (num & 0b00111111);
uint8[this.x++] = 0b10000000 | ((num >>> 6) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 13) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((num >>> 20) & 0b01111111);
uint8[this.x++] = 0b10000000 | ((hi32 & 0b11) << 5) | (num >>> 27);
uint8[this.x++] = 0b10000000 | ((hi32 & 508) >>> 2);
uint8[this.x++] = 0b10000000 | ((hi32 & 65024) >>> 9);
uint8[this.x++] = hi32 >>> 16;
}
}
}
}
}
exports.CrdtWriter = CrdtWriter;