Beispiel #1
0
            public override int GetCount(bool onlyIfCheap)
            {
                if (onlyIfCheap && !_hasOnlyCollections)
                {
                    return(-1);
                }

                int count = 0;
                ConcatNIterator <TSource>?node, previousN = this;

                do
                {
                    node = previousN;
                    IEnumerable <TSource> source = node._head;

                    // Enumerable.Count() handles ICollections in O(1) time, but check for them here anyway
                    // to avoid a method call because 1) they're common and 2) this code is run in a loop.
                    var collection = source as ICollection <TSource>;
                    Debug.Assert(!_hasOnlyCollections || collection != null);
                    int sourceCount = collection?.Count ?? source.Count();

                    checked
                    {
                        count += sourceCount;
                    }
                }while ((previousN = node.PreviousN) != null);

                Debug.Assert(node._tail is Concat2Iterator <TSource>);
                return(checked (count + node._tail.GetCount(onlyIfCheap)));
            }
Beispiel #2
0
            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.
                ConcatNIterator <TSource> current = this;

                while (true)
                {
                    if (index == current._nextIndex)
                    {
                        return(current._next);
                    }

                    ConcatNIterator <TSource> prevN = current._previousConcat as ConcatNIterator <TSource>;
                    if (prevN != null)
                    {
                        current = prevN;
                        continue;
                    }

                    Debug.Assert(current._previousConcat is Concat2Iterator <TSource>);
                    Debug.Assert(index == 0 || index == 1);
                    return(current._previousConcat.GetEnumerable(index));
                }
            }
Beispiel #3
0
            private TSource[] PreallocatingToArray()
            {
                // If there are only ICollections in this iterator, then we can just get the count, preallocate the
                // array, and copy them as we go. This has better time complexity than continuously re-walking the
                // linked list via GetEnumerable, and better memory usage than buffering the collections.

                Debug.Assert(_hasOnlyCollections);

                int count = GetCount(onlyIfCheap: true);

                Debug.Assert(count >= 0);

                if (count == 0)
                {
                    return(Array.Empty <TSource>());
                }

                var array      = new TSource[count];
                int arrayIndex = array.Length; // We start copying in collection-sized chunks from the end of the array.

                ConcatNIterator <TSource>?node, previousN = this;

                do
                {
                    node = previousN;
                    ICollection <TSource> source = (ICollection <TSource>)node._head;
                    int sourceCount = source.Count;
                    if (sourceCount > 0)
                    {
                        checked
                        {
                            arrayIndex -= sourceCount;
                        }
                        source.CopyTo(array, arrayIndex);
                    }
                }while ((previousN = node.PreviousN) != null);

                var previous2   = (Concat2Iterator <TSource>)node._tail;
                var second      = (ICollection <TSource>)previous2._second;
                int secondCount = second.Count;

                if (secondCount > 0)
                {
                    second.CopyTo(array, checked (arrayIndex - secondCount));
                }

                if (arrayIndex > secondCount)
                {
                    var first = (ICollection <TSource>)previous2._first;
                    first.CopyTo(array, 0);
                }

                return(array);
            }
Beispiel #4
0
            internal override IEnumerable <TSource> GetEnumerable(int index)
            {
                Debug.Assert(index >= 0);

                if (index > _headIndex)
                {
                    return(null);
                }

                ConcatNIterator <TSource> node, previousN = this;

                do
                {
                    node = previousN;
                    if (index == node._headIndex)
                    {
                        return(node._head);
                    }
                }while ((previousN = node.PreviousN) != null);

                Debug.Assert(index == 0 || index == 1);
                Debug.Assert(node._tail is Concat2Iterator <TSource>);
                return(node._tail.GetEnumerable(index));
            }