100 lines
2.8 KiB
TypeScript
Raw Normal View History

// SOURCE: ARCHITECTURE/32-LANGUAGE-OFFICIAL-13-IMPLEMENTATION-3.md
// AUTO-EXTRACTED - Do not edit directly. Edit the source document.
import type { Job } from "./types";
export interface Frontier {
push(job: Job): void;
pop(): Job | undefined;
size(): number;
clear(): void;
}
export class StackFrontier implements Frontier {
private xs: Job[] = [];
push(job: Job) { this.xs.push(job); }
pop() { return this.xs.pop(); }
size() { return this.xs.length; }
clear() { this.xs = []; }
}
export class QueueFrontier implements Frontier {
private xs: Job[] = [];
private head = 0;
push(job: Job) { this.xs.push(job); }
pop() {
if (this.head >= this.xs.length) return undefined;
const j = this.xs[this.head];
this.head += 1;
// compact occasionally
if (this.head > 1024 && this.head * 2 > this.xs.length) {
this.xs = this.xs.slice(this.head);
this.head = 0;
}
return j;
}
size() { return this.xs.length - this.head; }
clear() { this.xs = []; this.head = 0; }
}
export class PriorityFrontier implements Frontier {
// Max-heap by job.score (reference grade)
private heap: Job[] = [];
push(job: Job) { heapPush(this.heap, job); }
pop() { return heapPop(this.heap); }
size() { return this.heap.length; }
clear() { this.heap = []; }
}
function heapPush(heap: Job[], job: Job) {
heap.push(job);
let i = heap.length - 1;
while (i > 0) {
const p = Math.floor((i - 1) / 2);
if (heap[p].score >= heap[i].score) break;
[heap[p], heap[i]] = [heap[i], heap[p]];
i = p;
}
}
function heapPop(heap: Job[]): Job | undefined {
if (heap.length === 0) return undefined;
const top = heap[0];
const last = heap.pop()!;
if (heap.length > 0) {
heap[0] = last;
let i = 0;
while (true) {
const l = 2 * i + 1, r = 2 * i + 2;
let m = i;
if (l < heap.length && heap[l].score > heap[m].score) m = l;
if (r < heap.length && heap[r].score > heap[m].score) m = r;
if (m === i) break;
[heap[i], heap[m]] = [heap[m], heap[i]];
i = m;
}
}
return top;
}
export class BeamFrontier implements Frontier {
private heap: Job[] = [];
constructor(private readonly width: number) {}
push(job: Job) {
heapPush(this.heap, job);
if (this.heap.length > this.width) {
// drop worst by rebuilding heap after removing min:
// reference-grade: sort descending, truncate, rebuild
this.heap.sort((a, b) => b.score - a.score);
this.heap.length = this.width;
this.heap = this.heap.slice();
// rebuild heap structure
const xs = this.heap.slice().sort((a, b) => a.score - b.score);
this.heap = [];
for (const j of xs) heapPush(this.heap, j);
}
}
pop() { return heapPop(this.heap); }
size() { return this.heap.length; }
clear() { this.heap = []; }
}