Skip to content

Commit 2f213af

Browse files
update implementation (incorrectly using yield*)
1 parent 26bd708 commit 2f213af

File tree

2 files changed

+69
-125
lines changed

2 files changed

+69
-125
lines changed

src/index.ts

Lines changed: 20 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,70 +4,31 @@ if (typeof Iterator === 'undefined' || Iterator == null) {
44
globalThis.Iterator = function() {};
55
}
66

7-
function getIteratorFlattenable<A>(obj: IteratorOrIterable<A>, stringHandling: 'iterate-strings' | 'reject-strings'): Iterator<A>
8-
function getIteratorFlattenable(obj: any, stringHandling: 'iterate-strings' | 'reject-strings'): Iterator<unknown>
9-
function getIteratorFlattenable(obj: any, stringHandling: 'iterate-strings' | 'reject-strings'): Iterator<unknown> {
10-
if (Object(obj) !== obj) {
11-
if (stringHandling === 'reject-strings' || typeof obj != 'string') {
12-
throw new TypeError;
13-
}
14-
obj = Object(obj);
15-
}
16-
let iter = Symbol.iterator in obj ? obj[Symbol.iterator]() : obj as Iterator<unknown>;
17-
if (Object(iter) !== iter) {
18-
throw new TypeError;
19-
}
20-
return iter;
21-
}
22-
23-
type IteratorOrIterable<A> = Iterable<A> | Iterator<A>
24-
interface Iterable<T> {
25-
[Symbol.iterator](): Iterator<T, unknown, unknown>;
26-
}
27-
28-
function liftIterator<A>(iter: Iterator<A>): Iterable<A> {
29-
return { [Symbol.iterator]() { return iter; } };
30-
}
31-
32-
function concatImpl<A>(...iterators: Array<IteratorOrIterable<A>>): Generator<A>
7+
function concatImpl<A>(...iterables: Array<Iterable<A>>): Generator<A>
338
function concatImpl(): Generator<never>
34-
function concatImpl<A>(iteratorA: IteratorOrIterable<A>): Generator<A>
35-
function concatImpl<A, B>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>): Generator<A | B>
36-
function concatImpl<A, B, C>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>, iteratorC: IteratorOrIterable<C>): Generator<A | B | C>
37-
function concatImpl<A, B, C, D>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>, iteratorC: IteratorOrIterable<C>, iteratorD: IteratorOrIterable<D>): Generator<A | B | C | D>
38-
function concatImpl<A, B, C, D, E>(iteratorA: IteratorOrIterable<A>, iteratorB: IteratorOrIterable<B>, iteratorC: IteratorOrIterable<C>, iteratorD: IteratorOrIterable<D>, iteratorE: IteratorOrIterable<E>): Generator<A | B | C | D | E>
39-
function concatImpl(...iterators: Array<IteratorOrIterable<unknown>>): Generator<unknown>
40-
function* concatImpl(...iterators: Array<unknown>): Generator<unknown> {
41-
let i = 0;
42-
try {
43-
for (; i < iterators.length; ++i) {
44-
let iter = iterators[i];
45-
yield* liftIterator(getIteratorFlattenable(iter, 'reject-strings'));
46-
}
47-
} finally {
48-
let err = null, hasErr = false;
49-
for (++i; i < iterators.length; ++i) {
50-
try {
51-
let obj = iterators[i];
52-
if (obj != null && (typeof obj === 'object' || typeof obj === 'function')) {
53-
let iter = obj as Iterator<unknown>;
54-
if (typeof iter.next === 'function') {
55-
iter.return?.();
56-
}
57-
}
58-
} catch (e) {
59-
if (!hasErr) {
60-
hasErr = true;
61-
err = e;
62-
}
63-
}
64-
}
65-
if (hasErr) throw err;
9+
function concatImpl<A>(iterableA: Iterable<A>): Generator<A>
10+
function concatImpl<A, B>(iterableA: Iterable<A>, iterableB: Iterable<B>): Generator<A | B>
11+
function concatImpl<A, B, C>(iterableA: Iterable<A>, iterableB: Iterable<B>, iterableC: Iterable<C>): Generator<A | B | C>
12+
function concatImpl<A, B, C, D>(iterableA: Iterable<A>, iterableB: Iterable<B>, iterableC: Iterable<C>, iterableD: Iterable<D>): Generator<A | B | C | D>
13+
function concatImpl<A, B, C, D, E>(iterableA: Iterable<A>, iterableB: Iterable<B>, iterableC: Iterable<C>, iterableD: Iterable<D>, iterableE: Iterable<E>): Generator<A | B | C | D | E>
14+
function concatImpl(...iterables: Array<Iterable<unknown>>): Generator<unknown>
15+
function concatImpl(...iterables: Array<unknown>): Generator<unknown> {
16+
const openMethods = [];
17+
for (let iterable of iterables) {
18+
if (iterable == null || Object(iterable) !== iterable) throw new TypeError;
19+
let openMethod = (iterable as any)[Symbol.iterator];
20+
if (typeof openMethod !== 'function') throw new TypeError;
21+
openMethods.push({openMethod, iterable});
6622
}
23+
return function*() {
24+
for (let { openMethod, iterable } of openMethods) {
25+
yield* { [Symbol.iterator]() { return openMethod.call(iterable); } }
26+
}
27+
}();
6728
}
6829

6930
// NOTE: this line makes concat non-constructible, and gives it the appropriate name and length
70-
const concat = (...iterators: Array<IteratorOrIterable<unknown>>) => concatImpl(...iterators);
31+
const concat = (...iterators: Array<Iterable<unknown>>) => concatImpl(...iterators);
7132
Object.defineProperty(Iterator, 'concat', {
7233
configurable: true,
7334
writable: true,

test/index.mjs

Lines changed: 49 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -31,64 +31,46 @@ test('concat', async t => {
3131
});
3232

3333
test('concat does not iterate strings', async t => {
34-
let it = Iterator.concat("ab", "cd");
3534
assert.throws(
36-
() => Array.from(it),
35+
() => Iterator.concat("ab", "cd"),
3736
TypeError,
3837
);
3938
});
4039

41-
test('concat bare iterators', async t => {
42-
let count = 0;
43-
const iter = {
44-
next() {
45-
if (count < 6) {
46-
return { done: false, value: count++ };
47-
} else {
48-
return { done: true };
49-
}
40+
test('re-uses IteratorResult objects', async t => {
41+
const iterResult = { done: false, value: 0 };
42+
const iter = Iterator.concat({
43+
[Symbol.iterator]() {
44+
return {
45+
next() {
46+
return iterResult;
47+
},
48+
};
5049
},
51-
};
52-
assert.deepEqual(
53-
Array.from(Iterator.concat(
54-
iter,
55-
iter,
56-
)),
57-
[0, 1, 2, 3, 4, 5],
50+
});
51+
assert.equal(
52+
iter.next(),
53+
iterResult,
5854
);
5955
});
6056

61-
test('closes later iterators', async t => {
57+
test('closes open iterators', async t => {
6258
await t.test('stopped between iterators', () => {
6359
let returned = [];
6460
let concatted = Iterator.concat(
6561
[0, 1],
6662
[2, 3],
6763
{
68-
next() {
69-
return { done: false, value: 'a' };
70-
},
71-
return() {
72-
returned.push('a');
73-
return { done: true, value: undefined };
74-
},
75-
},
76-
{
77-
next() {
78-
return { done: false, value: 'b' };
79-
},
80-
return() {
81-
returned.push('b');
82-
return { done: true, value: undefined };
83-
},
84-
},
85-
{
86-
next() {
87-
return { done: false, value: 'c' };
88-
},
89-
return() {
90-
returned.push('c');
91-
return { done: true, value: undefined };
64+
[Symbol.iterator]() {
65+
return {
66+
next() {
67+
return { done: false, value: 4 };
68+
},
69+
return() {
70+
returned.push('a');
71+
return { done: true, value: undefined };
72+
},
73+
};
9274
},
9375
},
9476
);
@@ -98,7 +80,7 @@ test('closes later iterators', async t => {
9880
assert.equal(concatted.next().value, 3);
9981
assert.deepEqual(returned, []);
10082
concatted.return();
101-
assert.deepEqual(returned, ['a', 'b', 'c']);
83+
assert.deepEqual(returned, []);
10284
});
10385

10486
await t.test('stopped during iteration', () => {
@@ -107,30 +89,29 @@ test('closes later iterators', async t => {
10789
[0, 1],
10890
[2, 3],
10991
{
110-
next() {
111-
return { done: false, value: 4 };
112-
},
113-
return() {
114-
returned.push('a');
115-
return { done: true, value: undefined };
92+
[Symbol.iterator]() {
93+
return {
94+
next() {
95+
return { done: false, value: 4 };
96+
},
97+
return() {
98+
returned.push('a');
99+
return { done: true, value: undefined };
100+
},
101+
};
116102
},
117103
},
118104
{
119-
next() {
120-
return { done: false, value: 'b' };
121-
},
122-
return() {
123-
returned.push('b');
124-
return { done: true, value: undefined };
125-
},
126-
},
127-
{
128-
next() {
129-
return { done: false, value: 'c' };
130-
},
131-
return() {
132-
returned.push('c');
133-
return { done: true, value: undefined };
105+
[Symbol.iterator]() {
106+
return {
107+
next() {
108+
return { done: false, value: 'b' };
109+
},
110+
return() {
111+
returned.push('b');
112+
return { done: true, value: undefined };
113+
},
114+
};
134115
},
135116
},
136117
);
@@ -141,6 +122,8 @@ test('closes later iterators', async t => {
141122
assert.equal(concatted.next().value, 4);
142123
assert.deepEqual(returned, []);
143124
concatted.return();
144-
assert.deepEqual(returned, ['a', 'b', 'c']);
125+
assert.deepEqual(returned, ['a']);
126+
concatted.return();
127+
assert.deepEqual(returned, ['a']);
145128
});
146129
});

0 commit comments

Comments
 (0)