UNPKG

@thi.ng/transducers

Version:

Collection of ~170 lightweight, composable transducers, reducers, generators, iterators for functional data transformations

126 lines (125 loc) 3.36 kB
import { isArray } from "@thi.ng/checks/is-array"; import { identity } from "@thi.ng/compose/identity"; import { illegalState } from "@thi.ng/errors/illegal-state"; import { __iter, iterator } from "./iterator.js"; import { isReduced } from "./reduced.js"; function partitionSync(...args) { const iter = __iter(partitionSync, args, iterator); if (iter) return iter; const { key = identity, mergeOnly = false, reset = true, all = true, backPressure = 0 } = args[1]; const requiredKeys = isArray(args[0]) ? new Set(args[0]) : args[0]; const currKeys = /* @__PURE__ */ new Set(); const cache = /* @__PURE__ */ new Map(); let curr = {}; const xform = ([init, complete, reduce]) => { let first = true; if (mergeOnly || backPressure < 1) { return [ init, (acc) => { if (reset && all && currKeys.size > 0 || !reset && first) { acc = reduce(acc, curr); curr = {}; currKeys.clear(); first = false; } return complete(acc); }, (acc, x) => { const k = key(x); if (requiredKeys.has(k)) { curr[k] = x; currKeys.add(k); if (mergeOnly || __requiredInputs(requiredKeys, currKeys)) { acc = reduce(acc, curr); first = false; if (reset) { curr = {}; currKeys.clear(); } else { curr = { ...curr }; } } } return acc; } ]; } else { return [ init, (acc) => { if (all && currKeys.size > 0) { acc = reduce(acc, __collect(cache, currKeys)); cache.clear(); currKeys.clear(); } return complete(acc); }, (acc, x) => { const k = key(x); if (requiredKeys.has(k)) { let slot = cache.get(k); !slot && cache.set(k, slot = []); slot.length >= backPressure && illegalState( `max back pressure (${backPressure}) exceeded for input: ${String( k )}` ); slot.push(x); currKeys.add(k); while (__requiredInputs(requiredKeys, currKeys)) { acc = reduce(acc, __collect(cache, currKeys)); first = false; if (isReduced(acc)) break; } } return acc; } ]; } }; xform.keys = () => requiredKeys; xform.clear = () => { cache.clear(); requiredKeys.clear(); currKeys.clear(); curr = {}; }; xform.add = (id) => { requiredKeys.add(id); }; xform.delete = (id, clean = true) => { cache.delete(id); requiredKeys.delete(id); if (clean) { currKeys.delete(id); delete curr[id]; } }; return xform; } const __requiredInputs = (required, curr) => { if (curr.size < required.size) return false; for (const id of required) { if (!curr.has(id)) return false; } return true; }; const __collect = (cache, currKeys) => { const curr = {}; for (const id of currKeys) { const slot = cache.get(id); curr[id] = slot.shift(); !slot.length && currKeys.delete(id); } return curr; }; export { partitionSync };