From 0e4ddbcafaa8a801983bfc7d9eb6b14987964ec5 Mon Sep 17 00:00:00 2001 From: Jacob Silas Bentley Date: Thu, 25 Apr 2024 16:58:45 +0100 Subject: [PATCH 01/16] Removed closures in favour of private static methods --- MoreLinq.Test/RankTest.cs | 2 +- MoreLinq/Assert.cs | 4 +++- MoreLinq/AssertCount.cs | 4 +++- MoreLinq/Backsert.cs | 4 ++-- MoreLinq/Batch.cs | 4 +++- MoreLinq/Choose.cs | 6 +++++- MoreLinq/CountBy.cs | 4 +++- MoreLinq/CountDown.cs | 23 +++++++++++++++++------ MoreLinq/DistinctBy.cs | 7 ++++++- MoreLinq/EndsWith.cs | 6 +++--- MoreLinq/ExceptBy.cs | 8 ++++++-- MoreLinq/Exclude.cs | 4 ++-- MoreLinq/FallbackIfEmpty.cs | 11 ++++++++++- MoreLinq/Flatten.cs | 12 +++++++++--- MoreLinq/From.cs | 12 +++++++++--- MoreLinq/FullGroupJoin.cs | 10 ++++++++-- MoreLinq/FullJoin.cs | 12 ++++++++++-- MoreLinq/Generate.cs | 4 +++- MoreLinq/Insert.cs | 4 +++- MoreLinq/Lag.cs | 8 +++++++- MoreLinq/Lead.cs | 8 +++++++- MoreLinq/Maxima.cs | 9 +++++++-- MoreLinq/Move.cs | 6 +++--- MoreLinq/OrderedMerge.cs | 20 ++++++++++++++++++-- MoreLinq/PadStart.cs | 8 +++++++- MoreLinq/Pairwise.cs | 4 +++- MoreLinq/Permutations.cs | 4 +++- MoreLinq/Pipe.cs | 4 +++- MoreLinq/PreScan.cs | 7 ++++++- MoreLinq/Rank.cs | 4 ++-- MoreLinq/RunLengthEncode.cs | 4 ++-- MoreLinq/ScanBy.cs | 9 +++++++-- MoreLinq/Segment.cs | 4 +++- MoreLinq/SkipUntil.cs | 4 +++- MoreLinq/Slice.cs | 6 +++--- MoreLinq/SortedMerge.cs | 4 ++-- MoreLinq/Split.cs | 8 +++++++- MoreLinq/Subsets.cs | 4 +++- MoreLinq/TagFirstLast.cs | 4 +++- MoreLinq/TakeUntil.cs | 4 +++- MoreLinq/Transpose.cs | 4 +++- MoreLinq/Traverse.cs | 8 ++++++-- MoreLinq/Unfold.cs | 9 ++++++++- MoreLinq/Window.cs | 4 +++- MoreLinq/WindowLeft.cs | 4 +++- MoreLinq/WindowRight.cs | 6 +++++- 46 files changed, 236 insertions(+), 73 deletions(-) diff --git a/MoreLinq.Test/RankTest.cs b/MoreLinq.Test/RankTest.cs index ad36c7afb..19bc1d5f9 100644 --- a/MoreLinq.Test/RankTest.cs +++ b/MoreLinq.Test/RankTest.cs @@ -123,7 +123,7 @@ public void TestRankGroupedItems() var sequence = Enumerable.Range(0, count) .Concat(Enumerable.Range(0, count)) .Concat(Enumerable.Range(0, count)); - using var ts = sequence.AsTestingSequence(); + using var ts = sequence.AsTestingSequence(maxEnumerations:2); var result = ts.Rank(); Assert.That(result.Distinct().Count(), Is.EqualTo(count)); diff --git a/MoreLinq/Assert.cs b/MoreLinq/Assert.cs index 1b272d8ed..0836113a6 100644 --- a/MoreLinq/Assert.cs +++ b/MoreLinq/Assert.cs @@ -65,7 +65,9 @@ public static IEnumerable Assert(this IEnumerable sou if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - return _(); IEnumerable _() + return _(source, predicate, errorSelector); + + static IEnumerable _(IEnumerable source, Func predicate, Func? errorSelector) { foreach (var element in source) { diff --git a/MoreLinq/AssertCount.cs b/MoreLinq/AssertCount.cs index 14a55c1a4..f742f36c7 100644 --- a/MoreLinq/AssertCount.cs +++ b/MoreLinq/AssertCount.cs @@ -70,7 +70,9 @@ public static IEnumerable AssertCount(this IEnumerable _() + return _(source, count, errorSelector); + + static IEnumerable _(IEnumerable source, int count, Func errorSelector) { if (source.TryAsCollectionLike() is { Count: var collectionCount } && collectionCount.CompareTo(count) is var comparison && comparison != 0) diff --git a/MoreLinq/Backsert.cs b/MoreLinq/Backsert.cs index 490e7702e..47407bf83 100644 --- a/MoreLinq/Backsert.cs +++ b/MoreLinq/Backsert.cs @@ -65,10 +65,10 @@ public static IEnumerable Backsert(this IEnumerable first, IEnumerable< { < 0 => throw new ArgumentOutOfRangeException(nameof(index), "Index cannot be negative."), 0 => first.Concat(second), - _ => _() + _ => _(first, second, index) }; - IEnumerable _() + static IEnumerable _(IEnumerable first, IEnumerable second, int index) { using var e = first.CountDown(index, ValueTuple.Create).GetEnumerator(); diff --git a/MoreLinq/Batch.cs b/MoreLinq/Batch.cs index 5da60c07a..3d30e4f1f 100644 --- a/MoreLinq/Batch.cs +++ b/MoreLinq/Batch.cs @@ -86,7 +86,9 @@ public static IEnumerable Batch(this IEnumerable _() + return _(source, size, resultSelector); + + static IEnumerable _(IEnumerable source, int size, Func resultSelector) { switch (source) { diff --git a/MoreLinq/Choose.cs b/MoreLinq/Choose.cs index bffbc72d9..865fb3928 100644 --- a/MoreLinq/Choose.cs +++ b/MoreLinq/Choose.cs @@ -55,7 +55,11 @@ public static IEnumerable Choose(this IEnumerable source if (source == null) throw new ArgumentNullException(nameof(source)); if (chooser == null) throw new ArgumentNullException(nameof(chooser)); - return _(); IEnumerable _() + return _(source, chooser); + + static IEnumerable _( + IEnumerable source, + Func chooser) { foreach (var item in source) { diff --git a/MoreLinq/CountBy.cs b/MoreLinq/CountBy.cs index c1f8873ed..0ea540d81 100644 --- a/MoreLinq/CountBy.cs +++ b/MoreLinq/CountBy.cs @@ -55,7 +55,9 @@ public static IEnumerable> CountBy(this I if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); - return _(); IEnumerable> _() + return _(source, keySelector, comparer); + + static IEnumerable> _(IEnumerable source, Func keySelector, IEqualityComparer? comparer) { List keys; List counts; diff --git a/MoreLinq/CountDown.cs b/MoreLinq/CountDown.cs index 53310e79a..4ffdcf92c 100644 --- a/MoreLinq/CountDown.cs +++ b/MoreLinq/CountDown.cs @@ -58,12 +58,16 @@ public static IEnumerable CountDown(this IEnumerable sou if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); return source.TryAsListLike() is { } listLike - ? IterateList(listLike) + ? IterateList(listLike, source, count, resultSelector) : source.TryAsCollectionLike() is { } collectionLike - ? IterateCollection(collectionLike) - : IterateSequence(); + ? IterateCollection(collectionLike, source, count, resultSelector) + : IterateSequence(source, count, resultSelector); - IEnumerable IterateList(ListLike list) + static IEnumerable IterateList( + ListLike list, + IEnumerable source, + int count, + Func resultSelector) { var listCount = list.Count; var countdown = Math.Min(count, listCount); @@ -72,14 +76,21 @@ IEnumerable IterateList(ListLike list) yield return resultSelector(list[i], listCount - i <= count ? --countdown : null); } - IEnumerable IterateCollection(CollectionLike collection) + static IEnumerable IterateCollection( + CollectionLike collection, + IEnumerable source, + int count, + Func resultSelector) { var i = collection.Count; foreach (var item in collection) yield return resultSelector(item, i-- <= count ? i : null); } - IEnumerable IterateSequence() + static IEnumerable IterateSequence( + IEnumerable source, + int count, + Func resultSelector) { var queue = new Queue(Math.Max(1, count + 1)); diff --git a/MoreLinq/DistinctBy.cs b/MoreLinq/DistinctBy.cs index 1079ff814..834e60f70 100644 --- a/MoreLinq/DistinctBy.cs +++ b/MoreLinq/DistinctBy.cs @@ -78,7 +78,12 @@ public static IEnumerable DistinctBy(this IEnumerable _() + return _(source, keySelector, comparer); + + static IEnumerable _( + IEnumerable source, + Func keySelector, + IEqualityComparer? comparer) { var knownKeys = new HashSet(comparer); foreach (var element in source) diff --git a/MoreLinq/EndsWith.cs b/MoreLinq/EndsWith.cs index d414a3dc0..edf76cb28 100644 --- a/MoreLinq/EndsWith.cs +++ b/MoreLinq/EndsWith.cs @@ -78,11 +78,11 @@ public static bool EndsWith(this IEnumerable first, IEnumerable second, return second.TryAsCollectionLike() is { Count: var secondCount } ? first.TryAsCollectionLike() is { Count: var firstCount } && secondCount > firstCount ? false - : Impl(second, secondCount) - : Impl(secondList = second.ToList(), secondList.Count); + : Impl(second, secondCount, first, comparer) + : Impl(secondList = second.ToList(), secondList.Count, first, comparer); #pragma warning restore IDE0075 // Simplify conditional expression - bool Impl(IEnumerable snd, int count) + static bool Impl(IEnumerable snd, int count, IEnumerable first, IEqualityComparer comparer) { using var firstIter = first.TakeLast(count).GetEnumerator(); return snd.All(item => firstIter.MoveNext() && comparer.Equals(firstIter.Current, item)); diff --git a/MoreLinq/ExceptBy.cs b/MoreLinq/ExceptBy.cs index 6a5e1f2c6..2a8fe7911 100644 --- a/MoreLinq/ExceptBy.cs +++ b/MoreLinq/ExceptBy.cs @@ -79,9 +79,13 @@ public static IEnumerable ExceptBy(this IEnumerable Impl() + static IEnumerable Impl( + IEnumerable first, + IEnumerable second, + Func keySelector, + IEqualityComparer? keyComparer) { // TODO Use ToHashSet var keys = new HashSet(second.Select(keySelector), keyComparer); diff --git a/MoreLinq/Exclude.cs b/MoreLinq/Exclude.cs index 455861862..6d416d0fa 100644 --- a/MoreLinq/Exclude.cs +++ b/MoreLinq/Exclude.cs @@ -41,10 +41,10 @@ public static IEnumerable Exclude(this IEnumerable sequence, int startI { < 0 => throw new ArgumentOutOfRangeException(nameof(count)), 0 => sequence, - _ => _() + _ => _(sequence, startIndex, count) }; - IEnumerable _() + static IEnumerable _(IEnumerable sequence, int startIndex, int count) { var index = 0; var endIndex = startIndex + count; diff --git a/MoreLinq/FallbackIfEmpty.cs b/MoreLinq/FallbackIfEmpty.cs index 159a7de4f..a54db158c 100644 --- a/MoreLinq/FallbackIfEmpty.cs +++ b/MoreLinq/FallbackIfEmpty.cs @@ -161,7 +161,16 @@ static IEnumerable FallbackIfEmptyImpl(IEnumerable source, int? count, T? fallback1, T? fallback2, T? fallback3, T? fallback4, IEnumerable? fallback) { - return _(); IEnumerable _() + return _(source, count, fallback1, fallback2, fallback3, fallback4, fallback); + + static IEnumerable _( + IEnumerable source, + int? count, + T? fallback1, + T? fallback2, + T? fallback3, + T? fallback4, + IEnumerable? fallback) { if (source.TryAsCollectionLike() is null or { Count: > 0 }) { diff --git a/MoreLinq/Flatten.cs b/MoreLinq/Flatten.cs index eaee331d2..e3ef35e2e 100644 --- a/MoreLinq/Flatten.cs +++ b/MoreLinq/Flatten.cs @@ -118,14 +118,20 @@ public static IEnumerable< if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); - return _(); + return _(source, selector); - IEnumerable< + static IEnumerable< // Just like "IEnumerable.Current" is null-oblivious, so is this: #nullable disable /*...................*/ object #nullable restore -/*.........................*/ > _() +/*.........................*/ > _(IEnumerable source, + Func< +// Just like "IEnumerable.Current" is null-oblivious, so is this: +#nullable disable +/*....................*/ object, +#nullable restore +/*....................*/ IEnumerable?> selector) { var e = source.GetEnumerator(); var stack = new Stack(); diff --git a/MoreLinq/From.cs b/MoreLinq/From.cs index b9bf76faa..bf2e826d6 100644 --- a/MoreLinq/From.cs +++ b/MoreLinq/From.cs @@ -36,7 +36,9 @@ partial class MoreEnumerable public static IEnumerable From(Func function) { - return _(); IEnumerable _() + return _(function); + + static IEnumerable _(Func function) { #pragma warning disable CA1062 // Validate arguments of public methods yield return function(); @@ -59,7 +61,9 @@ public static IEnumerable From(Func function) public static IEnumerable From(Func function1, Func function2) { - return _(); IEnumerable _() + return _(function1, function2); + + static IEnumerable _(Func function1, Func function2) { #pragma warning disable CA1062 // Validate arguments of public methods yield return function1(); @@ -84,7 +88,9 @@ public static IEnumerable From(Func function1, Func function2) public static IEnumerable From(Func function1, Func function2, Func function3) { - return _(); IEnumerable _() + return _(function1, function2, function3); + + static IEnumerable _(Func function1, Func function2, Func function3) { #pragma warning disable CA1062 // Validate arguments of public methods yield return function1(); diff --git a/MoreLinq/FullGroupJoin.cs b/MoreLinq/FullGroupJoin.cs index 2f6fb56c8..455940cc0 100644 --- a/MoreLinq/FullGroupJoin.cs +++ b/MoreLinq/FullGroupJoin.cs @@ -146,9 +146,15 @@ public static IEnumerable FullGroupJoin if (secondKeySelector == null) throw new ArgumentNullException(nameof(secondKeySelector)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(comparer ?? EqualityComparer.Default); + return _(first, second, firstKeySelector, secondKeySelector, resultSelector, comparer ?? EqualityComparer.Default); - IEnumerable _(IEqualityComparer comparer) + static IEnumerable _( + IEnumerable first, + IEnumerable second, + Func firstKeySelector, + Func secondKeySelector, + Func, IEnumerable, TResult> resultSelector, + IEqualityComparer comparer) { var alookup = Lookup.CreateForJoin(first, firstKeySelector, comparer); var blookup = Lookup.CreateForJoin(second, secondKeySelector, comparer); diff --git a/MoreLinq/FullJoin.cs b/MoreLinq/FullJoin.cs index 9b2da6d12..6d59386e7 100644 --- a/MoreLinq/FullJoin.cs +++ b/MoreLinq/FullJoin.cs @@ -228,9 +228,17 @@ public static IEnumerable FullJoin( if (secondSelector == null) throw new ArgumentNullException(nameof(secondSelector)); if (bothSelector == null) throw new ArgumentNullException(nameof(bothSelector)); - return Impl(); + return Impl(first, second, firstKeySelector, secondKeySelector, firstSelector, secondSelector, bothSelector, comparer); - IEnumerable Impl() + static IEnumerable Impl( + IEnumerable first, + IEnumerable second, + Func firstKeySelector, + Func secondKeySelector, + Func firstSelector, + Func secondSelector, + Func bothSelector, + IEqualityComparer? comparer) { var seconds = second.Select(e => new KeyValuePair(secondKeySelector(e), e)).ToArray(); var secondLookup = seconds.ToLookup(e => e.Key, e => e.Value, comparer); diff --git a/MoreLinq/Generate.cs b/MoreLinq/Generate.cs index a15b38486..519e9785f 100644 --- a/MoreLinq/Generate.cs +++ b/MoreLinq/Generate.cs @@ -45,7 +45,9 @@ public static IEnumerable Generate(TResult initial, Func _() + return _(initial, generator); + + static IEnumerable _(TResult initial, Func generator) { var current = initial; while (true) diff --git a/MoreLinq/Insert.cs b/MoreLinq/Insert.cs index 11c337ba3..774a7df9f 100644 --- a/MoreLinq/Insert.cs +++ b/MoreLinq/Insert.cs @@ -55,7 +55,9 @@ public static IEnumerable Insert(this IEnumerable first, IEnumerable if (second == null) throw new ArgumentNullException(nameof(second)); if (index < 0) throw new ArgumentOutOfRangeException(nameof(index), "Index cannot be negative."); - return _(); IEnumerable _() + return _(first, second, index); + + static IEnumerable _(IEnumerable first, IEnumerable second, int index) { var i = -1; diff --git a/MoreLinq/Lag.cs b/MoreLinq/Lag.cs index 4b532a649..f3ac4cacb 100644 --- a/MoreLinq/Lag.cs +++ b/MoreLinq/Lag.cs @@ -83,7 +83,13 @@ public static IEnumerable Lag(this IEnumerable _() + return _(source, offset, defaultLagValue, resultSelector); + + static IEnumerable _( + IEnumerable source, + int offset, + TSource defaultLagValue, + Func resultSelector) { using var iter = source.GetEnumerator(); diff --git a/MoreLinq/Lead.cs b/MoreLinq/Lead.cs index 2a0b7cbb3..392e55b99 100644 --- a/MoreLinq/Lead.cs +++ b/MoreLinq/Lead.cs @@ -80,7 +80,13 @@ public static IEnumerable Lead(this IEnumerable _() + return _(source, offset, defaultLeadValue, resultSelector); + + static IEnumerable _( + IEnumerable source, + int offset, + TSource defaultLeadValue, + Func resultSelector) { var leadQueue = new Queue(offset); using var iter = source.GetEnumerator(); diff --git a/MoreLinq/Maxima.cs b/MoreLinq/Maxima.cs index 645ea374d..a826c5a03 100644 --- a/MoreLinq/Maxima.cs +++ b/MoreLinq/Maxima.cs @@ -312,10 +312,15 @@ static IEnumerable ExtremaBy( Extrema extrema, int? limit, Func selector, Func comparer) { - foreach (var item in Extrema()) + var extremaResults = Extrema(source, extrema, limit, selector, comparer); + + foreach (var item in extremaResults) yield return item; - IEnumerable Extrema() + static IEnumerable Extrema( + IEnumerable source, + Extrema extrema, int? limit, + Func selector, Func comparer) { using var e = source.GetEnumerator(); diff --git a/MoreLinq/Move.cs b/MoreLinq/Move.cs index 43e38d2d7..73dbfc849 100644 --- a/MoreLinq/Move.cs +++ b/MoreLinq/Move.cs @@ -58,10 +58,10 @@ public static IEnumerable Move(this IEnumerable source, int fromIndex, return source; return toIndex < fromIndex - ? _(toIndex, fromIndex - toIndex, count) - : _(fromIndex, count, toIndex - fromIndex); + ? _(source, toIndex, fromIndex - toIndex, count) + : _(source, fromIndex, count, toIndex - fromIndex); - IEnumerable _(int bufferStartIndex, int bufferSize, int bufferYieldIndex) + static IEnumerable _(IEnumerable source, int bufferStartIndex, int bufferSize, int bufferYieldIndex) { var hasMore = true; bool MoveNext(IEnumerator e) => hasMore && (hasMore = e.MoveNext()); diff --git a/MoreLinq/OrderedMerge.cs b/MoreLinq/OrderedMerge.cs index 0e30e1517..41d410e64 100644 --- a/MoreLinq/OrderedMerge.cs +++ b/MoreLinq/OrderedMerge.cs @@ -282,9 +282,25 @@ public static IEnumerable OrderedMerge( if (bothSelector == null) throw new ArgumentNullException(nameof(bothSelector)); if (secondSelector == null) throw new ArgumentNullException(nameof(secondSelector)); - return _(comparer ?? Comparer.Default); + return _( + first, + second, + firstKeySelector, + secondKeySelector, + firstSelector, + secondSelector, + bothSelector, + comparer ?? Comparer.Default); - IEnumerable _(IComparer comparer) + static IEnumerable _( + IEnumerable first, + IEnumerable second, + Func firstKeySelector, + Func secondKeySelector, + Func firstSelector, + Func secondSelector, + Func bothSelector, + IComparer comparer) { using var e1 = first.GetEnumerator(); using var e2 = second.GetEnumerator(); diff --git a/MoreLinq/PadStart.cs b/MoreLinq/PadStart.cs index 5e9e380d1..639e15305 100644 --- a/MoreLinq/PadStart.cs +++ b/MoreLinq/PadStart.cs @@ -117,7 +117,13 @@ public static IEnumerable PadStart(this IEnumerable s static IEnumerable PadStartImpl(IEnumerable source, int width, T? padding, Func? paddingSelector) { - return _(); IEnumerable _() + return _(source, width, padding, paddingSelector); + + static IEnumerable _( + IEnumerable source, + int width, + T? padding, + Func? paddingSelector) { if (source.TryAsCollectionLike() is { Count: var collectionCount } && collectionCount < width) { diff --git a/MoreLinq/Pairwise.cs b/MoreLinq/Pairwise.cs index 9e262e85d..6b9c4347d 100644 --- a/MoreLinq/Pairwise.cs +++ b/MoreLinq/Pairwise.cs @@ -53,7 +53,9 @@ public static IEnumerable Pairwise(this IEnumerable _() + return _(source, resultSelector); + + static IEnumerable _(IEnumerable source, Func resultSelector) { using var e = source.GetEnumerator(); diff --git a/MoreLinq/Permutations.cs b/MoreLinq/Permutations.cs index 2324750bb..dd60235a4 100644 --- a/MoreLinq/Permutations.cs +++ b/MoreLinq/Permutations.cs @@ -49,7 +49,9 @@ public static IEnumerable> Permutations(this IEnumerable sequence { if (sequence == null) throw new ArgumentNullException(nameof(sequence)); - return _(); IEnumerable> _() + return _(sequence); + + static IEnumerable> _(IEnumerable sequence) { // The algorithm used to generate permutations uses the fact that any set can be put // into 1-to-1 correspondence with the set of ordinals number (0..n). The diff --git a/MoreLinq/Pipe.cs b/MoreLinq/Pipe.cs index 474ef725e..94c5c6138 100644 --- a/MoreLinq/Pipe.cs +++ b/MoreLinq/Pipe.cs @@ -43,7 +43,9 @@ public static IEnumerable Pipe(this IEnumerable source, Action actio if (source == null) throw new ArgumentNullException(nameof(source)); if (action == null) throw new ArgumentNullException(nameof(action)); - return _(); IEnumerable _() + return _(source, action); + + static IEnumerable _(IEnumerable source, Action action) { foreach (var element in source) { diff --git a/MoreLinq/PreScan.cs b/MoreLinq/PreScan.cs index 88aa8f57c..a23763722 100644 --- a/MoreLinq/PreScan.cs +++ b/MoreLinq/PreScan.cs @@ -59,7 +59,12 @@ public static IEnumerable PreScan( if (source == null) throw new ArgumentNullException(nameof(source)); if (transformation == null) throw new ArgumentNullException(nameof(transformation)); - return _(); IEnumerable _() + return _(source, transformation, identity); + + static IEnumerable _( + IEnumerable source, + Func transformation, + TSource identity) { var aggregator = identity; using var e = source.GetEnumerator(); diff --git a/MoreLinq/Rank.cs b/MoreLinq/Rank.cs index 4e5586382..c0bfb9abe 100644 --- a/MoreLinq/Rank.cs +++ b/MoreLinq/Rank.cs @@ -77,9 +77,9 @@ public static IEnumerable RankBy(this IEnumerable s if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); - return _(comparer ?? Comparer.Default); + return _(source, keySelector, comparer ?? Comparer.Default); - IEnumerable _(IComparer comparer) + static IEnumerable _(IEnumerable source, Func keySelector, IComparer< TKey> comparer) { source = source.ToArray(); // avoid enumerating source twice diff --git a/MoreLinq/RunLengthEncode.cs b/MoreLinq/RunLengthEncode.cs index 232c38e37..f701de31f 100644 --- a/MoreLinq/RunLengthEncode.cs +++ b/MoreLinq/RunLengthEncode.cs @@ -49,9 +49,9 @@ public static IEnumerable> RunLengthEncode(this IEnumera { if (sequence == null) throw new ArgumentNullException(nameof(sequence)); - return _(comparer ?? EqualityComparer.Default); + return _(sequence, comparer ?? EqualityComparer.Default); - IEnumerable> _(IEqualityComparer comparer) + static IEnumerable> _(IEnumerable sequence, IEqualityComparer comparer) { // This implementation could also have been written using a foreach loop, // but it proved to be easier to deal with edge certain cases that occur diff --git a/MoreLinq/ScanBy.cs b/MoreLinq/ScanBy.cs index 3ca138ced..d12d1de7f 100644 --- a/MoreLinq/ScanBy.cs +++ b/MoreLinq/ScanBy.cs @@ -85,9 +85,14 @@ public static IEnumerable> ScanBy.Default); + return _(source, keySelector, seedSelector, accumulator, comparer ?? EqualityComparer.Default); - IEnumerable> _(IEqualityComparer comparer) + static IEnumerable> _( + IEnumerable source, + Func keySelector, + Func seedSelector, + Func accumulator, + IEqualityComparer comparer) { var stateByKey = new Collections.Dictionary(comparer); diff --git a/MoreLinq/Segment.cs b/MoreLinq/Segment.cs index 859f59014..e29ecdce0 100644 --- a/MoreLinq/Segment.cs +++ b/MoreLinq/Segment.cs @@ -74,7 +74,9 @@ public static IEnumerable> Segment(this IEnumerable source, if (source == null) throw new ArgumentNullException(nameof(source)); if (newSegmentPredicate == null) throw new ArgumentNullException(nameof(newSegmentPredicate)); - return _(); IEnumerable> _() + return _(source, newSegmentPredicate); + + static IEnumerable> _(IEnumerable source, Func newSegmentPredicate) { using var e = source.GetEnumerator(); diff --git a/MoreLinq/SkipUntil.cs b/MoreLinq/SkipUntil.cs index 7a738c35c..07a45f667 100644 --- a/MoreLinq/SkipUntil.cs +++ b/MoreLinq/SkipUntil.cs @@ -57,7 +57,9 @@ public static IEnumerable SkipUntil(this IEnumerable if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - return _(); IEnumerable _() + return _(source, predicate); + + static IEnumerable _(IEnumerable source, Func predicate) { using var enumerator = source.GetEnumerator(); diff --git a/MoreLinq/Slice.cs b/MoreLinq/Slice.cs index 86f8306fa..5867d58fa 100644 --- a/MoreLinq/Slice.cs +++ b/MoreLinq/Slice.cs @@ -55,12 +55,12 @@ public static IEnumerable Slice(this IEnumerable sequence, int startInd return sequence switch { - IList list => SliceList(list.Count, i => list[i]), - IReadOnlyList list => SliceList(list.Count, i => list[i]), + IList list => SliceList(startIndex, count, list.Count, i => list[i]), + IReadOnlyList list => SliceList(startIndex, count, list.Count, i => list[i]), var seq => seq.Skip(startIndex).Take(count) }; - IEnumerable SliceList(int listCount, Func indexer) + static IEnumerable SliceList(int startIndex, int count, int listCount, Func indexer) { var countdown = count; var index = startIndex; diff --git a/MoreLinq/SortedMerge.cs b/MoreLinq/SortedMerge.cs index 03757dcb5..836ab42c6 100644 --- a/MoreLinq/SortedMerge.cs +++ b/MoreLinq/SortedMerge.cs @@ -96,7 +96,7 @@ public static IEnumerable SortedMerge(this IEnumerable comparer.Compare(b, a) > 0; // return the sorted merge result - return Impl(new[] { source }.Concat(otherSequences)); + return Impl(precedenceFunc, new[] { source }.Concat(otherSequences)); // Private implementation method that performs a merge of multiple, ordered sequences using // a precedence function which encodes order-sensitive comparison logic based on the caller's arguments. @@ -109,7 +109,7 @@ public static IEnumerable SortedMerge(this IEnumerableN => otherSequences.Count()+1. - IEnumerable Impl(IEnumerable> sequences) + static IEnumerable Impl(Func precedenceFunc, IEnumerable> sequences) { using var disposables = new DisposableGroup(sequences.Select(e => e.GetEnumerator()).Acquire()); diff --git a/MoreLinq/Split.cs b/MoreLinq/Split.cs index 935537aa5..5edb1f0ba 100644 --- a/MoreLinq/Split.cs +++ b/MoreLinq/Split.cs @@ -267,7 +267,13 @@ public static IEnumerable Split(this IEnumerable _() + return _(source, separatorFunc, count, resultSelector); + + static IEnumerable _( + IEnumerable source, + Func separatorFunc, + int count, + Func, TResult> resultSelector) { if (count == 0) // No splits? { diff --git a/MoreLinq/Subsets.cs b/MoreLinq/Subsets.cs index f1167152f..10900e4a9 100644 --- a/MoreLinq/Subsets.cs +++ b/MoreLinq/Subsets.cs @@ -51,7 +51,9 @@ public static IEnumerable> Subsets(this IEnumerable sequence) { if (sequence == null) throw new ArgumentNullException(nameof(sequence)); - return _(); IEnumerable> _() + return _(sequence); + + static IEnumerable> _(IEnumerable sequence) { var sequenceAsList = sequence.ToList(); var sequenceLength = sequenceAsList.Count; diff --git a/MoreLinq/TagFirstLast.cs b/MoreLinq/TagFirstLast.cs index 61d90f6e7..705b22a04 100644 --- a/MoreLinq/TagFirstLast.cs +++ b/MoreLinq/TagFirstLast.cs @@ -59,7 +59,9 @@ public static IEnumerable TagFirstLast(this IEnumerab if (source == null) throw new ArgumentNullException(nameof(source)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(); IEnumerable _() + return _(source, resultSelector); + + static IEnumerable _(IEnumerable source, Func resultSelector) { using var enumerator = source.GetEnumerator(); diff --git a/MoreLinq/TakeUntil.cs b/MoreLinq/TakeUntil.cs index bceb05c22..3488a3bec 100644 --- a/MoreLinq/TakeUntil.cs +++ b/MoreLinq/TakeUntil.cs @@ -57,7 +57,9 @@ public static IEnumerable TakeUntil(this IEnumerable if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - return _(); IEnumerable _() + return _(source, predicate); + + static IEnumerable _(IEnumerable source, Func predicate) { foreach (var item in source) { diff --git a/MoreLinq/Transpose.cs b/MoreLinq/Transpose.cs index eb1a151bd..e6841a9ca 100644 --- a/MoreLinq/Transpose.cs +++ b/MoreLinq/Transpose.cs @@ -56,7 +56,9 @@ public static IEnumerable> Transpose(this IEnumerable> _() + return _(source); + + static IEnumerable> _(IEnumerable> source) { #pragma warning disable IDE0007 // Use implicit type (false positive) IEnumerator?[] enumerators = source.Select(e => e.GetEnumerator()).Acquire(); diff --git a/MoreLinq/Traverse.cs b/MoreLinq/Traverse.cs index 4fb46b5b8..1ec5b0d9b 100644 --- a/MoreLinq/Traverse.cs +++ b/MoreLinq/Traverse.cs @@ -48,7 +48,9 @@ public static IEnumerable TraverseBreadthFirst(T root, Func _() + return _(root, childrenSelector); + + static IEnumerable _(T root, Func> childrenSelector) { var queue = new Queue(); queue.Enqueue(root); @@ -88,7 +90,9 @@ public static IEnumerable TraverseDepthFirst(T root, Func _() + return _(root, childrenSelector); + + static IEnumerable _(T root, Func> childrenSelector) { var stack = new Stack(); stack.Push(root); diff --git a/MoreLinq/Unfold.cs b/MoreLinq/Unfold.cs index d6f5b8738..380a10858 100644 --- a/MoreLinq/Unfold.cs +++ b/MoreLinq/Unfold.cs @@ -61,7 +61,14 @@ public static IEnumerable Unfold( if (stateSelector == null) throw new ArgumentNullException(nameof(stateSelector)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(state); IEnumerable _(TState initialState) + return _(state, generator, predicate, stateSelector, resultSelector); + + static IEnumerable _( + TState initialState, + Func generator, + Func predicate, + Func stateSelector, + Func resultSelector) { for (var state = initialState; ;) { diff --git a/MoreLinq/Window.cs b/MoreLinq/Window.cs index 04b1ddefd..e3de531f7 100644 --- a/MoreLinq/Window.cs +++ b/MoreLinq/Window.cs @@ -44,7 +44,9 @@ public static IEnumerable> Window(this IEnumerable> _() + return _(source, size); + + static IEnumerable> _(IEnumerable source, int size) { using var iter = source.GetEnumerator(); diff --git a/MoreLinq/WindowLeft.cs b/MoreLinq/WindowLeft.cs index fdcd72803..43dc0ad8a 100644 --- a/MoreLinq/WindowLeft.cs +++ b/MoreLinq/WindowLeft.cs @@ -63,7 +63,9 @@ public static IEnumerable> WindowLeft(this IEnumerable> _() + return _(source, size); + + static IEnumerable> _(IEnumerable source, int size) { var window = new List(); foreach (var item in source) diff --git a/MoreLinq/WindowRight.cs b/MoreLinq/WindowRight.cs index 4172c3d6d..52bd9a050 100644 --- a/MoreLinq/WindowRight.cs +++ b/MoreLinq/WindowRight.cs @@ -78,7 +78,11 @@ static IEnumerable> WindowRightWhile( if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - return _(); IEnumerable> _() + return _(source, predicate); + + static IEnumerable> _( + IEnumerable source, + Func predicate) { var window = new List(); foreach (var item in source) From 0ba576804c8bc1168af5e38cb06bee0b7733b3be Mon Sep 17 00:00:00 2001 From: Jacob Silas Bentley Date: Sun, 28 Apr 2024 08:54:47 +0100 Subject: [PATCH 02/16] Updated test so that result of the Rank method is only iterated once. --- MoreLinq.Test/RankTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MoreLinq.Test/RankTest.cs b/MoreLinq.Test/RankTest.cs index 19bc1d5f9..6e84dc719 100644 --- a/MoreLinq.Test/RankTest.cs +++ b/MoreLinq.Test/RankTest.cs @@ -123,8 +123,8 @@ public void TestRankGroupedItems() var sequence = Enumerable.Range(0, count) .Concat(Enumerable.Range(0, count)) .Concat(Enumerable.Range(0, count)); - using var ts = sequence.AsTestingSequence(maxEnumerations:2); - var result = ts.Rank(); + using var ts = sequence.AsTestingSequence(); + var result = ts.Rank().ToArray(); Assert.That(result.Distinct().Count(), Is.EqualTo(count)); Assert.That(result, Is.EqualTo(sequence.Reverse().Select(x => x + 1))); From 5d0067ab78e5a1d95f0006daa26d5bc0e61df18c Mon Sep 17 00:00:00 2001 From: Jacob Silas Bentley Date: Mon, 29 Apr 2024 05:39:08 +0100 Subject: [PATCH 03/16] Updated method argument order for consistency --- MoreLinq/EndsWith.cs | 8 ++++---- MoreLinq/SortedMerge.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MoreLinq/EndsWith.cs b/MoreLinq/EndsWith.cs index edf76cb28..99ce9428f 100644 --- a/MoreLinq/EndsWith.cs +++ b/MoreLinq/EndsWith.cs @@ -78,14 +78,14 @@ public static bool EndsWith(this IEnumerable first, IEnumerable second, return second.TryAsCollectionLike() is { Count: var secondCount } ? first.TryAsCollectionLike() is { Count: var firstCount } && secondCount > firstCount ? false - : Impl(second, secondCount, first, comparer) - : Impl(secondList = second.ToList(), secondList.Count, first, comparer); + : Impl(first, second, secondCount, comparer) + : Impl(first, secondList = second.ToList(), secondList.Count, comparer); #pragma warning restore IDE0075 // Simplify conditional expression - static bool Impl(IEnumerable snd, int count, IEnumerable first, IEqualityComparer comparer) + static bool Impl(IEnumerable first, IEnumerable second, int count, IEqualityComparer comparer) { using var firstIter = first.TakeLast(count).GetEnumerator(); - return snd.All(item => firstIter.MoveNext() && comparer.Equals(firstIter.Current, item)); + return second.All(item => firstIter.MoveNext() && comparer.Equals(firstIter.Current, item)); } } } diff --git a/MoreLinq/SortedMerge.cs b/MoreLinq/SortedMerge.cs index 836ab42c6..04d328099 100644 --- a/MoreLinq/SortedMerge.cs +++ b/MoreLinq/SortedMerge.cs @@ -96,7 +96,7 @@ public static IEnumerable SortedMerge(this IEnumerable comparer.Compare(b, a) > 0; // return the sorted merge result - return Impl(precedenceFunc, new[] { source }.Concat(otherSequences)); + return Impl(new[] { source }.Concat(otherSequences), precedenceFunc); // Private implementation method that performs a merge of multiple, ordered sequences using // a precedence function which encodes order-sensitive comparison logic based on the caller's arguments. @@ -109,7 +109,7 @@ public static IEnumerable SortedMerge(this IEnumerableN => otherSequences.Count()+1. - static IEnumerable Impl(Func precedenceFunc, IEnumerable> sequences) + static IEnumerable Impl(IEnumerable> sequences, Func precedenceFunc) { using var disposables = new DisposableGroup(sequences.Select(e => e.GetEnumerator()).Acquire()); From 3fea37278eb4a16f7a1d554c7b7285cbc7c6306d Mon Sep 17 00:00:00 2001 From: JacobSilasBentley <30935918+JacobSilasBentley@users.noreply.github.com> Date: Mon, 29 Apr 2024 06:08:14 +0100 Subject: [PATCH 04/16] Removed erroneous space. Co-authored-by: Atif Aziz --- MoreLinq/Rank.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoreLinq/Rank.cs b/MoreLinq/Rank.cs index c0bfb9abe..4232fac00 100644 --- a/MoreLinq/Rank.cs +++ b/MoreLinq/Rank.cs @@ -79,7 +79,7 @@ public static IEnumerable RankBy(this IEnumerable s return _(source, keySelector, comparer ?? Comparer.Default); - static IEnumerable _(IEnumerable source, Func keySelector, IComparer< TKey> comparer) + static IEnumerable _(IEnumerable source, Func keySelector, IComparer comparer) { source = source.ToArray(); // avoid enumerating source twice From 236df7349aec2b848ef7342bfc86a411930818bd Mon Sep 17 00:00:00 2001 From: JacobSilasBentley <30935918+JacobSilasBentley@users.noreply.github.com> Date: Mon, 29 Apr 2024 06:09:41 +0100 Subject: [PATCH 05/16] Calling ToArray on the result of the Rank method to avoid multiple enumerations when testing the result. Co-authored-by: Atif Aziz --- MoreLinq.Test/RankTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MoreLinq.Test/RankTest.cs b/MoreLinq.Test/RankTest.cs index 19bc1d5f9..6e84dc719 100644 --- a/MoreLinq.Test/RankTest.cs +++ b/MoreLinq.Test/RankTest.cs @@ -123,8 +123,8 @@ public void TestRankGroupedItems() var sequence = Enumerable.Range(0, count) .Concat(Enumerable.Range(0, count)) .Concat(Enumerable.Range(0, count)); - using var ts = sequence.AsTestingSequence(maxEnumerations:2); - var result = ts.Rank(); + using var ts = sequence.AsTestingSequence(); + var result = ts.Rank().ToArray(); Assert.That(result.Distinct().Count(), Is.EqualTo(count)); Assert.That(result, Is.EqualTo(sequence.Reverse().Select(x => x + 1))); From 2d62f8d1a71b43623b5970d5c85cb8ab5abe55dc Mon Sep 17 00:00:00 2001 From: JacobSilasBentley <30935918+JacobSilasBentley@users.noreply.github.com> Date: Mon, 29 Apr 2024 06:10:17 +0100 Subject: [PATCH 06/16] Updated method argument alignment. Co-authored-by: Atif Aziz --- MoreLinq/OrderedMerge.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/MoreLinq/OrderedMerge.cs b/MoreLinq/OrderedMerge.cs index 41d410e64..3f4a7e5e8 100644 --- a/MoreLinq/OrderedMerge.cs +++ b/MoreLinq/OrderedMerge.cs @@ -282,15 +282,14 @@ public static IEnumerable OrderedMerge( if (bothSelector == null) throw new ArgumentNullException(nameof(bothSelector)); if (secondSelector == null) throw new ArgumentNullException(nameof(secondSelector)); - return _( - first, - second, - firstKeySelector, - secondKeySelector, - firstSelector, - secondSelector, - bothSelector, - comparer ?? Comparer.Default); + return _(first, + second, + firstKeySelector, + secondKeySelector, + firstSelector, + secondSelector, + bothSelector, + comparer ?? Comparer.Default); static IEnumerable _( IEnumerable first, From 77c50e87d0633a10b6453d0e8cff3929ec059551 Mon Sep 17 00:00:00 2001 From: JacobSilasBentley <30935918+JacobSilasBentley@users.noreply.github.com> Date: Mon, 29 Apr 2024 06:11:33 +0100 Subject: [PATCH 07/16] Inlined the result of the Extrema method. Co-authored-by: Atif Aziz --- MoreLinq/Maxima.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MoreLinq/Maxima.cs b/MoreLinq/Maxima.cs index a826c5a03..9f4a35c1a 100644 --- a/MoreLinq/Maxima.cs +++ b/MoreLinq/Maxima.cs @@ -312,9 +312,7 @@ static IEnumerable ExtremaBy( Extrema extrema, int? limit, Func selector, Func comparer) { - var extremaResults = Extrema(source, extrema, limit, selector, comparer); - - foreach (var item in extremaResults) + foreach (var item in Extrema(source, extrema, limit, selector, comparer)) yield return item; static IEnumerable Extrema( From 72f6f1b21dc325acc8560fe9d4ce5b715ec16b61 Mon Sep 17 00:00:00 2001 From: JacobSilasBentley <30935918+JacobSilasBentley@users.noreply.github.com> Date: Mon, 29 Apr 2024 06:12:55 +0100 Subject: [PATCH 08/16] Updated alignment of arguments. Co-authored-by: Atif Aziz --- MoreLinq/Flatten.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoreLinq/Flatten.cs b/MoreLinq/Flatten.cs index e3ef35e2e..086ed2394 100644 --- a/MoreLinq/Flatten.cs +++ b/MoreLinq/Flatten.cs @@ -131,7 +131,7 @@ static IEnumerable< #nullable disable /*....................*/ object, #nullable restore -/*....................*/ IEnumerable?> selector) +/*........................*/ IEnumerable?> selector) { var e = source.GetEnumerator(); var stack = new Stack(); From 955a6fa5aef7b53dd2886a1a032ce85317735071 Mon Sep 17 00:00:00 2001 From: Jacob Silas Bentley Date: Mon, 29 Apr 2024 06:28:51 +0100 Subject: [PATCH 09/16] Remove unused method argument. --- MoreLinq/CountDown.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MoreLinq/CountDown.cs b/MoreLinq/CountDown.cs index 4ffdcf92c..aa0da23ce 100644 --- a/MoreLinq/CountDown.cs +++ b/MoreLinq/CountDown.cs @@ -58,14 +58,13 @@ public static IEnumerable CountDown(this IEnumerable sou if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); return source.TryAsListLike() is { } listLike - ? IterateList(listLike, source, count, resultSelector) + ? IterateList(listLike, count, resultSelector) : source.TryAsCollectionLike() is { } collectionLike - ? IterateCollection(collectionLike, source, count, resultSelector) + ? IterateCollection(collectionLike, count, resultSelector) : IterateSequence(source, count, resultSelector); static IEnumerable IterateList( ListLike list, - IEnumerable source, int count, Func resultSelector) { @@ -78,7 +77,6 @@ static IEnumerable IterateList( static IEnumerable IterateCollection( CollectionLike collection, - IEnumerable source, int count, Func resultSelector) { From 2241256cf4bd3f99d7b4247ba73a83e9b2cf728f Mon Sep 17 00:00:00 2001 From: Jacob Silas Bentley Date: Mon, 29 Apr 2024 08:02:58 +0100 Subject: [PATCH 10/16] Updated more Methods to use private static methods instead of closures. --- MoreLinq/Cartesian.g.cs | 28 +++++++++++++++++------ MoreLinq/Cartesian.g.tt | 4 +++- MoreLinq/Experimental/Async/Merge.cs | 4 ++-- MoreLinq/Experimental/Await.cs | 13 +++++++++-- MoreLinq/Experimental/Batch.cs | 7 +++++- MoreLinq/Experimental/Memoize.cs | 34 +++++++++++++++------------- MoreLinq/Subsets.cs | 4 +++- 7 files changed, 64 insertions(+), 30 deletions(-) diff --git a/MoreLinq/Cartesian.g.cs b/MoreLinq/Cartesian.g.cs index 64694c065..891eefa29 100644 --- a/MoreLinq/Cartesian.g.cs +++ b/MoreLinq/Cartesian.g.cs @@ -69,7 +69,9 @@ public static IEnumerable Cartesian( if (second == null) throw new ArgumentNullException(nameof(second)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(); IEnumerable _() + return _(first, second, resultSelector); + + static IEnumerable _(IEnumerable first, IEnumerable second, Func resultSelector) { IEnumerable secondMemo; @@ -123,7 +125,9 @@ public static IEnumerable Cartesian( if (third == null) throw new ArgumentNullException(nameof(third)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(); IEnumerable _() + return _(first, second, third, resultSelector); + + static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -185,7 +189,9 @@ public static IEnumerable Cartesian( if (fourth == null) throw new ArgumentNullException(nameof(fourth)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(); IEnumerable _() + return _(first, second, third, fourth, resultSelector); + + static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -255,7 +261,9 @@ public static IEnumerable Cartesian( if (fifth == null) throw new ArgumentNullException(nameof(fifth)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(); IEnumerable _() + return _(first, second, third, fourth, fifth, resultSelector); + + static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, IEnumerable fifth, Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -333,7 +341,9 @@ public static IEnumerable Cartesian( if (sixth == null) throw new ArgumentNullException(nameof(sixth)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(); IEnumerable _() + return _(first, second, third, fourth, fifth, sixth, resultSelector); + + static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, IEnumerable fifth, IEnumerable sixth, Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -419,7 +429,9 @@ public static IEnumerable Cartesian _() + return _(first, second, third, fourth, fifth, sixth, seventh, resultSelector); + + static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, IEnumerable fifth, IEnumerable sixth, IEnumerable seventh, Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -513,7 +525,9 @@ public static IEnumerable Cartesian _() + return _(first, second, third, fourth, fifth, sixth, seventh, eighth, resultSelector); + + static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, IEnumerable fifth, IEnumerable sixth, IEnumerable seventh, IEnumerable eighth, Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; diff --git a/MoreLinq/Cartesian.g.tt b/MoreLinq/Cartesian.g.tt index 4bc112cea..16c497dc5 100644 --- a/MoreLinq/Cartesian.g.tt +++ b/MoreLinq/Cartesian.g.tt @@ -115,7 +115,9 @@ Func<<#= string.Join(", ", from x in o.Arguments select "T" + x.Number) #>, TRes <# } #> if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(); IEnumerable _() + return _(<#= string.Join(", ", from x in o.Arguments select x.Ordinal) #>, resultSelector); + + static IEnumerable _(<#= string.Join(", ", from x in o.Arguments select "IEnumerable " + x.Ordinal) #>, Func<<#= string.Join(", ", from x in o.Arguments select "T" + x.Number) #>, TResult> resultSelector) { <# foreach (var arg in o.Arguments.Skip(1)) { #> IEnumerable> <#= arg.Ordinal #>Memo; diff --git a/MoreLinq/Experimental/Async/Merge.cs b/MoreLinq/Experimental/Async/Merge.cs index f414eaa7d..03ae97c82 100644 --- a/MoreLinq/Experimental/Async/Merge.cs +++ b/MoreLinq/Experimental/Async/Merge.cs @@ -85,9 +85,9 @@ public static IAsyncEnumerable Merge(this IEnumerable> if (sources is null) throw new ArgumentNullException(nameof(sources)); if (maxConcurrent <= 0) throw new ArgumentOutOfRangeException(nameof(maxConcurrent)); - return Async(); + return Async(sources, maxConcurrent); - async IAsyncEnumerable Async([EnumeratorCancellation]CancellationToken cancellationToken = default) + static async IAsyncEnumerable Async(IEnumerable> sources, int maxConcurrent, [EnumeratorCancellation]CancellationToken cancellationToken = default) { using var thisCancellationTokenSource = new CancellationTokenSource(); diff --git a/MoreLinq/Experimental/Await.cs b/MoreLinq/Experimental/Await.cs index 717a209bc..dca801b51 100644 --- a/MoreLinq/Experimental/Await.cs +++ b/MoreLinq/Experimental/Await.cs @@ -424,11 +424,20 @@ public static IAwaitQuery AwaitCompletion( return AwaitQuery.Create( - options => Impl(options.MaxConcurrency, + options => Impl(source, + evaluator, + resultSelector, + options.MaxConcurrency, options.Scheduler ?? TaskScheduler.Default, options.PreserveOrder)); - IEnumerable Impl(int? maxConcurrency, TaskScheduler scheduler, bool ordered) + static IEnumerable Impl( + IEnumerable source, + Func> evaluator, + Func, TResult> resultSelector, + int? maxConcurrency, + TaskScheduler scheduler, + bool ordered) { // A separate task will enumerate the source and launch tasks. // It will post all progress as notices to the collection below. diff --git a/MoreLinq/Experimental/Batch.cs b/MoreLinq/Experimental/Batch.cs index 9e9c28425..d3c444804 100644 --- a/MoreLinq/Experimental/Batch.cs +++ b/MoreLinq/Experimental/Batch.cs @@ -145,7 +145,12 @@ public static IEnumerable if (bucketProjectionSelector == null) throw new ArgumentNullException(nameof(bucketProjectionSelector)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); - return _(); IEnumerable _() + return _(source, size, pool, bucketProjectionSelector, resultSelector); + + static IEnumerable _( + IEnumerable source, int size, ArrayPool pool, + Func, IEnumerable> bucketProjectionSelector, + Func, TResult> resultSelector) { using var batch = source.Batch(size, pool); var bucket = bucketProjectionSelector(batch.CurrentBuffer); diff --git a/MoreLinq/Experimental/Memoize.cs b/MoreLinq/Experimental/Memoize.cs index 8e6a3c6b5..fb2311bc5 100644 --- a/MoreLinq/Experimental/Memoize.cs +++ b/MoreLinq/Experimental/Memoize.cs @@ -96,53 +96,55 @@ public IEnumerator GetEnumerator() } } - return _(); IEnumerator _() + return _(this); + + static IEnumerator _(MemoizedEnumerable memoized) { var index = 0; while (true) { T current; - lock (this.locker) + lock (memoized.locker) { - if (this.cache == null) // Cache disposed during iteration? + if (memoized.cache == null) // Cache disposed during iteration? throw new ObjectDisposedException(nameof(MemoizedEnumerable)); - if (index >= this.cache.Count) + if (index >= memoized.cache.Count) { - if (index == this.errorIndex) - Assume.NotNull(this.error).Throw(); + if (index == memoized.errorIndex) + Assume.NotNull(memoized.error).Throw(); - if (this.sourceEnumerator == null) + if (memoized.sourceEnumerator == null) break; bool moved; try { - moved = this.sourceEnumerator.MoveNext(); + moved = memoized.sourceEnumerator.MoveNext(); } catch (Exception ex) { - this.error = ExceptionDispatchInfo.Capture(ex); - this.errorIndex = index; - this.sourceEnumerator.Dispose(); - this.sourceEnumerator = null; + memoized.error = ExceptionDispatchInfo.Capture(ex); + memoized.errorIndex = index; + memoized.sourceEnumerator.Dispose(); + memoized.sourceEnumerator = null; throw; } if (moved) { - this.cache.Add(this.sourceEnumerator.Current); + memoized.cache.Add(memoized.sourceEnumerator.Current); } else { - this.sourceEnumerator.Dispose(); - this.sourceEnumerator = null; + memoized.sourceEnumerator.Dispose(); + memoized.sourceEnumerator = null; break; } } - current = this.cache[index]; + current = memoized.cache[index]; } yield return current; diff --git a/MoreLinq/Subsets.cs b/MoreLinq/Subsets.cs index 10900e4a9..9ffe27f05 100644 --- a/MoreLinq/Subsets.cs +++ b/MoreLinq/Subsets.cs @@ -115,7 +115,9 @@ public static IEnumerable> Subsets(this IEnumerable sequence, int // preconditions. This however, needs to be carefully considered - and perhaps // may change after further thought and review. - return _(); IEnumerable> _() + return _(sequence, subsetSize); + + static IEnumerable> _(IEnumerable sequence, int subsetSize) { foreach (var subset in Subsets(sequence.ToList(), subsetSize)) yield return subset; From b6608c448604545f7249d54e267b297a6f4105aa Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Mon, 29 Apr 2024 22:49:09 +0200 Subject: [PATCH 11/16] Fix alignment of "Flatten" (type) args --- MoreLinq/Flatten.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MoreLinq/Flatten.cs b/MoreLinq/Flatten.cs index 086ed2394..b2f5eb739 100644 --- a/MoreLinq/Flatten.cs +++ b/MoreLinq/Flatten.cs @@ -123,15 +123,15 @@ public static IEnumerable< static IEnumerable< // Just like "IEnumerable.Current" is null-oblivious, so is this: #nullable disable -/*...................*/ object +/*..........................*/ object #nullable restore -/*.........................*/ > _(IEnumerable source, - Func< +/*.................................*/ > _(IEnumerable source, + Func< // Just like "IEnumerable.Current" is null-oblivious, so is this: #nullable disable -/*....................*/ object, +/*..........................................*/ object, #nullable restore -/*........................*/ IEnumerable?> selector) +/*..................................................*/ IEnumerable?> selector) { var e = source.GetEnumerator(); var stack = new Stack(); From aca7772f0fa569b40d227acb721bd15a81b7d9bf Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Mon, 29 Apr 2024 22:50:47 +0200 Subject: [PATCH 12/16] Format "Cartesian" args layout to be consistenly vertical --- MoreLinq/Cartesian.g.cs | 56 +++++++++++++++++++++++++++++++++++------ MoreLinq/Cartesian.g.tt | 7 +++++- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/MoreLinq/Cartesian.g.cs b/MoreLinq/Cartesian.g.cs index 891eefa29..74740706c 100644 --- a/MoreLinq/Cartesian.g.cs +++ b/MoreLinq/Cartesian.g.cs @@ -71,7 +71,10 @@ public static IEnumerable Cartesian( return _(first, second, resultSelector); - static IEnumerable _(IEnumerable first, IEnumerable second, Func resultSelector) + static IEnumerable _( + IEnumerable first, + IEnumerable second, + Func resultSelector) { IEnumerable secondMemo; @@ -127,7 +130,11 @@ public static IEnumerable Cartesian( return _(first, second, third, resultSelector); - static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, Func resultSelector) + static IEnumerable _( + IEnumerable first, + IEnumerable second, + IEnumerable third, + Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -191,7 +198,12 @@ public static IEnumerable Cartesian( return _(first, second, third, fourth, resultSelector); - static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, Func resultSelector) + static IEnumerable _( + IEnumerable first, + IEnumerable second, + IEnumerable third, + IEnumerable fourth, + Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -263,7 +275,13 @@ public static IEnumerable Cartesian( return _(first, second, third, fourth, fifth, resultSelector); - static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, IEnumerable fifth, Func resultSelector) + static IEnumerable _( + IEnumerable first, + IEnumerable second, + IEnumerable third, + IEnumerable fourth, + IEnumerable fifth, + Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -343,7 +361,14 @@ public static IEnumerable Cartesian( return _(first, second, third, fourth, fifth, sixth, resultSelector); - static IEnumerable _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, IEnumerable fifth, IEnumerable sixth, Func resultSelector) + static IEnumerable _( + IEnumerable first, + IEnumerable second, + IEnumerable third, + IEnumerable fourth, + IEnumerable fifth, + IEnumerable sixth, + Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -431,7 +456,15 @@ public static IEnumerable Cartesian _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, IEnumerable fifth, IEnumerable sixth, IEnumerable seventh, Func resultSelector) + static IEnumerable _( + IEnumerable first, + IEnumerable second, + IEnumerable third, + IEnumerable fourth, + IEnumerable fifth, + IEnumerable sixth, + IEnumerable seventh, + Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; @@ -527,7 +560,16 @@ public static IEnumerable Cartesian _(IEnumerable first, IEnumerable second, IEnumerable third, IEnumerable fourth, IEnumerable fifth, IEnumerable sixth, IEnumerable seventh, IEnumerable eighth, Func resultSelector) + static IEnumerable _( + IEnumerable first, + IEnumerable second, + IEnumerable third, + IEnumerable fourth, + IEnumerable fifth, + IEnumerable sixth, + IEnumerable seventh, + IEnumerable eighth, + Func resultSelector) { IEnumerable secondMemo; IEnumerable thirdMemo; diff --git a/MoreLinq/Cartesian.g.tt b/MoreLinq/Cartesian.g.tt index 16c497dc5..4c078b9bc 100644 --- a/MoreLinq/Cartesian.g.tt +++ b/MoreLinq/Cartesian.g.tt @@ -117,7 +117,12 @@ Func<<#= string.Join(", ", from x in o.Arguments select "T" + x.Number) #>, TRes return _(<#= string.Join(", ", from x in o.Arguments select x.Ordinal) #>, resultSelector); - static IEnumerable _(<#= string.Join(", ", from x in o.Arguments select "IEnumerable " + x.Ordinal) #>, Func<<#= string.Join(", ", from x in o.Arguments select "T" + x.Number) #>, TResult> resultSelector) + static IEnumerable _( + <# foreach (var arg in o.Arguments) { #> +IEnumerable> <#= arg.Ordinal #>, + <# + } #> +Func<<#= string.Join(", ", from x in o.Arguments select "T" + x.Number) #>, TResult> resultSelector) { <# foreach (var arg in o.Arguments.Skip(1)) { #> IEnumerable> <#= arg.Ordinal #>Memo; From 66ffc8f842fad2c1ccb5dadbe4dad640ea7071e2 Mon Sep 17 00:00:00 2001 From: Jacob Silas Bentley Date: Tue, 30 Apr 2024 09:25:22 +0100 Subject: [PATCH 13/16] Reverted making GetEnumerator implementation static. --- MoreLinq/Experimental/Memoize.cs | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/MoreLinq/Experimental/Memoize.cs b/MoreLinq/Experimental/Memoize.cs index fb2311bc5..46daa0754 100644 --- a/MoreLinq/Experimental/Memoize.cs +++ b/MoreLinq/Experimental/Memoize.cs @@ -96,55 +96,55 @@ public IEnumerator GetEnumerator() } } - return _(this); + return _(); - static IEnumerator _(MemoizedEnumerable memoized) + IEnumerator _() { var index = 0; while (true) { T current; - lock (memoized.locker) + lock (this.locker) { - if (memoized.cache == null) // Cache disposed during iteration? + if (this.cache == null) // Cache disposed during iteration? throw new ObjectDisposedException(nameof(MemoizedEnumerable)); - if (index >= memoized.cache.Count) + if (index >= this.cache.Count) { - if (index == memoized.errorIndex) - Assume.NotNull(memoized.error).Throw(); + if (index == this.errorIndex) + Assume.NotNull(this.error).Throw(); - if (memoized.sourceEnumerator == null) + if (this.sourceEnumerator == null) break; bool moved; try { - moved = memoized.sourceEnumerator.MoveNext(); + moved = this.sourceEnumerator.MoveNext(); } catch (Exception ex) { - memoized.error = ExceptionDispatchInfo.Capture(ex); - memoized.errorIndex = index; - memoized.sourceEnumerator.Dispose(); - memoized.sourceEnumerator = null; + this.error = ExceptionDispatchInfo.Capture(ex); + this.errorIndex = index; + this.sourceEnumerator.Dispose(); + this.sourceEnumerator = null; throw; } if (moved) { - memoized.cache.Add(memoized.sourceEnumerator.Current); + this.cache.Add(this.sourceEnumerator.Current); } else { - memoized.sourceEnumerator.Dispose(); - memoized.sourceEnumerator = null; + this.sourceEnumerator.Dispose(); + this.sourceEnumerator = null; break; } } - current = memoized.cache[index]; + current = this.cache[index]; } yield return current; From fe4aba3aea5fef3ed3978ea84b2f0509ec2898ad Mon Sep 17 00:00:00 2001 From: Jacob Silas Bentley Date: Tue, 30 Apr 2024 09:28:29 +0100 Subject: [PATCH 14/16] Split initialisation logic and enumeration logic into seperate private methods. --- MoreLinq/Experimental/Memoize.cs | 90 +++++++++++++++++--------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/MoreLinq/Experimental/Memoize.cs b/MoreLinq/Experimental/Memoize.cs index 46daa0754..3cb7d199d 100644 --- a/MoreLinq/Experimental/Memoize.cs +++ b/MoreLinq/Experimental/Memoize.cs @@ -72,6 +72,12 @@ sealed class MemoizedEnumerable(IEnumerable sequence) : IEnumerable, ID ExceptionDispatchInfo? error; public IEnumerator GetEnumerator() + { + InitializeEnumerator(); + return GetEnumeratorImpl(); + } + + void InitializeEnumerator() { if (this.cache == null) { @@ -95,61 +101,59 @@ public IEnumerator GetEnumerator() } } } + } - return _(); + IEnumerator GetEnumeratorImpl() + { + var index = 0; - IEnumerator _() + while (true) { - var index = 0; - - while (true) + T current; + lock (this.locker) { - T current; - lock (this.locker) + if (this.cache == null) // Cache disposed during iteration? + throw new ObjectDisposedException(nameof(MemoizedEnumerable)); + + if (index >= this.cache.Count) { - if (this.cache == null) // Cache disposed during iteration? - throw new ObjectDisposedException(nameof(MemoizedEnumerable)); + if (index == this.errorIndex) + Assume.NotNull(this.error).Throw(); - if (index >= this.cache.Count) + if (this.sourceEnumerator == null) + break; + + bool moved; + try { - if (index == this.errorIndex) - Assume.NotNull(this.error).Throw(); - - if (this.sourceEnumerator == null) - break; - - bool moved; - try - { - moved = this.sourceEnumerator.MoveNext(); - } - catch (Exception ex) - { - this.error = ExceptionDispatchInfo.Capture(ex); - this.errorIndex = index; - this.sourceEnumerator.Dispose(); - this.sourceEnumerator = null; - throw; - } - - if (moved) - { - this.cache.Add(this.sourceEnumerator.Current); - } - else - { - this.sourceEnumerator.Dispose(); - this.sourceEnumerator = null; - break; - } + moved = this.sourceEnumerator.MoveNext(); + } + catch (Exception ex) + { + this.error = ExceptionDispatchInfo.Capture(ex); + this.errorIndex = index; + this.sourceEnumerator.Dispose(); + this.sourceEnumerator = null; + throw; } - current = this.cache[index]; + if (moved) + { + this.cache.Add(this.sourceEnumerator.Current); + } + else + { + this.sourceEnumerator.Dispose(); + this.sourceEnumerator = null; + break; + } } - yield return current; - index++; + current = this.cache[index]; } + + yield return current; + index++; } } From 44dd9450f4fa7699fb5e89b86136b54509b40144 Mon Sep 17 00:00:00 2001 From: Jacob Silas Bentley Date: Wed, 1 May 2024 11:57:30 +0100 Subject: [PATCH 15/16] Revert "Split initialisation logic and enumeration logic into seperate private methods." This reverts commit fe4aba3aea5fef3ed3978ea84b2f0509ec2898ad. --- MoreLinq/Experimental/Memoize.cs | 90 +++++++++++++++----------------- 1 file changed, 43 insertions(+), 47 deletions(-) diff --git a/MoreLinq/Experimental/Memoize.cs b/MoreLinq/Experimental/Memoize.cs index 3cb7d199d..46daa0754 100644 --- a/MoreLinq/Experimental/Memoize.cs +++ b/MoreLinq/Experimental/Memoize.cs @@ -72,12 +72,6 @@ sealed class MemoizedEnumerable(IEnumerable sequence) : IEnumerable, ID ExceptionDispatchInfo? error; public IEnumerator GetEnumerator() - { - InitializeEnumerator(); - return GetEnumeratorImpl(); - } - - void InitializeEnumerator() { if (this.cache == null) { @@ -101,59 +95,61 @@ void InitializeEnumerator() } } } - } - IEnumerator GetEnumeratorImpl() - { - var index = 0; + return _(); - while (true) + IEnumerator _() { - T current; - lock (this.locker) - { - if (this.cache == null) // Cache disposed during iteration? - throw new ObjectDisposedException(nameof(MemoizedEnumerable)); + var index = 0; - if (index >= this.cache.Count) + while (true) + { + T current; + lock (this.locker) { - if (index == this.errorIndex) - Assume.NotNull(this.error).Throw(); + if (this.cache == null) // Cache disposed during iteration? + throw new ObjectDisposedException(nameof(MemoizedEnumerable)); - if (this.sourceEnumerator == null) - break; - - bool moved; - try + if (index >= this.cache.Count) { - moved = this.sourceEnumerator.MoveNext(); - } - catch (Exception ex) - { - this.error = ExceptionDispatchInfo.Capture(ex); - this.errorIndex = index; - this.sourceEnumerator.Dispose(); - this.sourceEnumerator = null; - throw; + if (index == this.errorIndex) + Assume.NotNull(this.error).Throw(); + + if (this.sourceEnumerator == null) + break; + + bool moved; + try + { + moved = this.sourceEnumerator.MoveNext(); + } + catch (Exception ex) + { + this.error = ExceptionDispatchInfo.Capture(ex); + this.errorIndex = index; + this.sourceEnumerator.Dispose(); + this.sourceEnumerator = null; + throw; + } + + if (moved) + { + this.cache.Add(this.sourceEnumerator.Current); + } + else + { + this.sourceEnumerator.Dispose(); + this.sourceEnumerator = null; + break; + } } - if (moved) - { - this.cache.Add(this.sourceEnumerator.Current); - } - else - { - this.sourceEnumerator.Dispose(); - this.sourceEnumerator = null; - break; - } + current = this.cache[index]; } - current = this.cache[index]; + yield return current; + index++; } - - yield return current; - index++; } } From ad154a84e9b6432dc7261b0b3755c3473bb5a1ed Mon Sep 17 00:00:00 2001 From: Jacob Silas Bentley Date: Wed, 1 May 2024 12:00:08 +0100 Subject: [PATCH 16/16] Reverting styling changes to code. --- MoreLinq/Experimental/Memoize.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MoreLinq/Experimental/Memoize.cs b/MoreLinq/Experimental/Memoize.cs index 46daa0754..8e6a3c6b5 100644 --- a/MoreLinq/Experimental/Memoize.cs +++ b/MoreLinq/Experimental/Memoize.cs @@ -96,9 +96,7 @@ public IEnumerator GetEnumerator() } } - return _(); - - IEnumerator _() + return _(); IEnumerator _() { var index = 0;