67 lines
3.4 KiB
TypeScript
67 lines
3.4 KiB
TypeScript
/**
|
||
* 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; },
|
||
};
|
||
}
|