mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-25 06:24:27 +08:00
shift() moved every remaining element down one slot, making queue drains quadratic (100k elements: 0.85 s; 1M: no result in 30 s). Dense arrays of 8-byte slots with their own allocation now remove front elements by advancing data/present and lowering cap; the vacated slots stay in the allocation as head room. A flag in `spare` marks it and its size is implied by the layout (present == data + cap + head), so every reader, including inline element access in emitted code, is unchanged. Growth moves the elements back to the start of the allocation (in place only when that leaves half the moved count free, else geometrically), a drained array starts over at the front, unshift reuses head room, and an array unshift already had to move once reserves head room for half its length. scr_arr_outline drops head room before compiled storage swaps. Booleans, inline slots, sparse arrays and static arrays keep the old behavior. Scaling probes: shift/BFS/splice(0,1)/deque drains and unshift runs go from exponent ~2.0 to ~1.0 (shift 1e5 847 ms -> 1.6 ms); runtime bench geomean 1.0045 (neutral). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
74 lines
3.0 KiB
TypeScript
74 lines
3.0 KiB
TypeScript
// Arrays used as double-ended queues: runs of unshift (one value, several
|
|
// values, spread) on arrays long enough to reserve room in front of their
|
|
// elements, mixed with push, pop, shift, splice, indexing and iteration.
|
|
function checksum(xs: number[]): number {
|
|
let s = 0;
|
|
for (let i = 0; i < xs.length; i++) s = (s * 31 + xs[i]!) % 1000000007;
|
|
return s;
|
|
}
|
|
|
|
// A long run of single unshifts builds the array in reverse.
|
|
const rev: number[] = [];
|
|
for (let i = 0; i < 5000; i++) rev.unshift(i);
|
|
console.log("reverse", rev.length, rev[0], rev[4999], rev[2500], checksum(rev));
|
|
let ok = true;
|
|
for (let i = 0; i < rev.length; i++) if (rev[i] !== 4999 - i) ok = false;
|
|
console.log("reverse-order", ok);
|
|
|
|
// Several values at a time keep their argument order.
|
|
const many: number[] = [];
|
|
for (let i = 0; i < 300; i++) many.unshift(i, i + 0.5, -i);
|
|
console.log("many", many.length, many.slice(0, 6).join(","), many.slice(-3).join(","), checksum(many));
|
|
|
|
// Spread unshift, including the array itself.
|
|
const sp: number[] = [];
|
|
for (let i = 0; i < 20; i++) sp.push(i);
|
|
const extra = [100, 101, 102];
|
|
for (let i = 0; i < 5; i++) sp.unshift(...extra);
|
|
console.log("spread", sp.length, sp.slice(0, 7).join(","), sp[sp.length - 1]);
|
|
sp.unshift(...sp);
|
|
console.log("self-spread", sp.length, sp[0], sp[35], sp[69], checksum(sp));
|
|
|
|
// A deque: values enter at both ends and leave at both ends.
|
|
const dq: number[] = [];
|
|
const out: number[] = [];
|
|
for (let i = 0; i < 4000; i++) {
|
|
if (i % 3 === 0) dq.unshift(i);
|
|
else dq.push(i);
|
|
if (i % 5 === 0 && dq.length > 0) out.push(dq.shift()!);
|
|
if (i % 7 === 0 && dq.length > 0) out.push(dq.pop()!);
|
|
if (i % 11 === 0) dq.unshift(-i, -i - 1);
|
|
}
|
|
let iterated = 0;
|
|
for (const x of dq) iterated += x;
|
|
console.log("deque", dq.length, dq[0], dq[dq.length - 1], checksum(dq), checksum(out), iterated);
|
|
console.log("deque-search", dq.indexOf(-11), dq.lastIndexOf(3), dq.includes(3999), dq.at(-2));
|
|
dq.splice(0, 100);
|
|
dq.splice(10, 5, 1, 2, 3);
|
|
dq.unshift(...dq.splice(dq.length - 4, 4));
|
|
console.log("deque-splice", dq.length, dq.slice(0, 8).join(","), checksum(dq));
|
|
|
|
// Strings in a deque: the array owns every remaining element.
|
|
const words: string[] = [];
|
|
for (let i = 0; i < 200; i++) {
|
|
words.unshift("w" + i);
|
|
if (i % 4 === 0) words.push("t" + i);
|
|
if (i % 9 === 0) words.shift();
|
|
}
|
|
console.log("words", words.length, words[0], words[words.length - 1], words.slice(50, 53).join(","));
|
|
console.log("words-join", words.join("").length, words.filter((w) => w.startsWith("t")).length);
|
|
|
|
// Holes stay holes when values are unshifted in front of them.
|
|
const holed: (number | undefined)[] = [];
|
|
for (let i = 0; i < 30; i++) holed.push(i);
|
|
holed.length = 34;
|
|
holed[32] = 32;
|
|
holed.copyWithin(5, 33, 34);
|
|
for (let i = 0; i < 20; i++) holed.unshift(-i);
|
|
const marks: string[] = [];
|
|
for (let i = 0; i < holed.length; i++) marks.push(i in holed ? "v" : "_");
|
|
console.log("holed", holed.length, marks.join(""), holed[24], 25 in holed, holed[52]);
|
|
holed.length = 10;
|
|
holed.unshift(1, 2);
|
|
console.log("holed-trim", holed.join(","));
|