@thi.ng/transducers
Version:
Collection of ~170 lightweight, composable transducers, reducers, generators, iterators for functional data transformations
126 lines (125 loc) • 3.36 kB
JavaScript
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
};