import { Timestamp, timestampCompare } from "../common.ts"; export type CausalTreeOp = T & { at: Timestamp; parent?: CausalTreeOp }; // parent is referred to via timestamp instead of reference here // makes the api simpler export type WeakCausalTreeOp = T & { at: Timestamp; parent?: Timestamp }; export type AnyCausalTreeOp = CausalTreeOp | WeakCausalTreeOp; export class CausalTree { operations: CausalTreeOp[] = []; clock: number = 0; /** WARN: mutates 'op' for performance (in-place conversion from weak op to strong) */ apply(op: AnyCausalTreeOp): number { const opParent = op.parent; const parentOpIdx = this.operations.findIndex( Array.isArray(opParent) ? it => timestampCompare(it.at, opParent) === 0 : it => it === opParent, ); if (opParent && parentOpIdx === -1) throw new Error("parent was not found in op log"); let idx = parentOpIdx + 1; for (; idx < this.operations.length; idx++) { const curr = this.operations[idx]; if (timestampCompare(curr.at, op.at) < 0) break; } const storedOp = op as CausalTreeOp; storedOp.parent = this.operations[parentOpIdx]; this.operations.splice(idx, 0, storedOp); this.clock = Math.max(this.clock, storedOp.at[1]); return idx; } static toWeakOp(op: CausalTreeOp): WeakCausalTreeOp { return { ...op, parent: op.parent?.at }; } }