Files
scriptc/tests/corpus/8533-stream-buffer-queue-index.ts
T
Chris Tate 9632906b4d Take from a Readable's buffered queue by moving its head index
Taking the head entry of a Readable's buffer moved every remaining entry
down one slot, so draining a queue of n buffered chunks cost O(n²). The
buffer now keeps the index of its first entry: a take advances it, a push
at the tail moves the entries down only when at least half the slots are
free at the front (and grows otherwise), and unshift takes a freed front
slot when there is one. The drop, trace and boxing loops walk the entries
from that index.

The stream-buffered-drain runtime workload buffers 200,000 objects and
100,000 Buffers before draining them; corpus 8533 covers reads across
entries, unshift into a freed slot and onto a part-read head, setEncoding
after takes, and object-mode takes, unshifts and pushes.
2026-10-29 14:59:10 -05:00

34 lines
1.4 KiB
TypeScript

// A Readable's buffered queue after its head moved: read(n) across
// entries, unshift into the freed front slot and onto a part-read head,
// setEncoding after takes, and object-mode takes, unshifts and pushes that
// reuse the freed slots.
import { Readable } from "node:stream";
const bytes = new Readable({ read() {} });
for (let i = 0; i < 40; i++) bytes.push(Buffer.from(`c${i};`));
const out: string[] = [];
out.push(String(bytes.read(7)));
out.push(String(bytes.read(4)));
bytes.unshift(Buffer.from("U1;"));
out.push(String(bytes.read(5)));
bytes.unshift(Buffer.from("U2;"));
out.push(String(bytes.read(30)));
bytes.setEncoding("utf8");
out.push(String(bytes.read(9)));
for (let i = 40; i < 60; i++) bytes.push(Buffer.from(`d${i};`));
out.push(String(bytes.read(20)));
out.push(`left ${bytes.readableLength}`);
console.log(out.join("\n"));
const objects = new Readable({ objectMode: true, highWaterMark: 4, read() {} });
for (let i = 0; i < 12; i++) objects.push({ n: i });
const seen: number[] = [];
for (let i = 0; i < 9; i++) seen.push((objects.read() as { n: number }).n);
objects.unshift({ n: 100 });
objects.unshift({ n: 101 });
for (let i = 12; i < 40; i++) objects.push({ n: i });
let row: { n: number } | null;
while ((row = objects.read() as { n: number } | null) !== null) seen.push(row.n);
console.log(seen.join(","));
console.log(`object left ${objects.readableLength}`);