mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-28 06:53:42 +08:00
A typed number-key Map or Set that is boxed and cast back to Map<unknown, unknown> or Set<unknown> keeps its own storage, with 16-byte entries. Inline iteration over a checked collection used the 24-byte step, so it tested the wrong words for liveness and read past the entry array: a Set skipped entries and a Map aborted with "map iteration index out of range". The iteration step for a collection with checked keys now reads the map's key kind and takes the number-key step for SCR_MAP_KEY_F64 and the 24-byte step otherwise. Keys and values are at bytes 0 and 8 in both layouts, so the slot reads are unchanged. Typed collections keep their static step, and their IR is unchanged. scr_map.h asserts the key kind's offset and SCR_MAP_KEY_F64's value. set-checked-storage.ts iterates a number-key Set and a hashed number-key Map through their checked views, with deleted entries.
34 lines
1.4 KiB
TypeScript
34 lines
1.4 KiB
TypeScript
function opaque(value: unknown): unknown { return value; }
|
|
const source = new Set<unknown>([1, "one", 0n]);
|
|
const record = opaque({ values: source }) as { values: Set<unknown> };
|
|
console.log(record.values === source);
|
|
record.values.add(2);
|
|
const roundTrip = opaque(source) as Set<unknown>;
|
|
console.log(roundTrip === source, source.size, source.has(2), source.has(0n));
|
|
source.delete(1);
|
|
console.log(roundTrip.size, roundTrip.has(1));
|
|
console.log(String(opaque(source)), Object.prototype.toString.call(opaque(source)));
|
|
console.log("set");
|
|
|
|
// A typed number-key collection cast back to its checked form keeps its own
|
|
// storage; iteration visits its live entries in insertion order.
|
|
const numbers = new Set<number>([5, 6, 7.5, 8]);
|
|
numbers.delete(6);
|
|
const numberView = opaque(numbers) as Set<unknown>;
|
|
const seen: unknown[] = [];
|
|
for (const value of numberView) seen.push(value);
|
|
numberView.forEach((value) => seen.push(value));
|
|
console.log(numberView.size, seen.join(","), [...numberView].join(","));
|
|
const byId = new Map<number, string>();
|
|
for (let i = 0; i < 40; i++) byId.set(i * 1000 + 0.5, `v${i}`);
|
|
byId.delete(1000.5);
|
|
byId.delete(39000.5);
|
|
const mapView = opaque(byId) as Map<unknown, unknown>;
|
|
let keys = 0;
|
|
let last = "";
|
|
for (const [key, value] of mapView) {
|
|
keys += key as number;
|
|
last = value as string;
|
|
}
|
|
console.log(mapView.size, keys, last, [...mapView.keys()].length, [...mapView.values()][0]);
|