Skip to content

Commit fa57817

Browse files
committed
perf: hoist TextDecoder to module level in lance-v2 string decode
Hot path — called on every string column page read. Avoids allocating a new TextDecoder per decodeLanceV2Strings call.
1 parent dfde519 commit fa57817

File tree

1 file changed

+4
-3
lines changed

1 file changed

+4
-3
lines changed

src/lance-v2.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import type { ColumnMeta, DataType, SchemaField } from "./types.js";
3535
import { logicalTypeToDataType } from "./manifest.js";
3636

37+
const textDecoder = new TextDecoder();
38+
3739
export interface LanceV2ColumnInfo {
3840
name: string;
3941
dtype: DataType;
@@ -553,7 +555,7 @@ export function decodeLanceV2Utf8(buf: ArrayBuffer, rowCount: number): string[]
553555
const bytes = new Uint8Array(buf);
554556

555557
// Decode entire string data block at once (1 TextDecoder call, not N)
556-
const allStringsDecoded = new TextDecoder().decode(bytes.subarray(dataStart, dataStart + totalStringLen));
558+
const allStringsDecoded = textDecoder.decode(bytes.subarray(dataStart, dataStart + totalStringLen));
557559

558560
// Fast path: if all strings are ASCII (common), use byte offsets directly as char offsets
559561
if (allStringsDecoded.length === totalStringLen) {
@@ -568,12 +570,11 @@ export function decodeLanceV2Utf8(buf: ArrayBuffer, rowCount: number): string[]
568570
}
569571

570572
// Slow path: multi-byte UTF-8 — must decode per-string to get correct boundaries
571-
const decoder = new TextDecoder();
572573
const strings = new Array<string>(rowCount);
573574
let prevEnd = 0;
574575
for (let i = 0; i < rowCount; i++) {
575576
const end = endOffsets[i];
576-
strings[i] = decoder.decode(bytes.subarray(dataStart + prevEnd, dataStart + end));
577+
strings[i] = textDecoder.decode(bytes.subarray(dataStart + prevEnd, dataStart + end));
577578
prevEnd = end;
578579
}
579580
return strings;

0 commit comments

Comments
 (0)