Files
Endoleap/src/lib/canvas-runtime/structures.ts
T

67 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* runtime 使用的基础调度容器,不包含任务状态事实:FIFO 存可执行顺序,min-heap 存优先项。
* 两者都是内存结构,ledger/checkpoint 才负责可恢复事实;容器本身不去重、不校验依赖或执行网络。
*/
/** FIFO with amortized O(1) removal, without Array.shift on each item. */
/** 当前接口是先进先出队列:push 入尾、pop 出头,并非 history 的后进先出 stack。
* head 游标避免每次 Array.shift 搬动所有元素,周期压缩使出队摊销 O(1)。 */
export function createDeque<T>() {
// 已出队区间保留到下一次压缩/clear;有效长度为 items.length-head。
let items: T[] = [], head = 0;
return {
/** 有效未消费数量,不包含 head 前已取出的槽位。 */
get size() { return items.length - head; },
/** 追加队尾,不处理重复值;queued Set 等去重策略由上层维护。 */
push(value: T) { items.push(value); },
/** 查看最早未消费项,不移动 head。 */
peek(): T | undefined { return items[head]; },
/** 取出队头;空队列返回 undefined,已消费量较大且过半时压缩数组。 */
pop(): T | undefined {
if (head === items.length) return undefined;
const value = items[head++];
if (head > 1024 && head * 2 >= items.length) { items = items.slice(head); head = 0; }
return value;
},
/** 同时丢弃底层数组和游标,释放旧任务引用。 */
clear() { items = []; head = 0; },
/** 返回有效区间的数组副本,外部改副本不会更改队列成员。 */
values() { return items.slice(head); },
};
}
/** 数组实现二叉最小堆,compare<0 表示左项优先;peek O(1),push/pop O(log n)。
* 相等优先级不保证插入稳定性,上层若需要 FIFO tie-break 必须把序列写进 comparator。 */
export function createMinHeap<T>(compare: (left: T, right: T) => number) {
// 父下标 (i-1)>>1,左右孩子 2i+1/2i+2;堆序只要求父不大于孩子,不是全数组排序。
const items: T[] = [];
return {
/** 当前堆条目数,包含上层可能尚未清理的过期条目。 */
get size() { return items.length; },
/** 查看最优项,不移除;任务是否过期仍由调度器校验。 */
peek(): T | undefined { return items[0]; },
/** 新值从末端向上筛选,把较大的祖先下移到空位,最后写入新值。 */
push(value: T) {
let index = items.length; items.push(value);
while (index > 0) { const parent = (index - 1) >> 1; if (compare(items[parent], value) <= 0) break; items[index] = items[parent]; index = parent; }
items[index] = value;
},
pop(): T | undefined {
// 出堆:取根并移走末项,再将末项沿较小孩子向下筛选,恢复父≤孩子的不变量。
if (!items.length) return undefined;
const first = items[0], last = items.pop()!;
if (items.length) {
let index = 0;
while (index * 2 + 1 < items.length) {
let child = index * 2 + 1;
if (child + 1 < items.length && compare(items[child + 1], items[child]) < 0) child++;
if (compare(last, items[child]) <= 0) break;
items[index] = items[child]; index = child;
}
items[index] = last;
}
return first;
},
/** 清空全部条目;不会替任务执行取消或修改 ledger 状态。 */
clear() { items.length = 0; },
};
}