import { add, emptySet, forEach } from "../structures/set.js"; import { deepEqual } from "../util/util.js"; import {inspect} from "node:util"; // UUID -> Value -> Slot export const newSlot = uuid => value => ({ overwrites: uuid, value, depth: 1, [inspect.custom]: (depth, options, inspect) => `newSlot(${inspect(uuid)}, ${inspect(value)})`, }); export const compareSlots = compareElems => slotA => slotB => { if (slotA.depth < slotB.depth) { return -1; } if (slotB.depth < slotA.depth) { return 1; } return compareValues(compareElems)(slotA.value)(slotB.value); }; export const compareValues = compareElems => valA => valB => { if (valA.kind < valB.kind) { return -1; } if (valB.kind < valA.kind) { return 1; } if (valA.kind === "literal") { return compareElems(valA.out)(valB.out); } if (valA.kind === "read") { return compareSlots(compareElems)(valA.slot)(valB.slot); } if (valA.kind === "transformation") { const cmpIn = compareValues(compareElems)(valA.in)(valB.in); if (cmpIn !== 0) { return cmpIn; } return compareValues(compareElems)(valA.fn)(valB.fn); } }; // Slot -> Value -> Slot export const overwrite = slot => value => ({ overwrites: slot, value, depth: slot.depth + 1, // [inspect.custom]: (depth, options, inspect) => `overwrite(${inspect(slot)}, ${inspect(value)})`, }); const findLCA = slotA => slotB => { if (deepEqual(slotA, slotB)) { return slotA; } if (slotA.depth > slotB.depth) { return findLCA(slotA.overwrites)(slotB) } else { return findLCA(slotB.overwrites)(slotA) } }; // Slot -> Slot -> MergeResult export const merge = compareElems => slotA => slotB => { const lca = findLCA(slotA)(slotB); if (lca === undefined) { throw new Error("Could not find LCA"); } if (deepEqual(lca, slotA)) { return add(emptySet(compareSlots(compareElems)))(slotB); // return new Set([slotB]); // B is successor of A -> fast-forward } if (deepEqual(lca, slotB)) { return add(emptySet(compareSlots(compareElems)))(slotA); // return new Set([slotA]); // A is successor of B -> fast-forward } return add(add(emptySet(compareSlots(compareElems)))(slotA))(slotB); // return new Set([slotA, slotB]); }; // MergeResult -> MergeResult -> MergeResult export const merge2 = compareElems => mA => mB => { let result = emptySet(compareSlots(compareElems)); forEach(mA)(slotOfA => { forEach(mB)(slotOfB => { const merged = merge(compareElems)(slotOfA)(slotOfB); forEach(merged)(merged => { result = add(result)(merged); }); }); }); return result; };