671 lines
24 KiB
JavaScript
671 lines
24 KiB
JavaScript
import IntWrapper from "../decoding/intWrapper";
|
|
import { createFastPforEncoderWorkspace, encodeFastPforInt32WithWorkspace } from "./fastPforEncoder";
|
|
import { encodeBigEndianInt32s } from "./bigEndianEncode";
|
|
export function encodeVarintInt32Value(value, dst, offset) {
|
|
let v = value;
|
|
while (v > 0x7f) {
|
|
dst[offset.get()] = (v & 0x7f) | 0x80;
|
|
offset.increment();
|
|
v >>>= 7;
|
|
}
|
|
dst[offset.get()] = v & 0x7f;
|
|
offset.increment();
|
|
}
|
|
export function encodeVarintInt32(values) {
|
|
const buffer = new Uint8Array(values.length * 5);
|
|
const offset = new IntWrapper(0);
|
|
for (const value of values) {
|
|
encodeVarintInt32Value(value, buffer, offset);
|
|
}
|
|
return buffer.slice(0, offset.get());
|
|
}
|
|
export function encodeVarintInt64(values) {
|
|
const buffer = new Uint8Array(values.length * 10);
|
|
const offset = new IntWrapper(0);
|
|
for (const value of values) {
|
|
encodeVarintInt64Value(value, buffer, offset);
|
|
}
|
|
return buffer.slice(0, offset.get());
|
|
}
|
|
function encodeVarintInt64Value(value, dst, offset) {
|
|
let v = value;
|
|
while (v > 0x7fn) {
|
|
dst[offset.get()] = Number(v & 0x7fn) | 0x80;
|
|
offset.increment();
|
|
v >>= 7n;
|
|
}
|
|
dst[offset.get()] = Number(v & 0x7fn);
|
|
offset.increment();
|
|
}
|
|
export function encodeVarintFloat64(values) {
|
|
// 1. Calculate the exact size required for the buffer
|
|
let size = 0;
|
|
for (let i = 0; i < values.length; i++) {
|
|
let val = values[i];
|
|
// Ensure we handle the value as a positive integer
|
|
val = val < 0 ? 0 : Math.floor(val);
|
|
// 0 always takes 1 byte
|
|
if (val === 0) {
|
|
size++;
|
|
continue;
|
|
}
|
|
// Calculate bytes needed: ceil(log128(val + 1))
|
|
while (val > 0) {
|
|
size++;
|
|
val = Math.floor(val / 128);
|
|
}
|
|
}
|
|
const dst = new Uint8Array(size);
|
|
const offset = new IntWrapper(0);
|
|
for (let i = 0; i < values.length; i++) {
|
|
encodeVarintFloat64Value(values[i], dst, offset);
|
|
}
|
|
return dst;
|
|
}
|
|
/**
|
|
* Encodes a single number into the buffer at the given offset using Varint encoding.
|
|
* Handles numbers up to 2^53 (MAX_SAFE_INTEGER) correctly.
|
|
*/
|
|
function encodeVarintFloat64Value(val, buf, offset) {
|
|
// Ensure integer
|
|
val = Math.floor(val);
|
|
// Handle 0 explicitly or ensure loop runs once
|
|
if (val === 0) {
|
|
buf[offset.get()] = 0;
|
|
offset.increment();
|
|
return;
|
|
}
|
|
while (val >= 128) {
|
|
// Write 7 bits of data | 0x80 (continuation bit)
|
|
buf[offset.get()] = (val % 128) | 0x80;
|
|
offset.increment();
|
|
// Shift right by 7 bits
|
|
val = Math.floor(val / 128);
|
|
}
|
|
// Write the last byte (no continuation bit)
|
|
buf[offset.get()] = val;
|
|
offset.increment();
|
|
}
|
|
export function encodeFastPfor(values) {
|
|
const encoderWorkspace = createFastPforEncoderWorkspace();
|
|
const encodedWords = encodeFastPforInt32WithWorkspace(values, encoderWorkspace);
|
|
return encodeBigEndianInt32s(encodedWords);
|
|
}
|
|
export function encodeZigZagInt32Value(value) {
|
|
return (value << 1) ^ (value >> 31);
|
|
}
|
|
export function encodeZigZagInt64Value(value) {
|
|
return (value << 1n) ^ (value >> 63n);
|
|
}
|
|
export function encodeZigZagFloat64Value(n) {
|
|
return n >= 0 ? n * 2 : n * -2 - 1;
|
|
}
|
|
export function encodeZigZagInt32(data) {
|
|
const result = new Uint32Array(data.length);
|
|
for (let i = 0; i < data.length; i++) {
|
|
result[i] = encodeZigZagInt32Value(data[i]);
|
|
}
|
|
return result;
|
|
}
|
|
export function encodeZigZagInt64(data) {
|
|
const result = new BigUint64Array(data.length);
|
|
for (let i = 0; i < data.length; i++) {
|
|
result[i] = encodeZigZagInt64Value(data[i]);
|
|
}
|
|
return result;
|
|
}
|
|
export function encodeZigZagFloat64(data) {
|
|
for (let i = 0; i < data.length; i++) {
|
|
data[i] = encodeZigZagFloat64Value(data[i]);
|
|
}
|
|
}
|
|
export function encodeUnsignedRleInt32(input) {
|
|
if (input.length === 0) {
|
|
return { data: new Uint32Array(0), runs: 0 };
|
|
}
|
|
const runLengths = [];
|
|
const runValues = [];
|
|
let currentRunLength = 0;
|
|
let currentValue = input[0];
|
|
for (let i = 0; i < input.length; i++) {
|
|
const nextValue = input[i];
|
|
if (nextValue === currentValue) {
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
// End of the current run, record it
|
|
runLengths.push(currentRunLength);
|
|
runValues.push(currentValue);
|
|
// Start a new run
|
|
currentValue = nextValue;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Record the final run after the loop finishes
|
|
runLengths.push(currentRunLength);
|
|
runValues.push(currentValue);
|
|
// Combine lengths and values into the final structured output array
|
|
const numRuns = runLengths.length;
|
|
const encodedData = new Uint32Array(numRuns * 2);
|
|
// Populate the first half with lengths
|
|
encodedData.set(runLengths, 0);
|
|
// Populate the second half with values, offset by the total number of runs
|
|
encodedData.set(runValues, numRuns);
|
|
return { data: encodedData, runs: numRuns };
|
|
}
|
|
export function encodeUnsignedRleInt64(input) {
|
|
if (input.length === 0) {
|
|
return { data: new BigUint64Array(0), runs: 0 };
|
|
}
|
|
const runLengths = [];
|
|
const runValues = [];
|
|
let currentRunLength = 0;
|
|
let currentValue = input[0];
|
|
for (let i = 0; i < input.length; i++) {
|
|
const nextValue = input[i];
|
|
if (nextValue === currentValue) {
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
// End of the current run, record it
|
|
runLengths.push(currentRunLength);
|
|
runValues.push(currentValue);
|
|
// Start a new run
|
|
currentValue = nextValue;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Record the final run after the loop finishes
|
|
runLengths.push(currentRunLength);
|
|
runValues.push(currentValue);
|
|
// Combine lengths and values into the final structured output array (BigUint64Array)
|
|
const numRuns = runLengths.length;
|
|
const encodedData = new BigUint64Array(numRuns * 2);
|
|
// Populate the first half with lengths, converting the run length numbers to bigint for storage in the BigUint64Array.
|
|
for (let i = 0; i < numRuns; i++) {
|
|
encodedData[i] = BigInt(runLengths[i]);
|
|
}
|
|
// Populate the second half with values, offset by the total number of runs
|
|
encodedData.set(runValues, numRuns);
|
|
return { data: encodedData, runs: numRuns };
|
|
}
|
|
export function encodeUnsignedRleFloat64(input) {
|
|
if (input.length === 0) {
|
|
return { data: new Float64Array(0), runs: 0 };
|
|
}
|
|
const runLengths = [];
|
|
const runValues = [];
|
|
let currentRunLength = 0;
|
|
let currentValue = input[0];
|
|
for (let i = 0; i < input.length; i++) {
|
|
const nextValue = input[i];
|
|
if (nextValue === currentValue) {
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
// End of the current run, record it
|
|
runLengths.push(currentRunLength);
|
|
runValues.push(currentValue);
|
|
// Start a new run
|
|
currentValue = nextValue;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Record the final run after the loop finishes
|
|
runLengths.push(currentRunLength);
|
|
runValues.push(currentValue);
|
|
// Combine lengths and values into the final structured output array (Float64Array)
|
|
const numRuns = runLengths.length;
|
|
// The final array is twice the size of the number of runs
|
|
const encodedData = new Float64Array(numRuns * 2);
|
|
// Populate the first half with lengths
|
|
encodedData.set(runLengths, 0);
|
|
// Populate the second half with values, offset by the total number of runs
|
|
encodedData.set(runValues, numRuns);
|
|
return { data: encodedData, runs: numRuns };
|
|
}
|
|
export function encodeZigZagDeltaInt32(data) {
|
|
if (data.length === 0) {
|
|
return new Uint32Array(0);
|
|
}
|
|
const encodedData = new Uint32Array(data.length);
|
|
let previousValue = data[0];
|
|
encodedData[0] = encodeZigZagInt32Value(previousValue);
|
|
for (let i = 1; i < data.length; i++) {
|
|
const currentValue = data[i];
|
|
const delta = currentValue - previousValue;
|
|
const encodedDelta = encodeZigZagInt32Value(delta);
|
|
// Store the encoded delta back into the array
|
|
encodedData[i] = encodedDelta;
|
|
// Update the previous value tracker for the next iteration's delta calculation
|
|
previousValue = currentValue;
|
|
}
|
|
return encodedData;
|
|
}
|
|
export function encodeZigZagDeltaInt64(data) {
|
|
if (data.length === 0) {
|
|
return new BigUint64Array(0);
|
|
}
|
|
const encodedData = new BigUint64Array(data.length);
|
|
let previousValue = data[0];
|
|
encodedData[0] = encodeZigZagInt64Value(previousValue);
|
|
for (let i = 1; i < data.length; i++) {
|
|
const currentValue = data[i];
|
|
const delta = currentValue - previousValue;
|
|
const encodedDelta = encodeZigZagInt64Value(delta);
|
|
// Store the encoded delta back into the array
|
|
encodedData[i] = encodedDelta;
|
|
// Update the previous value tracker for the next iteration's delta calculation
|
|
previousValue = currentValue;
|
|
}
|
|
return encodedData;
|
|
}
|
|
export function encodeZigZagDeltaFloat64(data) {
|
|
if (data.length === 0) {
|
|
return;
|
|
}
|
|
let previousValue = data[0];
|
|
data[0] = encodeZigZagFloat64Value(previousValue);
|
|
for (let i = 1; i < data.length; i++) {
|
|
const currentValue = data[i];
|
|
const delta = currentValue - previousValue;
|
|
const encodedDelta = encodeZigZagFloat64Value(delta);
|
|
// Store the encoded delta back into the array
|
|
data[i] = encodedDelta;
|
|
// Update the previous value tracker for the next iteration's delta calculation
|
|
previousValue = currentValue;
|
|
}
|
|
}
|
|
export function encodeZigZagRleInt32(input) {
|
|
if (input.length === 0) {
|
|
return { data: new Uint32Array(0), runs: 0, numTotalValues: 0 };
|
|
}
|
|
const zigzagEncodedStream = [];
|
|
// Step 1: Apply Zigzag Encoding to all values
|
|
for (let i = 0; i < input.length; i++) {
|
|
zigzagEncodedStream.push(encodeZigZagInt32Value(input[i]));
|
|
}
|
|
// zigzagEncodedStream now holds the intermediate stream of zigzag values
|
|
// Step 2: Apply RLE to the stream of zigzag-encoded values
|
|
const runLengths = [];
|
|
const runZigZagValues = [];
|
|
let currentRunLength = 0;
|
|
let currentValue = zigzagEncodedStream[0];
|
|
for (let i = 0; i < zigzagEncodedStream.length; i++) {
|
|
const nextValue = zigzagEncodedStream[i];
|
|
if (nextValue === currentValue) {
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
runLengths.push(currentRunLength);
|
|
runZigZagValues.push(currentValue);
|
|
currentValue = nextValue;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Record the final run
|
|
runLengths.push(currentRunLength);
|
|
runZigZagValues.push(currentValue);
|
|
// Step 3: Combine lengths and values into the final structured output array
|
|
const numRuns = runLengths.length;
|
|
// The final array uses Uint32Array for lengths AND values
|
|
const encodedData = new Uint32Array(numRuns * 2);
|
|
// Populate the first half with lengths
|
|
encodedData.set(runLengths, 0);
|
|
// Populate the second half with zigzagged values
|
|
encodedData.set(runZigZagValues, numRuns);
|
|
return {
|
|
data: encodedData,
|
|
runs: numRuns,
|
|
numTotalValues: input.length, // Total original values count
|
|
};
|
|
}
|
|
export function encodeZigZagRleInt64(input) {
|
|
if (input.length === 0) {
|
|
return { data: new BigUint64Array(0), runs: 0, numTotalValues: 0 };
|
|
}
|
|
const zigzagEncodedStream = [];
|
|
// Step 1: Apply Zigzag Encoding to all values
|
|
for (let i = 0; i < input.length; i++) {
|
|
zigzagEncodedStream.push(encodeZigZagInt64Value(input[i]));
|
|
}
|
|
// zigzagEncodedStream now holds the intermediate stream of zigzag values
|
|
// Step 2: Apply RLE to the stream of zigzag-encoded values
|
|
const runLengths = [];
|
|
const runZigZagValues = [];
|
|
let currentRunLength = 0;
|
|
let currentValue = zigzagEncodedStream[0];
|
|
for (let i = 0; i < zigzagEncodedStream.length; i++) {
|
|
const nextValue = zigzagEncodedStream[i];
|
|
if (nextValue === currentValue) {
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
runLengths.push(currentRunLength);
|
|
runZigZagValues.push(currentValue);
|
|
currentValue = nextValue;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Record the final run
|
|
runLengths.push(currentRunLength);
|
|
runZigZagValues.push(currentValue);
|
|
// Step 3: Combine lengths and values into the final structured output array
|
|
const numRuns = runLengths.length;
|
|
// The final array uses BigUint64Array for lengths AND values
|
|
const encodedData = new BigUint64Array(numRuns * 2);
|
|
// Populate the first half with lengths (converting numbers back to BigUint64Array format)
|
|
for (let i = 0; i < numRuns; i++) {
|
|
encodedData[i] = BigInt(runLengths[i]);
|
|
}
|
|
// Populate the second half with zigzagged values
|
|
encodedData.set(runZigZagValues, numRuns);
|
|
return {
|
|
data: encodedData,
|
|
runs: numRuns,
|
|
numTotalValues: input.length, // Total original values count
|
|
};
|
|
}
|
|
export function encodeZigZagRleFloat64(input) {
|
|
if (input.length === 0) {
|
|
return { data: new Float64Array(0), runs: 0, numTotalValues: 0 };
|
|
}
|
|
const zigzagEncodedStream = [];
|
|
// Step 1: Apply Float-based Zigzag Encoding to all values
|
|
for (let i = 0; i < input.length; i++) {
|
|
zigzagEncodedStream.push(encodeZigZagFloat64Value(input[i]));
|
|
}
|
|
// zigzagEncodedStream now holds the intermediate stream of zigzag values (as floats acting as integers)
|
|
// Step 2: Apply RLE to the stream of zigzag-encoded values
|
|
const runLengths = [];
|
|
const runZigZagValues = [];
|
|
let currentRunLength = 0;
|
|
let currentValue = zigzagEncodedStream[0];
|
|
for (let i = 0; i < zigzagEncodedStream.length; i++) {
|
|
const nextValue = zigzagEncodedStream[i];
|
|
if (nextValue === currentValue) {
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
runLengths.push(currentRunLength);
|
|
runZigZagValues.push(currentValue);
|
|
currentValue = nextValue;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Record the final run
|
|
runLengths.push(currentRunLength);
|
|
runZigZagValues.push(currentValue);
|
|
// Step 3: Combine lengths and values into the final structured output array
|
|
const numRuns = runLengths.length;
|
|
// The final array uses Float64Array for lengths AND values
|
|
const encodedData = new Float64Array(numRuns * 2);
|
|
// Populate the first half with lengths
|
|
encodedData.set(runLengths, 0);
|
|
// Populate the second half with zigzagged values
|
|
encodedData.set(runZigZagValues, numRuns);
|
|
return {
|
|
data: encodedData,
|
|
runs: numRuns,
|
|
numTotalValues: input.length, // Total original values count
|
|
};
|
|
}
|
|
/**
|
|
* This is not really a encode, but more of a decode method...
|
|
*/
|
|
export function encodeDeltaInt32(data) {
|
|
if (data.length === 0) {
|
|
return;
|
|
}
|
|
for (let i = data.length - 1; i >= 1; i--) {
|
|
data[i] = data[i] - data[i - 1];
|
|
}
|
|
}
|
|
export function encodeComponentwiseDeltaVec2(data) {
|
|
if (data.length < 2)
|
|
return new Uint32Array(data);
|
|
const encoded = new Uint32Array(data.length);
|
|
// Reverse iterate to avoid overwriting data needed for delta computation
|
|
for (let i = data.length - 2; i >= 2; i -= 2) {
|
|
const deltaX = data[i] - data[i - 2];
|
|
const deltaY = data[i + 1] - data[i - 1];
|
|
encoded[i] = encodeZigZagInt32Value(deltaX);
|
|
encoded[i + 1] = encodeZigZagInt32Value(deltaY);
|
|
}
|
|
// Encode first vertex last (after computing all deltas)
|
|
encoded[0] = encodeZigZagInt32Value(data[0]);
|
|
encoded[1] = encodeZigZagInt32Value(data[1]);
|
|
return encoded;
|
|
}
|
|
export function encodeComponentwiseDeltaVec2Scaled(data, scale) {
|
|
if (data.length < 2)
|
|
return new Uint32Array(data);
|
|
const encoded = new Uint32Array(data.length);
|
|
// First, inverse scale all values (tile space -> original space)
|
|
for (let i = 0; i < data.length; i++) {
|
|
encoded[i] = Math.round(data[i] / scale);
|
|
}
|
|
// Then apply componentwise delta encoding (same as non-scaled version)
|
|
// Reverse iterate to avoid overwriting data needed for delta computation
|
|
for (let i = encoded.length - 2; i >= 2; i -= 2) {
|
|
const deltaX = encoded[i] - encoded[i - 2];
|
|
const deltaY = encoded[i + 1] - encoded[i - 1];
|
|
encoded[i] = encodeZigZagInt32Value(deltaX);
|
|
encoded[i + 1] = encodeZigZagInt32Value(deltaY);
|
|
}
|
|
// Encode first vertex last (after computing all deltas)
|
|
encoded[0] = encodeZigZagInt32Value(encoded[0]);
|
|
encoded[1] = encodeZigZagInt32Value(encoded[1]);
|
|
return encoded;
|
|
}
|
|
// HM TODO:
|
|
// zigZagDeltaOfDeltaDecoding
|
|
export function encodeZigZagRleDeltaInt32(values) {
|
|
if (values.length === 0) {
|
|
return { data: new Uint32Array(0), runs: 0, numTotalValues: 0 };
|
|
}
|
|
const runLengths = [];
|
|
const encodedDeltas = [];
|
|
// The decoder explicitly sets decodedValues[0] = 0 and uses previousValue = 0.
|
|
// Therefore, we initialize our 'previous' tracker to 0 to calculate the first delta correctly.
|
|
let previousValue = 0;
|
|
// Variables to track the current run
|
|
let currentDelta = null;
|
|
let currentRunLength = 0;
|
|
for (let i = 0; i < values.length; i++) {
|
|
const value = values[i];
|
|
const delta = value - previousValue;
|
|
previousValue = value;
|
|
if (currentDelta === null) {
|
|
// First element initialization
|
|
currentDelta = delta;
|
|
currentRunLength = 1;
|
|
}
|
|
else if (delta === currentDelta) {
|
|
// Continuation of the current run
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
// The run has broken (delta changed)
|
|
// 1. Push the length of the previous run
|
|
runLengths.push(currentRunLength);
|
|
// 2. ZigZag encode the previous delta and push it
|
|
encodedDeltas.push(encodeZigZagInt32Value(currentDelta));
|
|
// Start the new run
|
|
currentDelta = delta;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Flush the final run remaining after the loop finishes
|
|
if (currentDelta !== null) {
|
|
runLengths.push(currentRunLength);
|
|
encodedDeltas.push(encodeZigZagInt32Value(currentDelta));
|
|
}
|
|
const numRuns = runLengths.length;
|
|
// The decoder expects 'data' to be: [RunLength 1, RunLength 2... | Value 1, Value 2...]
|
|
// Size is numRuns * 2 (First half lengths, second half values)
|
|
const data = new Uint32Array(numRuns * 2);
|
|
for (let i = 0; i < numRuns; i++) {
|
|
data[i] = runLengths[i]; // First half: Run Lengths
|
|
data[i + numRuns] = encodedDeltas[i]; // Second half: ZigZag Encoded Deltas
|
|
}
|
|
return {
|
|
data: data,
|
|
runs: numRuns,
|
|
numTotalValues: values.length,
|
|
};
|
|
}
|
|
export function encodeRleDeltaInt32(values) {
|
|
if (values.length === 0) {
|
|
return { data: new Uint32Array(0), runs: 0, numTotalValues: 0 };
|
|
}
|
|
const runLengths = [];
|
|
const deltas = [];
|
|
// The decoder logic relies on: decodedValues[0] = 0; previousValue = 0;
|
|
// So the encoder must assume the sequence starts relative to 0.
|
|
let previousValue = 0;
|
|
// Track the current run of deltas
|
|
let currentDelta = null;
|
|
let currentRunLength = 0;
|
|
for (let i = 0; i < values.length; i++) {
|
|
const value = values[i];
|
|
const delta = value - previousValue;
|
|
previousValue = value;
|
|
if (currentDelta === null) {
|
|
// Initialize first run
|
|
currentDelta = delta;
|
|
currentRunLength = 1;
|
|
}
|
|
else if (delta === currentDelta) {
|
|
// Continue current run
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
// Delta changed: flush the previous run
|
|
runLengths.push(currentRunLength);
|
|
deltas.push(currentDelta);
|
|
// Start new run
|
|
currentDelta = delta;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Flush the final run
|
|
if (currentDelta !== null) {
|
|
runLengths.push(currentRunLength);
|
|
deltas.push(currentDelta);
|
|
}
|
|
const numRuns = runLengths.length;
|
|
// Pack into Uint32Array: [ RunLength 1...N | Delta 1...N ]
|
|
const data = new Uint32Array(numRuns * 2);
|
|
for (let i = 0; i < numRuns; i++) {
|
|
data[i] = runLengths[i];
|
|
data[i + numRuns] = deltas[i];
|
|
}
|
|
return {
|
|
data: data,
|
|
runs: numRuns,
|
|
numTotalValues: values.length,
|
|
};
|
|
}
|
|
export function encodeDeltaRleInt32(input) {
|
|
if (input.length === 0) {
|
|
return { data: new Uint32Array(0), runs: 0, numValues: 0 };
|
|
}
|
|
const deltasAndEncoded = [];
|
|
let previousValue = 0;
|
|
// Step 1 & 2: Calculate Deltas and Zigzag Encode them
|
|
for (let i = 0; i < input.length; i++) {
|
|
const currentValue = input[i];
|
|
const delta = currentValue - previousValue;
|
|
const encodedDelta = encodeZigZagInt32Value(delta);
|
|
deltasAndEncoded.push(encodedDelta);
|
|
previousValue = currentValue;
|
|
}
|
|
// deltasAndEncoded now holds the intermediate stream of zigzagged deltas
|
|
// Step 3: Apply RLE to the stream of zigzag-encoded deltas
|
|
const runLengths = [];
|
|
const runZigZagDeltas = [];
|
|
let currentRunLength = 0;
|
|
let currentRunValue = deltasAndEncoded[0];
|
|
for (let i = 0; i < deltasAndEncoded.length; i++) {
|
|
const nextValue = deltasAndEncoded[i];
|
|
if (nextValue === currentRunValue) {
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
runLengths.push(currentRunLength);
|
|
runZigZagDeltas.push(currentRunValue);
|
|
currentRunValue = nextValue;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Record the final run
|
|
runLengths.push(currentRunLength);
|
|
runZigZagDeltas.push(currentRunValue);
|
|
// Step 4: Combine lengths and values into the final structured output array
|
|
const numRuns = runLengths.length;
|
|
const encodedData = new Uint32Array(numRuns * 2);
|
|
// Populate the first half with lengths
|
|
for (let i = 0; i < numRuns; i++) {
|
|
encodedData[i] = runLengths[i];
|
|
}
|
|
// Populate the second half with zigzagged deltas
|
|
// Uint32Array.set() works with standard number arrays
|
|
encodedData.set(runZigZagDeltas, numRuns);
|
|
return {
|
|
data: encodedData,
|
|
runs: numRuns,
|
|
numValues: input.length, // Total original values count
|
|
};
|
|
}
|
|
export function encodeDeltaRleInt64(input) {
|
|
if (input.length === 0) {
|
|
return { data: new BigUint64Array(0), runs: 0, numValues: 0 };
|
|
}
|
|
const deltasAndEncoded = [];
|
|
let previousValue = 0n;
|
|
// Step 1 & 2: Calculate Deltas and Zigzag Encode them
|
|
for (let i = 0; i < input.length; i++) {
|
|
const currentValue = input[i];
|
|
const delta = currentValue - previousValue;
|
|
const encodedDelta = encodeZigZagInt64Value(delta);
|
|
deltasAndEncoded.push(encodedDelta);
|
|
previousValue = currentValue;
|
|
}
|
|
// deltasAndEncoded now holds the intermediate stream of zigzagged deltas
|
|
// Step 3: Apply RLE to the stream of zigzag-encoded deltas
|
|
const runLengths = [];
|
|
const runZigZagDeltas = [];
|
|
let currentRunLength = 0;
|
|
let currentValue = deltasAndEncoded[0];
|
|
for (let i = 0; i < deltasAndEncoded.length; i++) {
|
|
const nextValue = deltasAndEncoded[i];
|
|
if (nextValue === currentValue) {
|
|
currentRunLength++;
|
|
}
|
|
else {
|
|
runLengths.push(currentRunLength);
|
|
runZigZagDeltas.push(currentValue);
|
|
currentValue = nextValue;
|
|
currentRunLength = 1;
|
|
}
|
|
}
|
|
// Record the final run
|
|
runLengths.push(currentRunLength);
|
|
runZigZagDeltas.push(currentValue);
|
|
// Step 4: Combine lengths and values into the final structured output array
|
|
const numRuns = runLengths.length;
|
|
const encodedData = new BigUint64Array(numRuns * 2);
|
|
// Populate the first half with lengths (converting numbers back to BigUint64Array for storage)
|
|
for (let i = 0; i < numRuns; i++) {
|
|
encodedData[i] = BigInt(runLengths[i]);
|
|
}
|
|
// Populate the second half with zigzagged deltas
|
|
encodedData.set(runZigZagDeltas, numRuns);
|
|
return {
|
|
data: encodedData,
|
|
runs: numRuns,
|
|
numValues: input.length, // Total original values count
|
|
};
|
|
}
|
|
//# sourceMappingURL=integerEncodingUtils.js.map
|