Setting the file. One moment.
Chapter 06 · Clickhouse Js Node Rowbinary
Subchapter 6.75
src/writers/varint.ts
TypeScript64 lines2 KB
import { Sink, reserve } from "./core.js";
/**
* Write a LEB128 unsigned varint — the encode mirror of `readUVarint` (used for
* string/array/map lengths).
*
* Takes a JS `number`, so it is NOT bigint-friendly: the value MUST be a
* non-negative integer no larger than `Number.MAX_SAFE_INTEGER` (2^53 - 1). That
* precondition is NOT checked here — at this level the data is expected to be
* correct (a length the encoder itself produced), and an out-of-range value is a
* programming error the server will reject. If you genuinely need lengths beyond
* 2^53, write a bigint version with a bigint accumulator instead of widening this
* one.
*
* UNROLLED, mirroring `readUVarint`: branch on magnitude so the exact byte count
* is known up front for a single {@link reserve}, with no length-counting loop.
* Each byte carries 7 payload bits low-first, with the continuation bit (`+ 0x80`)
* set while more bits remain. `/` and `%` (never `>>>`/`&`): JS bitwise operators
* are 32-bit and would corrupt values past bit 31. The overwhelmingly common
* 1–2 byte case costs one or two compares.
*/
export function writeUVarint(sink: Sink, value: number): void {
if (value < 0x80) {
sink.buf[reserve(sink, 1)] = value;
return;
}
if (value < 0x4000) {
const o = reserve(sink, 2);
sink.buf[o] = (value % 128) + 0x80;
sink.buf[o + 1] = Math.floor(value / 128);
return;
}
if (value < 0x200000) {
const o = reserve(sink, 3);
sink.buf[o] = (value % 128) + 0x80;
sink.buf[o + 1] = (Math.floor(value / 128) % 128) + 0x80;
sink.buf[o + 2] = Math.floor(value / 16384);
return;
}
if (value < 0x10000000) {
const o = reserve(sink, 4);
sink.buf[o] = (value % 128) + 0x80;
sink.buf[o + 1] = (Math.floor(value / 128) % 128) + 0x80;
sink.buf[o + 2] = (Math.floor(value / 16384) % 128) + 0x80;
sink.buf[o + 3] = Math.floor(value / 2097152);
return;
}
// >= 2^28 — rare for RowBinary lengths. Fall back to a short loop writing into
// a single span sized by a leading magnitude count (still one reserve()).
let size = 5;
for (
let v = Math.floor(value / 268435456);
v >= 0x80;
v = Math.floor(v / 128)
)
size++;
const o = reserve(sink, size);
let v = value;
for (let i = 0; i < size - 1; i++) {
sink.buf[o + i] = (v % 128) + 0x80;
v = Math.floor(v / 128);
}
sink.buf[o + size - 1] = v;
}