Files
scriptc/benchmarks/runtime/workloads/optional-child-sets.ts
T
Chris Tate 6cc5345a41 Key Sets and Maps of identity-arm unions by their pointer representation
A union that is a Set element or a Map key was a tagged box in the whole
program, because the C map hashes and compares union keys by tag and
payload. One `Set<Node | undefined>` made every `Node | undefined` value
of the program a box, at every read.

A union whose arms all compare by identity (records, class instances,
arrays, functions), beside at most one undefined and one null arm, now
keeps its pointer representation in collections too. The map keys such a
union by reference: the pointer carries the identity, and NULL and the
null sentinel are two more distinct keys. Unions with a string or another
value arm keep their boxes, and library builds keep the earlier rule.

The tests of the box paths keep their unions boxed through a new
`boxedUnions` emission option instead of a Set of each union.
2026-10-28 16:22:38 -05:00

49 lines
1.6 KiB
TypeScript

// Syntax-tree walks through class nodes whose getters return optional
// children, in a program that also keeps a `Set` of the optional node type.
class TreeNode {
readonly kind: number;
private readonly kids: (TreeNode | undefined)[];
parentNode: TreeNode | undefined;
constructor(kind: number, kids: (TreeNode | undefined)[]) {
this.kind = kind;
this.kids = kids;
this.parentNode = undefined;
for (const kid of kids) if (kid !== undefined) kid.parentNode = this;
}
get left(): TreeNode | undefined {
return this.kids[0];
}
get right(): TreeNode | undefined {
return this.kids[1];
}
get parent(): TreeNode | undefined {
return this.parentNode;
}
}
function build(depth: number, seed: number): TreeNode {
if (depth === 0) return new TreeNode(seed % 7, [undefined, undefined]);
const right = seed % 11 === 0 ? undefined : build(depth - 1, seed * 7 + 3);
return new TreeNode(seed % 7, [build(depth - 1, seed * 5 + 1), right]);
}
function sumKinds(node: TreeNode | undefined): number {
let total = 0;
while (node !== undefined) {
total += node.kind;
const up = node.parent;
if (up !== undefined && up.kind === node.kind) total++;
total += sumKinds(node.right);
node = node.left;
}
return total;
}
const root = build(20, 1);
// The one Set of the optional node type.
const marked = new Set<TreeNode | undefined>([root, root.left, undefined]);
let total = 0;
const rounds = 30 * Number(process.argv[2] ?? "1");
for (let i = 0; i < rounds; i++) total += sumKinds(root);
console.log(total, marked.size, marked.has(root.right));