asclasit
Version:
ASync CLasses + ASync ITerators
275 lines (219 loc) • 6.41 kB
JavaScript
const AsIt = require('./map');
const $ = require('../func');
async function* chunkByCount(iter, count) {
let buf = [];
for await (const item of iter) {
if (buf.push(item) === count) {
yield buf;
buf = [];
}
}
if (buf.length) yield buf;
}
async function* chunkByCountFunc(iter, msec, count, ...funcs) {
$._predicateFuncs(funcs);
let snap = msec && $.upMsec();
let desc = {buf: [], idx: 0, snap, iter, ctx: this};
for await (const item of iter) {
let newChunk = funcs.length ? item : 0;
for (const func of funcs) {
newChunk = await func.call(this, newChunk, item, desc);
}
if (msec && newChunk <= 0 && $.upMsec(desc.snap) > msec) {
newChunk = 1;
}
if (newChunk > 0 && desc.buf.length) {
yield desc.buf;
desc.buf = [];
}
if (msec) {
if (newChunk > 0) desc.snap = snap;
snap = $.upMsec();
}
if (desc.buf.push(item) === count || newChunk < 0) {
yield desc.buf;
desc.buf = [];
desc.snap = snap;
}
desc.idx++;
}
if (desc.buf.length) yield desc.buf;
}
AsIt.chain_(async function* chunk(iter, ...funcs) {
if (typeof funcs[0] === 'function') yield* chunkByCountFunc(iter, 0, 0, ...funcs);
else if (funcs[1] !== undefined) yield* chunkByCountFunc(iter, 0, ...funcs);
else yield* chunkByCount(iter, funcs[0]);
});
AsIt.chain_(async function* chunkMsec(iter, msec, ...funcs) {
if (typeof funcs[0] === 'function') yield* chunkByCountFunc(iter, msec, 0, ...funcs);
yield* chunkByCountFunc(iter, msec, ...funcs);
});
AsIt.chain_(async function* flatten(iter, depth) {
if (depth == null) { depth = 1; }
else if (depth === 0) { yield* iter; return; }
for await (const item of iter) {
const it = AsIt.getIter(item);
if (!it) yield item;
else if (depth === 1) yield* it;
else yield* flatten(it, depth - 1);
}
});
function isIter(itrb) {
const gen = AsIt.getGen(itrb);
if (!gen) return [itrb];
const iter = AsIt.getIter(gen);
return [itrb, iter, itrb != iter && gen, true];
}
function countIter(sum, i2) {
if (i2[1]) sum++;
return sum;
}
AsIt.chain_(async function* cut(iter, n) {
if (!n || !Number.isInteger(n)) return yield* iter;
let cutted;
if (n > 0) {
cutted = iter;
} else {
cutted = AsIt.map.gen.call(this, iter, n);
n = -n;
}
await AsIt.affwd(cutted, n);
yield* cutted;
});
AsIt.chain_(async function* zipt(...iters) {
const l = iters.length;
if (!l) return;
const its = iters.map(isIter);
let active = its.reduce(countIter, 0);
let safe;
try {
while (active) {
for (const it of its) {
if (it[1]) {
safe = true;
while (true) {
const [, iter, gen, first] = it;
let value, done;
try { ({value, done} = await iter.next()); }
catch (err) { it.fill(); throw err; }
if (done) {
if (first) { active--; it[3] = false; }
if (gen && safe) {
safe = false;
it[1] = AsIt.getIter(gen);
continue;
} else {
it.fill();
yield;
}
} else {
yield value;
}
break;
}
} else {
yield it[0];
}
}
}
/*} catch (err) {
for (const [, iter] of its) {
if (iter && iter.throw) try {
await iter.throw(err);
} catch (e) { console.log('???', e); err = e; }
}
throw err;*/
} finally {
for (const [, iter] of its) {
if (iter && iter.return) {
await iter.return();
}
}
}
});
AsIt.chain_(async function* zip(...iters) {
const l = iters.length;
if (!l) return;
const zipt = AsIt.zipt.gen.call(this, ...iters);
const cut = AsIt.cut.gen.call(this, zipt, -l);
yield* cut;
});
async function *partialDim(pfx, dim1, dim2, ...dims) {
const desc = {iter: dim1, ctx: this};
for await (const item of dim1) {
const out = [...pfx, item];
if (dim2) {
const iter = AsIt.getIter.call(this, dim2, false, out, desc);
yield* partialDim.call(this, out, iter || [dim2], ...dims);
} else {
yield out;
}
}
};
AsIt.chain_(async function* dim(...dims) {
const pfx = [];
yield* partialDim.call(this, pfx, ...dims);
});
AsIt.chain_(async function* sep(iter, gen, ...funcs) {
const desc = {iter, ctx: this};
let idx = 0;
for await (item of iter) {
if (idx) {
let v = true;
for (const func of funcs) v = await func.call(this, v, item, idx, desc);
if (v) {
const it = AsIt.getIter.call(this, gen, false, item, idx, desc);
if (it) yield* it; else yield gen;
}
}
yield item;
idx++;
}
});
AsIt.chain_(async function* sortedWith(inA, inB, func = $.numSort) {
const A = AsIt.from(inA);
const B = AsIt.from(inB);
let a, b;
try {
a = await A.read();
b = await B.read();
while (a !== $.eof && b !== $.eof) {
if (await func.call(this, a, b) > 0) { yield b; b = await B.read(); }
else { yield a; a = await A.read(); }
}
if (a === $.eof) while (b !== $.eof) { yield b; b = await B.read(); }
else while (a !== $.eof) { yield a; a = await A.read(); }
} finally {
try { if (a !== $.eof) await A.return(); } catch (err) { }
try { if (b !== $.eof) await B.return(); } catch (err) { }
}
});
AsIt.value_(async function sort(iter, func, opts = {}) {
if (typeof func !== 'function') {
opts = func;
func = $.numSort;
}
if (typeof opts !== 'object') opts = {limit: opts};
let {skip, limit, desc} = opts;
if (skip > 0 && limit > 0) limit += skip;
if (limit === 0) {
for await (const item of iter) break;
return [];
}
if (!(opts.limit > 0)) {
const res = [];
for await (const item of iter) res.push(item);
if (desc) res.sort($.neg_(func));
else res.sort(func);
if (skip) return res.slice(skip);
return res;
}
if (opts.filters) iter = AsIt.filter.gen.call(this, iter, ...opts.filters);
if (opts.filter !== undefined) iter = AsIt.filter.gen.call(this, iter, opts.filter);
const pq = new $.PQ.Limited({sort: func, limit, reverse: !opts.desc});
for await (const item of iter) pq.pushOne(item);
const res = pq.toArray();
if (skip) return res.slice(skip);
return res;
});
module.exports = AsIt;