// Copy all of the elements in the iterator, finishing before indexAfterCopy. // If indexAfterCopy is array.Length, we'll finish copying at the end of the array. // The reason we take an ending index as opposed to a starting one is because // we only hold a reference to the most recently concat'd collection. So to start // copying at a certain index, we'd have to re-walk the linked list of iterators // all the way back to the least recent one, and repeat that for all of the // collections we hold. private void CopyBefore(TSource[] array, int indexAfterCopy) { Debug.Assert(array != null); Debug.Assert(indexAfterCopy >= 0 && indexAfterCopy <= array.Length); Debug.Assert(indexAfterCopy >= Count); // Copy the items from this collection, which is the last // one that was concatenated int copied = _next.Count; _next.CopyTo(array, indexAfterCopy - copied); ConcatIterator <TSource> previous = _previous; ConcatNCollectionIterator <TSource> previousN; while ((previousN = previous as ConcatNCollectionIterator <TSource>) != null) { checked { copied += previousN._next.Count; } previousN._next.CopyTo(array, indexAfterCopy - copied); previous = previousN._previous; } // We've reached the first 2 collections that were concatenated var previous2 = (Concat2CollectionIterator <TSource>)previous; copied += previous2.Count; Debug.Assert(copied == Count); // We should have copied all the elements previous2.CopyTo(array, indexAfterCopy - copied); }
internal ConcatNEnumerableIterator(ConcatIterator <TSource> previousConcat, IEnumerable <TSource> next, int nextIndex) { Debug.Assert(previousConcat != null); Debug.Assert(next != null); Debug.Assert(nextIndex >= 2); _previousConcat = previousConcat; _next = next; _nextIndex = nextIndex; }
internal ConcatNCollectionIterator(ConcatIterator <TSource> previous, ICollection <TSource> next, int nextIndex) { Debug.Assert(previous != null); Debug.Assert(previous is Concat2CollectionIterator <TSource> || previous is ConcatNCollectionIterator <TSource>); Debug.Assert(next != null); Debug.Assert(nextIndex >= 2); _previous = previous; _next = next; _nextIndex = nextIndex; }
/// <summary> /// Initializes a new instance of the <see cref="ConcatNIterator{TSource}"/> class. /// </summary> /// <param name="tail">The linked list of previous sources.</param> /// <param name="head">The source associated with this iterator.</param> /// <param name="headIndex">The logical index associated with this iterator.</param> /// <param name="hasOnlyCollections"> /// <c>true</c> if all sources this iterator concatenates implement <see cref="ICollection{TSource}"/>; /// otherwise, <c>false</c>. /// </param> internal ConcatNIterator(ConcatIterator <TSource> tail, IEnumerable <TSource> head, int headIndex, bool hasOnlyCollections) { Debug.Assert(tail != null); Debug.Assert(head != null); Debug.Assert(headIndex >= 2); _tail = tail; _head = head; _headIndex = headIndex; _hasOnlyCollections = hasOnlyCollections; }
internal override IEnumerable <TSource> GetEnumerable(int index) { if (index > _nextIndex) { return(null); } // Walk back through the chain of ConcatNIterators looking for the one // that has its _nextIndex equal to index. If we don't find one, then it // must be prior to any of them, so call GetEnumerable on the previous // Concat2Iterator. This avoids a deep recursive call chain. ConcatNEnumerableIterator <TSource> current = this; while (true) { if (index == current._nextIndex) { return(current._next); } ConcatIterator <TSource> previous = current._previousConcat; var previousEnumerables = previous as ConcatNEnumerableIterator <TSource>; if (previousEnumerables != null) { current = previousEnumerables; continue; } var previousCollections = previous as ConcatNCollectionIterator <TSource>; if (previousCollections != null) { // Since ConcatNCollectionIterator.GetEnumerable does not call into this method, // it is safe to call GetEnumerable on it here. It also makes things faster, since // the above type-cast will only ever be run once per call of this method. return(previousCollections.GetEnumerable(index)); } // We've reached the tail of the linked list, which contains the first 2 enumerables. Debug.Assert(previous is Concat2EnumerableIterator <TSource> || previous is Concat2CollectionIterator <TSource>); Debug.Assert(index == 0 || index == 1); return(previous.GetEnumerable(index)); } }