Skip to content

Commit 65b0f48

Browse files
authored
Merge pull request #2038 from alexvictoor/fix-issue-1915
2 parents b3a1c9f + 61d90ab commit 65b0f48

File tree

3 files changed

+138
-21
lines changed

3 files changed

+138
-21
lines changed

__tests__/concat.ts

+39-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { is, List, Seq, Set } from 'immutable';
1+
import { List, Seq, Set } from 'immutable';
22

33
describe('concat', () => {
44
it('concats two sequences', () => {
55
const a = Seq([1, 2, 3]);
66
const b = Seq([4, 5, 6]);
7-
expect(is(a.concat(b), Seq([1, 2, 3, 4, 5, 6]))).toBe(true);
87
expect(a.concat(b).size).toBe(6);
98
expect(a.concat(b).toArray()).toEqual([1, 2, 3, 4, 5, 6]);
109
});
@@ -181,4 +180,42 @@ describe('concat', () => {
181180
expect(i.get(-4)).toBe(-9);
182181
expect(i.get(-5, 888)).toBe(888);
183182
});
183+
184+
it('should iterate on many concatenated sequences', () => {
185+
let meta = Seq();
186+
187+
for (let i = 0; i < 10000; ++i) {
188+
meta = meta.concat(i) as Seq<unknown, unknown>; // TODO fix typing
189+
}
190+
191+
expect(meta.toList().size).toBe(10000);
192+
});
193+
194+
it('should handle iterator on many concatenated sequences', () => {
195+
const nbLoops = 10000;
196+
let meta = Seq();
197+
for (let i = 1; i < nbLoops; i++) {
198+
meta = meta.concat(i) as Seq<unknown, unknown>; // TODO fix typing
199+
}
200+
const it = meta[Symbol.iterator]();
201+
let done = false;
202+
let i = 0;
203+
while (!done) {
204+
const result = it.next();
205+
i++;
206+
done = !!result.done;
207+
}
208+
expect(i).toBe(nbLoops);
209+
});
210+
211+
it('should iterate on reverse order on concatenated sequences', () => {
212+
let meta = Seq([1]);
213+
meta = meta.concat(42);
214+
const it = meta.reverse()[Symbol.iterator]();
215+
const result = it.next();
216+
expect(result).toEqual({
217+
done: false,
218+
value: 42,
219+
});
220+
});
184221
});

src/Iterator.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ Iterator.prototype[ITERATOR_SYMBOL] = function () {
2929
};
3030

3131
export function iteratorValue(type, k, v, iteratorResult) {
32-
const value = type === 0 ? k : type === 1 ? v : [k, v];
32+
const value =
33+
type === ITERATE_KEYS ? k : type === ITERATE_VALUES ? v : [k, v];
3334
iteratorResult
3435
? (iteratorResult.value = value)
3536
: (iteratorResult = {

src/Operations.js

+97-18
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import {
1313
IndexedCollection,
1414
} from './Collection';
1515
import { isCollection } from './predicates/isCollection';
16-
import { isKeyed } from './predicates/isKeyed';
17-
import { isIndexed } from './predicates/isIndexed';
16+
import { IS_KEYED_SYMBOL, isKeyed } from './predicates/isKeyed';
17+
import { IS_INDEXED_SYMBOL, isIndexed } from './predicates/isIndexed';
1818
import { isOrdered, IS_ORDERED_SYMBOL } from './predicates/isOrdered';
1919
import { isSeq } from './predicates/isSeq';
2020
import {
@@ -587,6 +587,100 @@ export function skipWhileFactory(collection, predicate, context, useKeys) {
587587
return skipSequence;
588588
}
589589

590+
class ConcatSeq extends Seq {
591+
constructor(iterables) {
592+
this._wrappedIterables = iterables.flatMap(iterable => {
593+
if (iterable._wrappedIterables) {
594+
return iterable._wrappedIterables;
595+
}
596+
return [iterable];
597+
});
598+
this.size = this._wrappedIterables.reduce((sum, iterable) => {
599+
if (sum !== undefined) {
600+
const size = iterable.size;
601+
if (size !== undefined) {
602+
return sum + size;
603+
}
604+
}
605+
}, 0);
606+
this[IS_KEYED_SYMBOL] = this._wrappedIterables[0][IS_KEYED_SYMBOL];
607+
this[IS_INDEXED_SYMBOL] = this._wrappedIterables[0][IS_INDEXED_SYMBOL];
608+
this[IS_ORDERED_SYMBOL] = this._wrappedIterables[0][IS_ORDERED_SYMBOL];
609+
}
610+
611+
__iterateUncached(fn, reverse) {
612+
if (this._wrappedIterables.length === 0) {
613+
return;
614+
}
615+
616+
if (reverse) {
617+
return this.cacheResult().__iterate(fn, reverse);
618+
}
619+
620+
let iterableIndex = 0;
621+
const useKeys = isKeyed(this);
622+
const iteratorType = useKeys ? ITERATE_ENTRIES : ITERATE_VALUES;
623+
let currentIterator = this._wrappedIterables[iterableIndex].__iterator(
624+
iteratorType,
625+
reverse
626+
);
627+
628+
let keepGoing = true;
629+
let index = 0;
630+
while (keepGoing) {
631+
let next = currentIterator.next();
632+
while (next.done) {
633+
iterableIndex++;
634+
if (iterableIndex === this._wrappedIterables.length) {
635+
return index;
636+
}
637+
currentIterator = this._wrappedIterables[iterableIndex].__iterator(
638+
iteratorType,
639+
reverse
640+
);
641+
next = currentIterator.next();
642+
}
643+
const fnResult = useKeys
644+
? fn(next.value[1], next.value[0], this)
645+
: fn(next.value, index, this);
646+
keepGoing = fnResult !== false;
647+
index++;
648+
}
649+
return index;
650+
}
651+
652+
__iteratorUncached(type, reverse) {
653+
if (this._wrappedIterables.length === 0) {
654+
return new Iterator(iteratorDone);
655+
}
656+
657+
if (reverse) {
658+
return this.cacheResult().__iterator(type, reverse);
659+
}
660+
661+
let iterableIndex = 0;
662+
let currentIterator = this._wrappedIterables[iterableIndex].__iterator(
663+
type,
664+
reverse
665+
);
666+
return new Iterator(() => {
667+
let next = currentIterator.next();
668+
while (next.done) {
669+
iterableIndex++;
670+
if (iterableIndex === this._wrappedIterables.length) {
671+
return next;
672+
}
673+
currentIterator = this._wrappedIterables[iterableIndex].__iterator(
674+
type,
675+
reverse
676+
);
677+
next = currentIterator.next();
678+
}
679+
return next;
680+
});
681+
}
682+
}
683+
590684
export function concatFactory(collection, values) {
591685
const isKeyedCollection = isKeyed(collection);
592686
const iters = [collection]
@@ -618,22 +712,7 @@ export function concatFactory(collection, values) {
618712
}
619713
}
620714

621-
let concatSeq = new ArraySeq(iters);
622-
if (isKeyedCollection) {
623-
concatSeq = concatSeq.toKeyedSeq();
624-
} else if (!isIndexed(collection)) {
625-
concatSeq = concatSeq.toSetSeq();
626-
}
627-
concatSeq = concatSeq.flatten(true);
628-
concatSeq.size = iters.reduce((sum, seq) => {
629-
if (sum !== undefined) {
630-
const size = seq.size;
631-
if (size !== undefined) {
632-
return sum + size;
633-
}
634-
}
635-
}, 0);
636-
return concatSeq;
715+
return new ConcatSeq(iters);
637716
}
638717

639718
export function flattenFactory(collection, depth, useKeys) {

0 commit comments

Comments
 (0)