You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@annotator.apache.org by ra...@apache.org on 2021/04/18 21:49:24 UTC
[incubator-annotator] 02/02: Close source iterators on cartesian
exit
This is an automated email from the ASF dual-hosted git repository.
randall pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-annotator.git
commit 5ba4b0ad8cdf9ce1338bebc6f2b24ffe588b6f3e
Author: Randall Leeds <ra...@apache.org>
AuthorDate: Sun Apr 18 14:48:29 2021 -0700
Close source iterators on cartesian exit
---
packages/dom/src/range/cartesian.ts | 71 +++++++++++++++++--------------
packages/dom/test/range/cartesian.test.ts | 30 +++++++++++++
2 files changed, 68 insertions(+), 33 deletions(-)
diff --git a/packages/dom/src/range/cartesian.ts b/packages/dom/src/range/cartesian.ts
index 060a27b..00f88dc 100644
--- a/packages/dom/src/range/cartesian.ts
+++ b/packages/dom/src/range/cartesian.ts
@@ -38,46 +38,51 @@ export async function* cartesian<T>(
return generator();
});
- // Track the number of non-exhausted iterators.
- let active = iterators.length;
+ try {
+ // Track the number of non-exhausted iterators.
+ let active = iterators.length;
- // Track all the values of each iterator in a log.
- const logs = iterators.map(() => []) as T[][];
+ // Track all the values of each iterator in a log.
+ const logs = iterators.map(() => []) as T[][];
- // Track the promise of the next value of each iterator.
- const nexts = iterators.map((it) => it.next());
+ // Track the promise of the next value of each iterator.
+ const nexts = iterators.map((it) => it.next());
- // Iterate the values of all the iterators in parallel and yield tuples from
- // the partial product of each new value and the existing logs of the other
- // iterators.
- while (active) {
- // Wait for the next result.
- const result = await Promise.race(nexts);
- const { index } = result.value;
+ // Iterate the values of all the iterators in parallel and yield tuples from
+ // the partial product of each new value and the existing logs of the other
+ // iterators.
+ while (active) {
+ // Wait for the next result.
+ const result = await Promise.race(nexts);
+ const { index } = result.value;
- // If the iterator has exhausted all the values, set the promise
- // of its next value to never resolve.
- if (result.done) {
- active--;
- nexts[index] = new Promise(() => undefined);
- continue;
- }
+ // If the iterator has exhausted all the values, set the promise
+ // of its next value to never resolve.
+ if (result.done) {
+ active--;
+ nexts[index] = new Promise(() => undefined);
+ continue;
+ }
- // Append the new value to the log.
- const { value } = result.value;
- logs[index].push(value);
+ // Append the new value to the log.
+ const { value } = result.value;
+ logs[index].push(value);
- // Record the promise of the next value.
- nexts[index] = iterators[index].next();
+ // Record the promise of the next value.
+ nexts[index] = iterators[index].next();
- // Create a scratch input for computing a partial product.
- const scratch = [...logs];
- scratch[index] = [value];
+ // Create a scratch input for computing a partial product.
+ const scratch = [...logs];
+ scratch[index] = [value];
- // Synchronously compute and yield tuples of the partial product.
- yield* scratch.reduce(
- (acc, next) => acc.flatMap((v) => next.map((w) => [...v, w])),
- [[]] as T[][],
- );
+ // Synchronously compute and yield tuples of the partial product.
+ yield* scratch.reduce(
+ (acc, next) => acc.flatMap((v) => next.map((w) => [...v, w])),
+ [[]] as T[][],
+ );
+ }
+ } finally {
+ const closeAll = iterators.map((it, index) => it.return({ index }));
+ await Promise.all(closeAll);
}
}
diff --git a/packages/dom/test/range/cartesian.test.ts b/packages/dom/test/range/cartesian.test.ts
index 475bc79..ff0ff8a 100644
--- a/packages/dom/test/range/cartesian.test.ts
+++ b/packages/dom/test/range/cartesian.test.ts
@@ -56,4 +56,34 @@ describe('cartesian', () => {
assert.sameDeepMembers(actual, expected, 'yields the expected items');
});
+
+ it.only('re-raises exceptions and closes iterators', async () => {
+ let didClose = false;
+ const error = new Error();
+
+
+ async function* throws() {
+ yield 1;
+ throw error;
+ }
+
+ async function* works() {
+ try {
+ yield 2;
+ yield 3;
+ } finally {
+ didClose = true;
+ }
+ }
+
+ try {
+ // eslint-disable-next-line
+ const cart = cartesian(throws(), works());
+ await cart.next();
+ await cart.next();
+ } catch (e) {
+ assert.strictEqual(error, e, 're-raises an error from an iterable');
+ assert.isTrue(didClose, 'closes the iterators');
+ }
+ });
});