diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d50a098ab0..da4080b094 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -159,7 +159,7 @@ jobs: dotnet test "Cosmos\Tests\Cosmos.TestRunner.UnitTest\Cosmos.TestRunner.UnitTest.csproj" --logger "trx;LogFileName=$($env:USER_KIT_PATH)TestResults\${{ matrix.kernel }}-TestResult.trx" --filter "FullyQualifiedName~${{ matrix.kernel }}" - name: Upload Test Logs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: test-logs path: ${{ env.USER_KIT_PATH }}TestResults diff --git a/source/Cosmos.System2_Plugs/System/Linq/EnumerableImpl.cs b/source/Cosmos.System2_Plugs/System/Linq/EnumerableImpl.cs new file mode 100644 index 0000000000..27d5826c9a --- /dev/null +++ b/source/Cosmos.System2_Plugs/System/Linq/EnumerableImpl.cs @@ -0,0 +1,2717 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using IL2CPU.API.Attribs; +using System.Net; + +namespace Cosmos.System_Plugs.System.Linq +{ + [Plug(Target = typeof(Enumerable))] + public static class EnumerableImpl + { + public static IEnumerable Where(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + if (source is Iterator) return ((Iterator)source).Where(predicate); + if (source is TSource[]) return new WhereArrayIterator((TSource[])source, predicate); + if (source is List) return new WhereListIterator((List)source, predicate); + return new WhereEnumerableIterator(source, predicate); + } + + public static IEnumerable Where(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + return WhereIterator(source, predicate); + } + + static IEnumerable WhereIterator(IEnumerable source, Func predicate) { + int index = -1; + foreach (TSource element in source) { + checked { index++; } + if (predicate(element, index)) yield return element; + } + } + + public static IEnumerable Select(this IEnumerable source, Func selector) { + if (source == null) throw new ArgumentNullException("source"); + if (selector == null) throw new ArgumentNullException("selector"); + if (source is Iterator) return ((Iterator)source).Select(selector); + if (source is TSource[]) return new WhereSelectArrayIterator((TSource[])source, null, selector); + if (source is List) return new WhereSelectListIterator((List)source, null, selector); + return new WhereSelectEnumerableIterator(source, null, selector); + } + + public static IEnumerable Select(this IEnumerable source, Func selector) { + if (source == null) throw new ArgumentNullException("source"); + if (selector == null) throw new ArgumentNullException("selector"); + return SelectIterator(source, selector); + } + + static IEnumerable SelectIterator(IEnumerable source, Func selector) { + int index = -1; + foreach (TSource element in source) { + checked { index++; } + yield return selector(element, index); + } + } + + static Func CombinePredicates(Func predicate1, Func predicate2) { + return x => predicate1(x) && predicate2(x); + } + + static Func CombineSelectors(Func selector1, Func selector2) { + return x => selector2(selector1(x)); + } + + abstract class Iterator : IEnumerable, IEnumerator + { + int threadId; + internal int state; + internal TSource current; + + public Iterator() { + threadId = 0; + } + + public TSource Current { + get { return current; } + } + + public abstract Iterator Clone(); + + public virtual void Dispose() { + current = default(TSource); + state = -1; + } + + public IEnumerator GetEnumerator() { + if (threadId == 0 && state == 0) { + state = 1; + return this; + } + Iterator duplicate = Clone(); + duplicate.state = 1; + return duplicate; + } + + public abstract bool MoveNext(); + + public abstract IEnumerable Select(Func selector); + + public abstract IEnumerable Where(Func predicate); + + object IEnumerator.Current { + get { return Current; } + } + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + void IEnumerator.Reset() { + throw new NotImplementedException(); + } + } + + class WhereEnumerableIterator : Iterator + { + IEnumerable source; + Func predicate; + IEnumerator enumerator; + + public WhereEnumerableIterator(IEnumerable source, Func predicate) { + this.source = source; + this.predicate = predicate; + } + + public override Iterator Clone() { + return new WhereEnumerableIterator(source, predicate); + } + + public override void Dispose() { + if (enumerator is IDisposable) ((IDisposable)enumerator).Dispose(); + enumerator = null; + base.Dispose(); + } + + public override bool MoveNext() { + switch (state) { + case 1: + enumerator = source.GetEnumerator(); + state = 2; + goto case 2; + case 2: + while (enumerator.MoveNext()) { + TSource item = enumerator.Current; + if (predicate(item)) { + current = item; + return true; + } + } + Dispose(); + break; + } + return false; + } + + public override IEnumerable Select(Func selector) { + return new WhereSelectEnumerableIterator(source, predicate, selector); + } + + public override IEnumerable Where(Func predicate) { + return new WhereEnumerableIterator(source, CombinePredicates(this.predicate, predicate)); + } + } + + class WhereArrayIterator : Iterator + { + TSource[] source; + Func predicate; + int index; + + public WhereArrayIterator(TSource[] source, Func predicate) { + this.source = source; + this.predicate = predicate; + } + + public override Iterator Clone() { + return new WhereArrayIterator(source, predicate); + } + + public override bool MoveNext() { + if (state == 1) { + while (index < source.Length) { + TSource item = source[index]; + index++; + if (predicate(item)) { + current = item; + return true; + } + } + Dispose(); + } + return false; + } + + public override IEnumerable Select(Func selector) { + return new WhereSelectArrayIterator(source, predicate, selector); + } + + public override IEnumerable Where(Func predicate) { + return new WhereArrayIterator(source, CombinePredicates(this.predicate, predicate)); + } + } + + class WhereListIterator : Iterator + { + List source; + Func predicate; + List.Enumerator enumerator; + + public WhereListIterator(List source, Func predicate) { + this.source = source; + this.predicate = predicate; + } + + public override Iterator Clone() { + return new WhereListIterator(source, predicate); + } + + public override bool MoveNext() { + switch (state) { + case 1: + enumerator = source.GetEnumerator(); + state = 2; + goto case 2; + case 2: + while (enumerator.MoveNext()) { + TSource item = enumerator.Current; + if (predicate(item)) { + current = item; + return true; + } + } + Dispose(); + break; + } + return false; + } + + public override IEnumerable Select(Func selector) { + return new WhereSelectListIterator(source, predicate, selector); + } + + public override IEnumerable Where(Func predicate) { + return new WhereListIterator(source, CombinePredicates(this.predicate, predicate)); + } + } + + public interface IIListProvider + { + // Get the count of elements (optional optimization). + int GetCount(bool onlyIfCheap); + + // Copy items to an array (optional optimization). + bool TryCopyTo(T[] array, int arrayIndex); + } + + /// + /// An iterator that maps each item of an . + /// + /// The type of the source enumerable. + /// The type of the mapped items. + class SelectEnumerableIterator : Iterator, IIListProvider + { + private readonly IEnumerable _source; + private readonly Func _selector; + private IEnumerator _enumerator; + + public SelectEnumerableIterator(IEnumerable source, Func selector) + { + _source = source; + _selector = selector; + } + + public override Iterator Clone() + { + return new SelectEnumerableIterator(_source, _selector); + } + + public override void Dispose() + { + if (_enumerator != null) + { + _enumerator.Dispose(); + _enumerator = null; + } + + base.Dispose(); + } + + public override bool MoveNext() + { + switch (state) + { + case 1: + _enumerator = _source.GetEnumerator(); + state = 2; + goto case 2; + case 2: + if (_enumerator.MoveNext()) + { + current = _selector(_enumerator.Current); + return true; + } + + Dispose(); + break; + } + + return false; + } + + public override IEnumerable Select(Func selector) + { + return new SelectEnumerableIterator(_source, CombineSelectors(_selector, selector)); + } + + public override IEnumerable Where(Func predicate) + { + return new WhereEnumerableIterator(this, predicate); + } + + public TResult[] ToArray() + { + var builder = new List(); + + foreach (TSource item in _source) + { + builder.Add(_selector(item)); + } + + return builder.ToArray(); + } + + public List ToList() + { + var list = new List(); + + foreach (TSource item in _source) + { + list.Add(_selector(item)); + } + + return list; + } + + public int GetCount(bool onlyIfCheap) + { + // In case someone uses Count() to force evaluation of + // the selector, run it provided `onlyIfCheap` is false. + + if (onlyIfCheap) + { + return -1; + } + + int count = 0; + + foreach (TSource item in _source) + { + _selector(item); + checked + { + count++; + } + } + + return count; + } + + public bool TryCopyTo(TResult[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + } + + class WhereSelectEnumerableIterator : Iterator + { + IEnumerable source; + Func predicate; + Func selector; + IEnumerator enumerator; + + public WhereSelectEnumerableIterator(IEnumerable source, Func predicate, Func selector) { + this.source = source; + this.predicate = predicate; + this.selector = selector; + } + + public override Iterator Clone() { + return new WhereSelectEnumerableIterator(source, predicate, selector); + } + + public override void Dispose() { + if (enumerator is IDisposable) ((IDisposable)enumerator).Dispose(); + enumerator = null; + base.Dispose(); + } + + public override bool MoveNext() { + switch (state) { + case 1: + enumerator = source.GetEnumerator(); + state = 2; + goto case 2; + case 2: + while (enumerator.MoveNext()) { + TSource item = enumerator.Current; + if (predicate == null || predicate(item)) { + current = selector(item); + return true; + } + } + Dispose(); + break; + } + return false; + } + + public override IEnumerable Select(Func selector) { + return new WhereSelectEnumerableIterator(source, predicate, CombineSelectors(this.selector, selector)); + } + + public override IEnumerable Where(Func predicate) { + return new WhereEnumerableIterator(this, predicate); + } + } + + class WhereSelectArrayIterator : Iterator + { + TSource[] source; + Func predicate; + Func selector; + int index; + + public WhereSelectArrayIterator(TSource[] source, Func predicate, Func selector) { + this.source = source; + this.predicate = predicate; + this.selector = selector; + } + + public override Iterator Clone() { + return new WhereSelectArrayIterator(source, predicate, selector); + } + + public override bool MoveNext() { + if (state == 1) { + while (index < source.Length) { + TSource item = source[index]; + index++; + if (predicate == null || predicate(item)) { + current = selector(item); + return true; + } + } + Dispose(); + } + return false; + } + + public override IEnumerable Select(Func selector) { + return new WhereSelectArrayIterator(source, predicate, CombineSelectors(this.selector, selector)); + } + + public override IEnumerable Where(Func predicate) { + return new WhereEnumerableIterator(this, predicate); + } + } + + class WhereSelectListIterator : Iterator + { + List source; + Func predicate; + Func selector; + List.Enumerator enumerator; + + public WhereSelectListIterator(List source, Func predicate, Func selector) { + this.source = source; + this.predicate = predicate; + this.selector = selector; + } + + public override Iterator Clone() { + return new WhereSelectListIterator(source, predicate, selector); + } + + public override bool MoveNext() { + switch (state) { + case 1: + enumerator = source.GetEnumerator(); + state = 2; + goto case 2; + case 2: + while (enumerator.MoveNext()) { + TSource item = enumerator.Current; + if (predicate == null || predicate(item)) { + current = selector(item); + return true; + } + } + Dispose(); + break; + } + return false; + } + + public override IEnumerable Select(Func selector) { + return new WhereSelectListIterator(source, predicate, CombineSelectors(this.selector, selector)); + } + + public override IEnumerable Where(Func predicate) { + return new WhereEnumerableIterator(this, predicate); + } + } + + //public static IEnumerable Where(this IEnumerable source, Func predicate) { + // if (source == null) throw new ArgumentNullException("source"); + // if (predicate == null) throw new ArgumentNullException("predicate"); + // return WhereIterator(source, predicate); + //} + + //static IEnumerable WhereIterator(IEnumerable source, Func predicate) { + // foreach (TSource element in source) { + // if (predicate(element)) yield return element; + // } + //} + + //public static IEnumerable Select(this IEnumerable source, Func selector) { + // if (source == null) throw new ArgumentNullException("source"); + // if (selector == null) throw new ArgumentNullException("selector"); + // return SelectIterator(source, selector); + //} + + //static IEnumerable SelectIterator(IEnumerable source, Func selector) { + // foreach (TSource element in source) { + // yield return selector(element); + // } + //} + + public static IEnumerable SelectMany(this IEnumerable source, Func> selector) { + if (source == null) throw new ArgumentNullException("source"); + if (selector == null) throw new ArgumentNullException("selector"); + return SelectManyIterator(source, selector); + } + + static IEnumerable SelectManyIterator(IEnumerable source, Func> selector) { + foreach (TSource element in source) { + foreach (TResult subElement in selector(element)) { + yield return subElement; + } + } + } + + public static IEnumerable SelectMany(this IEnumerable source, Func> selector) { + if (source == null) throw new ArgumentNullException("source"); + if (selector == null) throw new ArgumentNullException("selector"); + return SelectManyIterator(source, selector); + } + + static IEnumerable SelectManyIterator(IEnumerable source, Func> selector) { + int index = -1; + foreach (TSource element in source) { + checked { index++; } + foreach (TResult subElement in selector(element, index)) { + yield return subElement; + } + } + } + public static IEnumerable SelectMany(this IEnumerable source, Func> collectionSelector, Func resultSelector) + { + if (source == null) throw new ArgumentNullException("source"); + if (collectionSelector == null) throw new ArgumentNullException("collectionSelector"); + if (resultSelector == null) throw new ArgumentNullException("resultSelector"); + return SelectManyIterator(source, collectionSelector, resultSelector); + } + + static IEnumerable SelectManyIterator(IEnumerable source, Func> collectionSelector, Func resultSelector){ + int index = -1; + foreach (TSource element in source){ + checked { index++; } + foreach (TCollection subElement in collectionSelector(element, index)){ + yield return resultSelector(element, subElement); + } + } + } + + public static IEnumerable SelectMany(this IEnumerable source, Func> collectionSelector, Func resultSelector) { + if (source == null) throw new ArgumentNullException("source"); + if (collectionSelector == null) throw new ArgumentNullException("collectionSelector"); + if (resultSelector == null) throw new ArgumentNullException("resultSelector"); + return SelectManyIterator(source, collectionSelector, resultSelector); + } + + static IEnumerable SelectManyIterator(IEnumerable source, Func> collectionSelector, Func resultSelector) { + foreach (TSource element in source) { + foreach (TCollection subElement in collectionSelector(element)) { + yield return resultSelector(element, subElement); + } + } + } + + public static IEnumerable Take(this IEnumerable source, int count) { + if (source == null) throw new ArgumentNullException("source"); + return TakeIterator(source, count); + } + + static IEnumerable TakeIterator(IEnumerable source, int count) { + if (count > 0) { + foreach (TSource element in source) { + yield return element; + if (--count == 0) break; + } + } + } + + public static IEnumerable TakeWhile(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + return TakeWhileIterator(source, predicate); + } + + static IEnumerable TakeWhileIterator(IEnumerable source, Func predicate) { + foreach (TSource element in source) { + if (!predicate(element)) break; + yield return element; + } + } + + public static IEnumerable TakeWhile(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + return TakeWhileIterator(source, predicate); + } + + static IEnumerable TakeWhileIterator(IEnumerable source, Func predicate) { + int index = -1; + foreach (TSource element in source) { + checked { index++; } + if (!predicate(element, index)) break; + yield return element; + } + } + + public static IEnumerable Skip(this IEnumerable source, int count) { + if (source == null) throw new ArgumentNullException("source"); + return SkipIterator(source, count); + } + + static IEnumerable SkipIterator(IEnumerable source, int count) { + using (IEnumerator e = source.GetEnumerator()) { + while (count > 0 && e.MoveNext()) count--; + if (count <= 0) { + while (e.MoveNext()) yield return e.Current; + } + } + } + + public static IEnumerable SkipWhile(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + return SkipWhileIterator(source, predicate); + } + + static IEnumerable SkipWhileIterator(IEnumerable source, Func predicate) { + bool yielding = false; + foreach (TSource element in source) { + if (!yielding && !predicate(element)) yielding = true; + if (yielding) yield return element; + } + } + + public static IEnumerable SkipWhile(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + return SkipWhileIterator(source, predicate); + } + + static IEnumerable SkipWhileIterator(IEnumerable source, Func predicate) { + int index = -1; + bool yielding = false; + foreach (TSource element in source) { + checked { index++; } + if (!yielding && !predicate(element, index)) yielding = true; + if (yielding) yield return element; + } + } + + public static IEnumerable Join(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector) { + if (outer == null) throw new ArgumentNullException("outer"); + if (inner == null) throw new ArgumentNullException("inner"); + if (outerKeySelector == null) throw new ArgumentNullException("outerKeySelector"); + if (innerKeySelector == null) throw new ArgumentNullException("innerKeySelector"); + if (resultSelector == null) throw new ArgumentNullException("resultSelector"); + return JoinIterator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, null); + } + + public static IEnumerable Join(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector, IEqualityComparer comparer) { + if (outer == null) throw new ArgumentNullException("outer"); + if (inner == null) throw new ArgumentNullException("inner"); + if (outerKeySelector == null) throw new ArgumentNullException("outerKeySelector"); + if (innerKeySelector == null) throw new ArgumentNullException("innerKeySelector"); + if (resultSelector == null) throw new ArgumentNullException("resultSelector"); + return JoinIterator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer); + } + + static IEnumerable JoinIterator(IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector, IEqualityComparer comparer) { + Lookup lookup = Lookup.CreateForJoin(inner, innerKeySelector, comparer); + foreach (TOuter item in outer) { + Lookup.Grouping g = lookup.GetGrouping(outerKeySelector(item), false); + if (g != null) { + for (int i = 0; i < g.count; i++) { + yield return resultSelector(item, g.elements[i]); + } + } + } + } + + public static IEnumerable GroupJoin(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector) { + if (outer == null) throw new ArgumentNullException("outer"); + if (inner == null) throw new ArgumentNullException("inner"); + if (outerKeySelector == null) throw new ArgumentNullException("outerKeySelector"); + if (innerKeySelector == null) throw new ArgumentNullException("innerKeySelector"); + if (resultSelector == null) throw new ArgumentNullException("resultSelector"); + return GroupJoinIterator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, null); + } + + public static IEnumerable GroupJoin(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector, IEqualityComparer comparer) { + if (outer == null) throw new ArgumentNullException("outer"); + if (inner == null) throw new ArgumentNullException("inner"); + if (outerKeySelector == null) throw new ArgumentNullException("outerKeySelector"); + if (innerKeySelector == null) throw new ArgumentNullException("innerKeySelector"); + if (resultSelector == null) throw new ArgumentNullException("resultSelector"); + return GroupJoinIterator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer); + } + + static IEnumerable GroupJoinIterator(IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector, IEqualityComparer comparer) { + Lookup lookup = Lookup.CreateForJoin(inner, innerKeySelector, comparer); + foreach (TOuter item in outer) { + yield return resultSelector(item, lookup[outerKeySelector(item)]); + } + } + + public static IOrderedEnumerable OrderBy(this IEnumerable source, Func keySelector) { + return new OrderedEnumerable(source, keySelector, null, false); + } + + public static IOrderedEnumerable OrderBy(this IEnumerable source, Func keySelector, IComparer comparer) { + return new OrderedEnumerable(source, keySelector, comparer, false); + } + + public static IOrderedEnumerable OrderByDescending(this IEnumerable source, Func keySelector) { + return new OrderedEnumerable(source, keySelector, null, true); + } + + public static IOrderedEnumerable OrderByDescending(this IEnumerable source, Func keySelector, IComparer comparer) { + return new OrderedEnumerable(source, keySelector, comparer, true); + } + + public static IOrderedEnumerable ThenBy(this IOrderedEnumerable source, Func keySelector) { + if (source == null) throw new ArgumentNullException("source"); + return source.CreateOrderedEnumerable(keySelector, null, false); + } + + public static IOrderedEnumerable ThenBy(this IOrderedEnumerable source, Func keySelector, IComparer comparer) { + if (source == null) throw new ArgumentNullException("source"); + return source.CreateOrderedEnumerable(keySelector, comparer, false); + } + + public static IOrderedEnumerable ThenByDescending(this IOrderedEnumerable source, Func keySelector) { + if (source == null) throw new ArgumentNullException("source"); + return source.CreateOrderedEnumerable(keySelector, null, true); + } + + public static IOrderedEnumerable ThenByDescending(this IOrderedEnumerable source, Func keySelector, IComparer comparer) { + if (source == null) throw new ArgumentNullException("source"); + return source.CreateOrderedEnumerable(keySelector, comparer, true); + } + + public static IEnumerable> GroupBy(this IEnumerable source, Func keySelector) { + return new GroupedEnumerable(source, keySelector, IdentityFunction.Instance, null); + } + + public static IEnumerable> GroupBy(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { + return new GroupedEnumerable(source, keySelector, IdentityFunction.Instance, comparer); + } + + public static IEnumerable> GroupBy(this IEnumerable source, Func keySelector, Func elementSelector) { + return new GroupedEnumerable(source, keySelector, elementSelector, null); + } + + public static IEnumerable> GroupBy(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { + return new GroupedEnumerable(source, keySelector, elementSelector, comparer); + } + + public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func, TResult> resultSelector){ + return new GroupedEnumerable(source, keySelector, IdentityFunction.Instance, resultSelector, null); + } + + public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector){ + return new GroupedEnumerable(source, keySelector, elementSelector, resultSelector, null); + } + + public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func, TResult> resultSelector, IEqualityComparer comparer){ + return new GroupedEnumerable(source, keySelector, IdentityFunction.Instance, resultSelector, comparer); + } + + public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector, IEqualityComparer comparer){ + return new GroupedEnumerable(source, keySelector, elementSelector, resultSelector, comparer); + } + + public static IEnumerable Concat(this IEnumerable first, IEnumerable second) { + if (first == null) throw new ArgumentNullException("first"); + if (second == null) throw new ArgumentNullException("second"); + return ConcatIterator(first, second); + } + + static IEnumerable ConcatIterator(IEnumerable first, IEnumerable second) { + foreach (TSource element in first) yield return element; + foreach (TSource element in second) yield return element; + } + + public static IEnumerable Zip(this IEnumerable first, IEnumerable second, Func resultSelector) { + if (first == null) throw new ArgumentNullException("first"); + if (second == null) throw new ArgumentNullException("second"); + if (resultSelector == null) throw new ArgumentNullException("resultSelector"); + return ZipIterator(first, second, resultSelector); + } + + static IEnumerable ZipIterator(IEnumerable first, IEnumerable second, Func resultSelector) { + using (IEnumerator e1 = first.GetEnumerator()) + using (IEnumerator e2 = second.GetEnumerator()) + while (e1.MoveNext() && e2.MoveNext()) + yield return resultSelector(e1.Current, e2.Current); + } + + + public static IEnumerable Distinct(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + return DistinctIterator(source, null); + } + + public static IEnumerable Distinct(this IEnumerable source, IEqualityComparer comparer) { + if (source == null) throw new ArgumentNullException("source"); + return DistinctIterator(source, comparer); + } + + static IEnumerable DistinctIterator(IEnumerable source, IEqualityComparer comparer) { + Set set = new Set(comparer); + foreach (TSource element in source) + if (set.Add(element)) yield return element; + } + + public static IEnumerable Union(this IEnumerable first, IEnumerable second) { + if (first == null) throw new ArgumentNullException("first"); + if (second == null) throw new ArgumentNullException("second"); + return UnionIterator(first, second, null); + } + + public static IEnumerable Union(this IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + if (first == null) throw new ArgumentNullException("first"); + if (second == null) throw new ArgumentNullException("second"); + return UnionIterator(first, second, comparer); + } + + static IEnumerable UnionIterator(IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + Set set = new Set(comparer); + foreach (TSource element in first) + if (set.Add(element)) yield return element; + foreach (TSource element in second) + if (set.Add(element)) yield return element; + } + + public static IEnumerable Intersect(this IEnumerable first, IEnumerable second) { + if (first == null) throw new ArgumentNullException("first"); + if (second == null) throw new ArgumentNullException("second"); + return IntersectIterator(first, second, null); + } + + public static IEnumerable Intersect(this IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + if (first == null) throw new ArgumentNullException("first"); + if (second == null) throw new ArgumentNullException("second"); + return IntersectIterator(first, second, comparer); + } + + static IEnumerable IntersectIterator(IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + Set set = new Set(comparer); + foreach (TSource element in second) set.Add(element); + foreach (TSource element in first) + if (set.Remove(element)) yield return element; + } + + public static IEnumerable Except(this IEnumerable first, IEnumerable second) + { + if (first == null) throw new ArgumentNullException("first"); + if (second == null) throw new ArgumentNullException("second"); + return ExceptIterator(first, second, null); + } + + public static IEnumerable Except(this IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + if (first == null) throw new ArgumentNullException("first"); + if (second == null) throw new ArgumentNullException("second"); + return ExceptIterator(first, second, comparer); + } + + static IEnumerable ExceptIterator(IEnumerable first, IEnumerable second, IEqualityComparer comparer) { + Set set = new Set(comparer); + foreach (TSource element in second) set.Add(element); + foreach (TSource element in first) + if (set.Add(element)) yield return element; + } + + public static IEnumerable Reverse(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + return ReverseIterator(source); + } + + static IEnumerable ReverseIterator(IEnumerable source) { + Buffer buffer = new Buffer(source); + for (int i = buffer.count - 1; i >= 0; i--) yield return buffer.items[i]; + } + + public static bool SequenceEqual(this IEnumerable first, IEnumerable second) { + return SequenceEqual(first, second, null); + } + + public static bool SequenceEqual(this IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + if (comparer == null) comparer = EqualityComparer.Default; + if (first == null) throw new ArgumentNullException("first"); + if (second == null) throw new ArgumentNullException("second"); + using (IEnumerator e1 = first.GetEnumerator()) + using (IEnumerator e2 = second.GetEnumerator()) + { + while (e1.MoveNext()) + { + if (!(e2.MoveNext() && comparer.Equals(e1.Current, e2.Current))) return false; + } + if (e2.MoveNext()) return false; + } + return true; + } + + public static IEnumerable AsEnumerable(this IEnumerable source) + { + return source; + } + + public static TSource[] ToArray(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + return new Buffer(source).ToArray(); + } + + public static List ToList(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + return new List(source); + } + + public static Dictionary ToDictionary(this IEnumerable source, Func keySelector) { + return ToDictionary(source, keySelector, IdentityFunction.Instance, null); + } + + public static Dictionary ToDictionary(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { + return ToDictionary(source, keySelector, IdentityFunction.Instance, comparer); + } + + public static Dictionary ToDictionary(this IEnumerable source, Func keySelector, Func elementSelector) { + return ToDictionary(source, keySelector, elementSelector, null); + } + + public static Dictionary ToDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { + if (source == null) throw new ArgumentNullException("source"); + if (keySelector == null) throw new ArgumentNullException("keySelector"); + if (elementSelector == null) throw new ArgumentNullException("elementSelector"); + Dictionary d = new Dictionary(comparer); + foreach (TSource element in source) d.Add(keySelector(element), elementSelector(element)); + return d; + } + + public static ILookup ToLookup(this IEnumerable source, Func keySelector) { + return Lookup.Create(source, keySelector, IdentityFunction.Instance, null); + } + + public static ILookup ToLookup(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { + return Lookup.Create(source, keySelector, IdentityFunction.Instance, comparer); + } + + public static ILookup ToLookup(this IEnumerable source, Func keySelector, Func elementSelector) { + return Lookup.Create(source, keySelector, elementSelector, null); + } + + public static ILookup ToLookup(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { + return Lookup.Create(source, keySelector, elementSelector, comparer); + } + + public static HashSet ToHashSet(this IEnumerable source) { + return source.ToHashSet(null); + } + + public static HashSet ToHashSet(this IEnumerable source, IEqualityComparer comparer) { + if (source == null) throw new ArgumentNullException("source"); + return new HashSet(source, comparer); + } + + public static IEnumerable DefaultIfEmpty(this IEnumerable source) { + return DefaultIfEmpty(source, default(TSource)); + } + + public static IEnumerable DefaultIfEmpty(this IEnumerable source, TSource defaultValue) { + if (source == null) throw new ArgumentNullException("source"); + return DefaultIfEmptyIterator(source, defaultValue); + } + + static IEnumerable DefaultIfEmptyIterator(IEnumerable source, TSource defaultValue) { + using (IEnumerator e = source.GetEnumerator()) { + if (e.MoveNext()) { + do { + yield return e.Current; + } while (e.MoveNext()); + } + else { + yield return defaultValue; + } + } + } + + public static IEnumerable OfType(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + return OfTypeIterator(source); + } + + static IEnumerable OfTypeIterator(IEnumerable source) { + foreach (object obj in source) { + if (obj is TResult) yield return (TResult)obj; + } + } + + public static IEnumerable Cast(this IEnumerable source) { + IEnumerable typedSource = source as IEnumerable; + if (typedSource != null) return typedSource; + if (source == null) throw new ArgumentNullException("source"); + return CastIterator(source); + } + + static IEnumerable CastIterator(IEnumerable source) { + foreach (object obj in source) yield return (TResult)obj; + } + + public static TSource First(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + IList list = source as IList; + if (list != null) { + if (list.Count > 0) return list[0]; + } + else { + using (IEnumerator e = source.GetEnumerator()) { + if (e.MoveNext()) return e.Current; + } + } + throw new Exception(); + } + + public static TSource First(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + foreach (TSource element in source) { + if (predicate(element)) return element; + } + throw new Exception(); + } + + public static TSource FirstOrDefault(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + IList list = source as IList; + if (list != null) { + if (list.Count > 0) return list[0]; + } + else { + using (IEnumerator e = source.GetEnumerator()) { + if (e.MoveNext()) return e.Current; + } + } + return default(TSource); + } + + public static TSource FirstOrDefault(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + foreach (TSource element in source) { + if (predicate(element)) return element; + } + return default(TSource); + } + + public static TSource Last(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + IList list = source as IList; + if (list != null) { + int count = list.Count; + if (count > 0) return list[count - 1]; + } + else { + using (IEnumerator e = source.GetEnumerator()) { + if (e.MoveNext()) { + TSource result; + do { + result = e.Current; + } while (e.MoveNext()); + return result; + } + } + } + throw new Exception(); + } + + public static TSource Last(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + TSource result = default(TSource); + bool found = false; + foreach (TSource element in source) { + if (predicate(element)) { + result = element; + found = true; + } + } + if (found) return result; + throw new Exception(); + } + + public static TSource LastOrDefault(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + IList list = source as IList; + if (list != null) { + int count = list.Count; + if (count > 0) return list[count - 1]; + } + else { + using (IEnumerator e = source.GetEnumerator()) { + if (e.MoveNext()) { + TSource result; + do { + result = e.Current; + } while (e.MoveNext()); + return result; + } + } + } + return default(TSource); + } + + public static TSource LastOrDefault(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + TSource result = default(TSource); + foreach (TSource element in source) { + if (predicate(element)) { + result = element; + } + } + return result; + } + + public static TSource Single(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + IList list = source as IList; + if (list != null) { + switch (list.Count) { + case 0: throw new Exception(); + case 1: return list[0]; + } + } + else { + using (IEnumerator e = source.GetEnumerator()) { + if (!e.MoveNext()) throw new Exception(); + TSource result = e.Current; + if (!e.MoveNext()) return result; + } + } + throw new Exception(); + } + + public static TSource Single(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + TSource result = default(TSource); + long count = 0; + foreach (TSource element in source) { + if (predicate(element)) { + result = element; + checked { count++; } + } + } + switch (count) { + case 0: throw new Exception(); + case 1: return result; + } + throw new Exception(); + } + + public static TSource SingleOrDefault(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + IList list = source as IList; + if (list != null) { + switch (list.Count) { + case 0: return default(TSource); + case 1: return list[0]; + } + } + else { + using (IEnumerator e = source.GetEnumerator()) { + if (!e.MoveNext()) return default(TSource); + TSource result = e.Current; + if (!e.MoveNext()) return result; + } + } + throw new Exception(); + } + + public static TSource SingleOrDefault(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + TSource result = default(TSource); + long count = 0; + foreach (TSource element in source) { + if (predicate(element)) { + result = element; + checked { count++; } + } + } + switch (count) { + case 0: return default(TSource); + case 1: return result; + } + throw new Exception(); + } + + public static TSource ElementAt(this IEnumerable source, int index) { + if (source == null) throw new ArgumentNullException("source"); + IList list = source as IList; + if (list != null) return list[index]; + if (index < 0) throw new ArgumentOutOfRangeException("index"); + using (IEnumerator e = source.GetEnumerator()) { + while (true) { + if (!e.MoveNext()) throw new ArgumentOutOfRangeException("index"); + if (index == 0) return e.Current; + index--; + } + } + } + + public static TSource ElementAtOrDefault(this IEnumerable source, int index) { + if (source == null) throw new ArgumentNullException("source"); + if (index >= 0) { + IList list = source as IList; + if (list != null) { + if (index < list.Count) return list[index]; + } + else { + using (IEnumerator e = source.GetEnumerator()) { + while (true) { + if (!e.MoveNext()) break; + if (index == 0) return e.Current; + index--; + } + } + } + } + return default(TSource); + } + + public static IEnumerable Range(int start, int count) { + long max = ((long)start) + count - 1; + if (count < 0 || max > Int32.MaxValue) throw new ArgumentOutOfRangeException("count"); + return RangeIterator(start, count); + } + + static IEnumerable RangeIterator(int start, int count) { + for (int i = 0; i < count; i++) yield return start + i; + } + + public static IEnumerable Repeat(TResult element, int count) { + if (count < 0) throw new ArgumentOutOfRangeException("count"); + return RepeatIterator(element, count); + } + + static IEnumerable RepeatIterator(TResult element, int count) { + for (int i = 0; i < count; i++) yield return element; + } + + public static IEnumerable Empty() { + return EmptyEnumerable.Instance; + } + + public static bool Any(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + using (IEnumerator e = source.GetEnumerator()) { + if (e.MoveNext()) return true; + } + return false; + } + + public static bool Any(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + foreach (TSource element in source) { + if (predicate(element)) return true; + } + return false; + } + + public static bool All(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + foreach (TSource element in source) { + if (!predicate(element)) return false; + } + return true; + } + + public static int Count(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + ICollection collectionoft = source as ICollection; + if (collectionoft != null) return collectionoft.Count; + ICollection collection = source as ICollection; + if (collection != null) return collection.Count; + int count = 0; + using (IEnumerator e = source.GetEnumerator()) { + checked { + while (e.MoveNext()) count++; + } + } + return count; + } + + public static int Count(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + int count = 0; + foreach (TSource element in source) { + checked { + if (predicate(element)) count++; + } + } + return count; + } + + public static long LongCount(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long count = 0; + using (IEnumerator e = source.GetEnumerator()) { + checked { + while (e.MoveNext()) count++; + } + } + return count; + } + + public static long LongCount(this IEnumerable source, Func predicate) { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + long count = 0; + foreach (TSource element in source) { + checked { + if (predicate(element)) count++; + } + } + return count; + } + + public static bool Contains(this IEnumerable source, TSource value) { + ICollection collection = source as ICollection; + if (collection != null) return collection.Contains(value); + return Contains(source, value, null); + } + + public static bool Contains(this IEnumerable source, TSource value, IEqualityComparer comparer) + { + if (comparer == null) comparer = EqualityComparer.Default; + if (source == null) throw new ArgumentNullException("source"); + foreach (TSource element in source) + if (comparer.Equals(element, value)) return true; + return false; + } + + public static TSource Aggregate(this IEnumerable source, Func func) + { + if (source == null) throw new ArgumentNullException("source"); + if (func == null) throw new ArgumentNullException("func"); + using (IEnumerator e = source.GetEnumerator()) { + if (!e.MoveNext()) throw new Exception(); + TSource result = e.Current; + while (e.MoveNext()) result = func(result, e.Current); + return result; + } + } + + public static TAccumulate Aggregate(this IEnumerable source, TAccumulate seed, Func func) { + if (source == null) throw new ArgumentNullException("source"); + if (func == null) throw new ArgumentNullException("func"); + TAccumulate result = seed; + foreach (TSource element in source) result = func(result, element); + return result; + } + + public static TResult Aggregate(this IEnumerable source, TAccumulate seed, Func func, Func resultSelector) { + if (source == null) throw new ArgumentNullException("source"); + if (func == null) throw new ArgumentNullException("func"); + if (resultSelector == null) throw new ArgumentNullException("resultSelector"); + TAccumulate result = seed; + foreach (TSource element in source) result = func(result, element); + return resultSelector(result); + } + + public static int Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + int sum = 0; + checked { + foreach (int v in source) sum += v; + } + return sum; + } + + public static int? Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + int sum = 0; + checked { + foreach (int? v in source) { + if (v != null) sum += v.GetValueOrDefault(); + } + } + return sum; + } + + public static long Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long sum = 0; + checked { + foreach (long v in source) sum += v; + } + return sum; + } + + public static long? Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long sum = 0; + checked { + foreach (long? v in source) { + if (v != null) sum += v.GetValueOrDefault(); + } + } + return sum; + } + + public static float Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double sum = 0; + foreach (float v in source) sum += v; + return (float)sum; + } + + public static float? Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double sum = 0; + foreach (float? v in source) { + if (v != null) sum += v.GetValueOrDefault(); + } + return (float)sum; + } + + public static double Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double sum = 0; + foreach (double v in source) sum += v; + return sum; + } + + public static double? Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double sum = 0; + foreach (double? v in source) { + if (v != null) sum += v.GetValueOrDefault(); + } + return sum; + } + + public static decimal Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + decimal sum = 0; + foreach (decimal v in source) sum += v; + return sum; + } + + public static decimal? Sum(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + decimal sum = 0; + foreach (decimal? v in source) { + if (v != null) sum += v.GetValueOrDefault(); + } + return sum; + } + + public static int Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static int? Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static long Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static long? Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static float Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static float? Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static double Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static double? Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static decimal Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static decimal? Sum(this IEnumerable source, Func selector) { + return EnumerableImpl.Sum(EnumerableImpl.Select(source, selector)); + } + + public static int Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + int value = 0; + bool hasValue = false; + foreach (int x in source) { + if (hasValue) { + if (x < value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static int? Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + int? value = null; + foreach (int? x in source) { + if (value == null || x < value) + value = x; + } + return value; + } + + public static long Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long value = 0; + bool hasValue = false; + foreach (long x in source) { + if (hasValue) { + if (x < value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static long? Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long? value = null; + foreach (long? x in source) { + if (value == null || x < value) value = x; + } + return value; + } + + public static float Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + float value = 0; + bool hasValue = false; + foreach (float x in source) { + if (hasValue) { + // Normally NaN < anything is false, as is anything < NaN + // However, this leads to some irksome outcomes in Min and Max. + // If we use those semantics then Min(NaN, 5.0) is NaN, but + // Min(5.0, NaN) is 5.0! To fix this, we impose a total + // ordering where NaN is smaller than every value, including + // negative infinity. + if (x < value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static float? Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + float? value = null; + foreach (float? x in source) { + if (x == null) continue; + if (value == null || x < value) value = x; + } + return value; + } + + public static double Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double value = 0; + bool hasValue = false; + foreach (double x in source) { + if (hasValue) { + if (x < value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static double? Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double? value = null; + foreach (double? x in source) { + if (x == null) continue; + if (value == null || x < value) value = x; + } + return value; + } + + public static decimal Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + decimal value = 0; + bool hasValue = false; + foreach (decimal x in source) { + if (hasValue) { + if (x < value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static decimal? Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + decimal? value = null; + foreach (decimal? x in source) { + if (value == null || x < value) value = x; + } + return value; + } + + public static TSource Min(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + Comparer comparer = Comparer.Default; + TSource value = default(TSource); + if (value == null) { + foreach (TSource x in source) { + if (x != null && (value == null || comparer.Compare(x, value) < 0)) + value = x; + } + return value; + } + else { + bool hasValue = false; + foreach (TSource x in source) { + if (hasValue) { + if (comparer.Compare(x, value) < 0) + value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + } + + public static int Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static int? Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static long Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static long? Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static float Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static float? Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static double Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static double? Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static decimal Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static decimal? Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static TResult Min(this IEnumerable source, Func selector) { + return EnumerableImpl.Min(EnumerableImpl.Select(source, selector)); + } + + public static int Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + int value = 0; + bool hasValue = false; + foreach (int x in source) { + if (hasValue) { + if (x > value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static int? Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + int? value = null; + foreach (int? x in source) { + if (value == null || x > value) value = x; + } + return value; + } + + public static long Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long value = 0; + bool hasValue = false; + foreach (long x in source) { + if (hasValue) { + if (x > value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static long? Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long? value = null; + foreach (long? x in source) { + if (value == null || x > value) value = x; + } + return value; + } + + public static double Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double value = 0; + bool hasValue = false; + foreach (double x in source) { + if (hasValue) { + if (x > value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static double? Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double? value = null; + foreach (double? x in source) { + if (x == null) continue; + if (value == null || x > value) value = x; + } + return value; + } + + public static float Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + float value = 0; + bool hasValue = false; + foreach (float x in source) { + if (hasValue) { + if (x > value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static float? Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + float? value = null; + foreach (float? x in source) { + if (x == null) continue; + if (value == null || x > value) value = x; + } + return value; + } + + public static decimal Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + decimal value = 0; + bool hasValue = false; + foreach (decimal x in source) { + if (hasValue) { + if (x > value) value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + + public static decimal? Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + decimal? value = null; + foreach (decimal? x in source) { + if (value == null || x > value) value = x; + } + return value; + } + + public static TSource Max(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + Comparer comparer = Comparer.Default; + TSource value = default(TSource); + if (value == null) { + foreach (TSource x in source) { + if (x != null && (value == null || comparer.Compare(x, value) > 0)) + value = x; + } + return value; + } + else { + bool hasValue = false; + foreach (TSource x in source) { + if (hasValue) { + if (comparer.Compare(x, value) > 0) + value = x; + } + else { + value = x; + hasValue = true; + } + } + if (hasValue) return value; + throw new Exception(); + } + } + + public static int Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static int? Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static long Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static long? Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static float Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static float? Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static double Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static double? Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static decimal Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static decimal? Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static TResult Max(this IEnumerable source, Func selector) { + return EnumerableImpl.Max(EnumerableImpl.Select(source, selector)); + } + + public static double Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long sum = 0; + long count = 0; + checked { + foreach (int v in source) { + sum += v; + count++; + } + } + if (count > 0) return (double)sum / count; + throw new Exception(); + } + + public static double? Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long sum = 0; + long count = 0; + checked { + foreach (int? v in source) { + if (v != null) { + sum += v.GetValueOrDefault(); + count++; + } + } + } + if (count > 0) return (double)sum / count; + return null; + } + + public static double Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long sum = 0; + long count = 0; + checked { + foreach (long v in source) { + sum += v; + count++; + } + } + if (count > 0) return (double)sum / count; + throw new Exception(); + } + + public static double? Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + long sum = 0; + long count = 0; + checked { + foreach (long? v in source) { + if (v != null) { + sum += v.GetValueOrDefault(); + count++; + } + } + } + if (count > 0) return (double)sum / count; + return null; + } + + public static float Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double sum = 0; + long count = 0; + checked { + foreach (float v in source) { + sum += v; + count++; + } + } + if (count > 0) return (float)(sum / count); + throw new Exception(); + } + + public static float? Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double sum = 0; + long count = 0; + checked { + foreach (float? v in source) { + if (v != null) { + sum += v.GetValueOrDefault(); + count++; + } + } + } + if (count > 0) return (float)(sum / count); + return null; + } + + public static double Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double sum = 0; + long count = 0; + checked { + foreach (double v in source) { + sum += v; + count++; + } + } + if (count > 0) return sum / count; + throw new Exception(); + } + + public static double? Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + double sum = 0; + long count = 0; + checked { + foreach (double? v in source) { + if (v != null) { + sum += v.GetValueOrDefault(); + count++; + } + } + } + if (count > 0) return sum / count; + return null; + } + + public static decimal Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + decimal sum = 0; + long count = 0; + checked { + foreach (decimal v in source) { + sum += v; + count++; + } + } + if (count > 0) return sum / count; + throw new Exception(); + } + + public static decimal? Average(this IEnumerable source) { + if (source == null) throw new ArgumentNullException("source"); + decimal sum = 0; + long count = 0; + checked { + foreach (decimal? v in source) { + if (v != null) { + sum += v.GetValueOrDefault(); + count++; + } + } + } + if (count > 0) return sum / count; + return null; + } + + public static double Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + + public static double? Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + + public static double Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + + public static double? Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + + public static float Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + + public static float? Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + + public static double Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + + public static double? Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + + public static decimal Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + + public static decimal? Average(this IEnumerable source, Func selector) { + return EnumerableImpl.Average(EnumerableImpl.Select(source, selector)); + } + } + + + // + // We have added some optimization in SZArrayHelper class to cache the enumerator of zero length arrays so + // the enumerator will be created once per type. + // + internal class EmptyEnumerable + { + public static readonly TElement[] Instance = new TElement[0]; + } + + internal class IdentityFunction + { + public static Func Instance { + get { return x => x; } + } + } + + public interface IOrderedEnumerable : IEnumerable + { + IOrderedEnumerable CreateOrderedEnumerable(Func keySelector, IComparer comparer, bool descending); + } + +#if SILVERLIGHT && !FEATURE_NETCORE + public interface IGrouping : IEnumerable +#else + public interface IGrouping : IEnumerable +#endif + { + TKey Key { get; } + } + + public interface ILookup : IEnumerable>{ + int Count { get; } + IEnumerable this[TKey key] { get; } + bool Contains(TKey key); + } + + public class Lookup : IEnumerable>, ILookup{ + IEqualityComparer comparer; + Grouping[] groupings; + Grouping lastGrouping; + int count; + + internal static Lookup Create(IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { + if (source == null) throw new ArgumentNullException("source"); + if (keySelector == null) throw new ArgumentNullException("keySelector"); + if (elementSelector == null) throw new ArgumentNullException("elementSelector"); + Lookup lookup = new Lookup(comparer); + foreach (TSource item in source) { + lookup.GetGrouping(keySelector(item), true).Add(elementSelector(item)); + } + return lookup; + } + + internal static Lookup CreateForJoin(IEnumerable source, Func keySelector, IEqualityComparer comparer) { + Lookup lookup = new Lookup(comparer); + foreach (TElement item in source) { + TKey key = keySelector(item); + if (key != null) lookup.GetGrouping(key, true).Add(item); + } + return lookup; + } + + Lookup(IEqualityComparer comparer) { + if (comparer == null) comparer = EqualityComparer.Default; + this.comparer = comparer; + groupings = new Grouping[7]; + } + + public int Count { + get { return count; } + } + + public IEnumerable this[TKey key] { + get { + Grouping grouping = GetGrouping(key, false); + if (grouping != null) return grouping; + return EmptyEnumerable.Instance; + } + } + + public bool Contains(TKey key) { + return GetGrouping(key, false) != null; + } + + public IEnumerator> GetEnumerator() { + Grouping g = lastGrouping; + if (g != null) { + do { + g = g.next; + yield return g; + } while (g != lastGrouping); + } + } + + public IEnumerable ApplyResultSelector(Func, TResult> resultSelector){ + Grouping g = lastGrouping; + if (g != null) { + do { + g = g.next; + if (g.count != g.elements.Length) { Array.Resize(ref g.elements, g.count); } + yield return resultSelector(g.key, g.elements); + }while (g != lastGrouping); + } + } + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + internal int InternalGetHashCode(TKey key) + { + //Microsoft DevDivBugs 171937. work around comparer implementations that throw when passed null + return (key == null) ? 0 : comparer.GetHashCode(key) & 0x7FFFFFFF; + } + + internal Grouping GetGrouping(TKey key, bool create) { + int hashCode = InternalGetHashCode(key); + for (Grouping g = groupings[hashCode % groupings.Length]; g != null; g = g.hashNext) + if (g.hashCode == hashCode && comparer.Equals(g.key, key)) return g; + if (create) { + if (count == groupings.Length) Resize(); + int index = hashCode % groupings.Length; + Grouping g = new Grouping(); + g.key = key; + g.hashCode = hashCode; + g.elements = new TElement[1]; + g.hashNext = groupings[index]; + groupings[index] = g; + if (lastGrouping == null) { + g.next = g; + } + else { + g.next = lastGrouping.next; + lastGrouping.next = g; + } + lastGrouping = g; + count++; + return g; + } + return null; + } + + void Resize() { + int newSize = checked(count * 2 + 1); + Grouping[] newGroupings = new Grouping[newSize]; + Grouping g = lastGrouping; + do { + g = g.next; + int index = g.hashCode % newSize; + g.hashNext = newGroupings[index]; + newGroupings[index] = g; + } while (g != lastGrouping); + groupings = newGroupings; + } + + internal class Grouping : IGrouping, IList + { + internal TKey key; + internal int hashCode; + internal TElement[] elements; + internal int count; + internal Grouping hashNext; + internal Grouping next; + + internal void Add(TElement element) { + if (elements.Length == count) Array.Resize(ref elements, checked(count * 2)); + elements[count] = element; + count++; + } + + public IEnumerator GetEnumerator() { + for (int i = 0; i < count; i++) yield return elements[i]; + } + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + // DDB195907: implement IGrouping<>.Key implicitly + // so that WPF binding works on this property. + public TKey Key { + get { return key; } + } + + int ICollection.Count { + get { return count; } + } + + bool ICollection.IsReadOnly { + get { return true; } + } + + void ICollection.Add(TElement item) { + throw new Exception(); + } + + void ICollection.Clear() { + throw new Exception(); + } + + bool ICollection.Contains(TElement item) { + return Array.IndexOf(elements, item, 0, count) >= 0; + } + + void ICollection.CopyTo(TElement[] array, int arrayIndex) { + Array.Copy(elements, 0, array, arrayIndex, count); + } + + bool ICollection.Remove(TElement item) { + throw new Exception(); + } + + int IList.IndexOf(TElement item) { + return Array.IndexOf(elements, item, 0, count); + } + + void IList.Insert(int index, TElement item) { + throw new Exception(); + } + + void IList.RemoveAt(int index) { + throw new Exception(); + } + + TElement IList.this[int index] { + get { + if (index < 0 || index >= count) throw new ArgumentOutOfRangeException("index"); + return elements[index]; + } + set { + throw new Exception(); + } + } + } + } + + // @ + internal class Set + { + int[] buckets; + Slot[] slots; + int count; + int freeList; + IEqualityComparer comparer; + + public Set() : this(null) { } + + public Set(IEqualityComparer comparer) { + if (comparer == null) comparer = EqualityComparer.Default; + this.comparer = comparer; + buckets = new int[7]; + slots = new Slot[7]; + freeList = -1; + } + + // If value is not in set, add it and return true; otherwise return false + public bool Add(TElement value) { + return !Find(value, true); + } + + // Check whether value is in set + public bool Contains(TElement value) { + return Find(value, false); + } + + // If value is in set, remove it and return true; otherwise return false + public bool Remove(TElement value) { + int hashCode = InternalGetHashCode(value); + int bucket = hashCode % buckets.Length; + int last = -1; + for (int i = buckets[bucket] - 1; i >= 0; last = i, i = slots[i].next) { + if (slots[i].hashCode == hashCode && comparer.Equals(slots[i].value, value)) { + if (last < 0) { + buckets[bucket] = slots[i].next + 1; + } + else { + slots[last].next = slots[i].next; + } + slots[i].hashCode = -1; + slots[i].value = default(TElement); + slots[i].next = freeList; + freeList = i; + return true; + } + } + return false; + } + + bool Find(TElement value, bool add) { + int hashCode = InternalGetHashCode(value); + for (int i = buckets[hashCode % buckets.Length] - 1; i >= 0; i = slots[i].next) { + if (slots[i].hashCode == hashCode && comparer.Equals(slots[i].value, value)) return true; + } + if (add) { + int index; + if (freeList >= 0) { + index = freeList; + freeList = slots[index].next; + } + else { + if (count == slots.Length) Resize(); + index = count; + count++; + } + int bucket = hashCode % buckets.Length; + slots[index].hashCode = hashCode; + slots[index].value = value; + slots[index].next = buckets[bucket] - 1; + buckets[bucket] = index + 1; + } + return false; + } + + void Resize() { + int newSize = checked(count * 2 + 1); + int[] newBuckets = new int[newSize]; + Slot[] newSlots = new Slot[newSize]; + Array.Copy(slots, 0, newSlots, 0, count); + for (int i = 0; i < count; i++) { + int bucket = newSlots[i].hashCode % newSize; + newSlots[i].next = newBuckets[bucket] - 1; + newBuckets[bucket] = i + 1; + } + buckets = newBuckets; + slots = newSlots; + } + + internal int InternalGetHashCode(TElement value) + { + //Microsoft DevDivBugs 171937. work around comparer implementations that throw when passed null + return (value == null) ? 0 : comparer.GetHashCode(value) & 0x7FFFFFFF; + } + + internal struct Slot + { + internal int hashCode; + internal TElement value; + internal int next; + } + } + + internal class GroupedEnumerable : IEnumerable{ + IEnumerable source; + Func keySelector; + Func elementSelector; + IEqualityComparer comparer; + Func, TResult> resultSelector; + + public GroupedEnumerable(IEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector, IEqualityComparer comparer){ + if (source == null) throw new ArgumentNullException("source"); + if (keySelector == null) throw new ArgumentNullException("keySelector"); + if (elementSelector == null) throw new ArgumentNullException("elementSelector"); + if (resultSelector == null) throw new ArgumentNullException("resultSelector"); + this.source = source; + this.keySelector = keySelector; + this.elementSelector = elementSelector; + this.comparer = comparer; + this.resultSelector = resultSelector; + } + + public IEnumerator GetEnumerator(){ + Lookup lookup = Lookup.Create(source, keySelector, elementSelector, comparer); + return lookup.ApplyResultSelector(resultSelector).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator(){ + return GetEnumerator(); + } + } + + internal class GroupedEnumerable : IEnumerable> + { + IEnumerable source; + Func keySelector; + Func elementSelector; + IEqualityComparer comparer; + + public GroupedEnumerable(IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { + if (source == null) throw new ArgumentNullException("source"); + if (keySelector == null) throw new ArgumentNullException("keySelector"); + if (elementSelector == null) throw new ArgumentNullException("elementSelector"); + this.source = source; + this.keySelector = keySelector; + this.elementSelector = elementSelector; + this.comparer = comparer; + } + + public IEnumerator> GetEnumerator() { + return Lookup.Create(source, keySelector, elementSelector, comparer).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + } + + internal abstract class OrderedEnumerable : IOrderedEnumerable + { + internal IEnumerable source; + + public IEnumerator GetEnumerator() { + Buffer buffer = new Buffer(source); + if (buffer.count > 0) { + EnumerableSorter sorter = GetEnumerableSorter(null); + int[] map = sorter.Sort(buffer.items, buffer.count); + sorter = null; + for (int i = 0; i < buffer.count; i++) yield return buffer.items[map[i]]; + } + } + + internal abstract EnumerableSorter GetEnumerableSorter(EnumerableSorter next); + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + IOrderedEnumerable IOrderedEnumerable.CreateOrderedEnumerable(Func keySelector, IComparer comparer, bool descending) { + OrderedEnumerable result = new OrderedEnumerable(source, keySelector, comparer, descending); + result.parent = this; + return result; + } + } + + internal class OrderedEnumerable : OrderedEnumerable + { + internal OrderedEnumerable parent; + internal Func keySelector; + internal IComparer comparer; + internal bool descending; + + internal OrderedEnumerable(IEnumerable source, Func keySelector, IComparer comparer, bool descending) { + if (source == null) throw new ArgumentNullException("source"); + if (keySelector == null) throw new ArgumentNullException("keySelector"); + this.source = source; + this.parent = null; + this.keySelector = keySelector; + this.comparer = comparer != null ? comparer : Comparer.Default; + this.descending = descending; + } + + internal override EnumerableSorter GetEnumerableSorter(EnumerableSorter next) { + EnumerableSorter sorter = new EnumerableSorter(keySelector, comparer, descending, next); + if (parent != null) sorter = parent.GetEnumerableSorter(sorter); + return sorter; + } + } + + internal abstract class EnumerableSorter + { + internal abstract void ComputeKeys(TElement[] elements, int count); + + internal abstract int CompareKeys(int index1, int index2); + + internal int[] Sort(TElement[] elements, int count) { + ComputeKeys(elements, count); + int[] map = new int[count]; + for (int i = 0; i < count; i++) map[i] = i; + QuickSort(map, 0, count - 1); + return map; + } + + void QuickSort(int[] map, int left, int right) { + do { + int i = left; + int j = right; + int x = map[i + ((j - i) >> 1)]; + do { + while (i < map.Length && CompareKeys(x, map[i]) > 0) i++; + while (j >= 0 && CompareKeys(x, map[j]) < 0) j--; + if (i > j) break; + if (i < j) { + int temp = map[i]; + map[i] = map[j]; + map[j] = temp; + } + i++; + j--; + } while (i <= j); + if (j - left <= right - i) { + if (left < j) QuickSort(map, left, j); + left = i; + } + else { + if (i < right) QuickSort(map, i, right); + right = j; + } + } while (left < right); + } + } + + internal class EnumerableSorter : EnumerableSorter + { + internal Func keySelector; + internal IComparer comparer; + internal bool descending; + internal EnumerableSorter next; + internal TKey[] keys; + + internal EnumerableSorter(Func keySelector, IComparer comparer, bool descending, EnumerableSorter next) { + this.keySelector = keySelector; + this.comparer = comparer; + this.descending = descending; + this.next = next; + } + + internal override void ComputeKeys(TElement[] elements, int count) { + keys = new TKey[count]; + for (int i = 0; i < count; i++) keys[i] = keySelector(elements[i]); + if (next != null) next.ComputeKeys(elements, count); + } + + internal override int CompareKeys(int index1, int index2) { + int c = comparer.Compare(keys[index1], keys[index2]); + if (c == 0) { + if (next == null) return index1 - index2; + return next.CompareKeys(index1, index2); + } + return descending ? -c : c; + } + } + + struct Buffer + { + internal TElement[] items; + internal int count; + + internal Buffer(IEnumerable source) { + TElement[] items = null; + int count = 0; + ICollection collection = source as ICollection; + if (collection != null) { + count = collection.Count; + if (count > 0) { + items = new TElement[count]; + collection.CopyTo(items, 0); + } + } + else { + foreach (TElement item in source) { + if (items == null) { + items = new TElement[4]; + } + else if (items.Length == count) { + TElement[] newItems = new TElement[checked(count * 2)]; + Array.Copy(items, 0, newItems, 0, count); + items = newItems; + } + items[count] = item; + count++; + } + } + this.items = items; + this.count = count; + } + + internal TElement[] ToArray() { + if (count == 0) return new TElement[0]; + if (items.Length == count) return items; + TElement[] result = new TElement[count]; + Array.Copy(items, 0, result, 0, count); + return result; + } + } +}