From 539fcf88f191e65227c946092f6d53c5f4da2b21 Mon Sep 17 00:00:00 2001 From: Fred Silberberg Date: Tue, 17 Sep 2024 22:30:33 +0000 Subject: [PATCH 1/3] Implement Enumerable.Reverse(TSource[]) Closes https://github.com/dotnet/runtime/issues/107723. --- src/libraries/System.Linq/ref/System.Linq.cs | 1 + .../System.Linq/src/System/Linq/Reverse.cs | 15 ++++++++ .../System.Linq/tests/ReverseTests.cs | 37 ++++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Linq/ref/System.Linq.cs b/src/libraries/System.Linq/ref/System.Linq.cs index 7e89e2bf1ac1ce..85ab6fd35d0fd2 100644 --- a/src/libraries/System.Linq/ref/System.Linq.cs +++ b/src/libraries/System.Linq/ref/System.Linq.cs @@ -159,6 +159,7 @@ public static System.Collections.Generic.IEnumerable< public static System.Collections.Generic.IEnumerable Range(int start, int count) { throw null; } public static System.Collections.Generic.IEnumerable Repeat(TResult element, int count) { throw null; } public static System.Collections.Generic.IEnumerable Reverse(this System.Collections.Generic.IEnumerable source) { throw null; } + public static System.Collections.Generic.IEnumerable Reverse(this TSource[] source) { throw null; } public static System.Collections.Generic.IEnumerable SelectMany(this System.Collections.Generic.IEnumerable source, System.Func> selector) { throw null; } public static System.Collections.Generic.IEnumerable SelectMany(this System.Collections.Generic.IEnumerable source, System.Func> selector) { throw null; } public static System.Collections.Generic.IEnumerable SelectMany(this System.Collections.Generic.IEnumerable source, System.Func> collectionSelector, System.Func resultSelector) { throw null; } diff --git a/src/libraries/System.Linq/src/System/Linq/Reverse.cs b/src/libraries/System.Linq/src/System/Linq/Reverse.cs index 0eba290b7c7f49..6c8bd74f8bc9b9 100644 --- a/src/libraries/System.Linq/src/System/Linq/Reverse.cs +++ b/src/libraries/System.Linq/src/System/Linq/Reverse.cs @@ -23,6 +23,21 @@ public static IEnumerable Reverse(this IEnumerable so return new ReverseIterator(source); } + public static IEnumerable Reverse(this T[] source) + { + if (source is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); + } + + if (source.Length == 0) + { + return []; + } + + return new ReverseIterator(source); + } + /// /// An iterator that yields the items of an in reverse. /// diff --git a/src/libraries/System.Linq/tests/ReverseTests.cs b/src/libraries/System.Linq/tests/ReverseTests.cs index 1cd337a9750361..d780b27b06390c 100644 --- a/src/libraries/System.Linq/tests/ReverseTests.cs +++ b/src/libraries/System.Linq/tests/ReverseTests.cs @@ -11,7 +11,8 @@ public class ReverseTests : EnumerableTests [Fact] public void InvalidArguments() { - AssertExtensions.Throws("source", () => Enumerable.Reverse(null)); + AssertExtensions.Throws("source", () => Enumerable.Reverse((IEnumerable)null)); + AssertExtensions.Throws("source", () => Enumerable.Reverse((string[])null)); } [Theory] @@ -48,6 +49,40 @@ public void Reverse(IEnumerable source) Assert.Equal(actual, actual); // Repeat the enumeration against itself. } + [Theory] + [MemberData(nameof(ReverseData))] + public void ReverseArray(IEnumerable source) + { + T[] expected = source.ToArray(); + Array.Reverse(expected); + + IEnumerable actual = source.ToArray().Reverse(); + + Assert.Equal(expected, actual); + Assert.Equal(expected.Count(), actual.Count()); // Count may be optimized. + Assert.Equal(expected, actual.ToArray()); + Assert.Equal(expected, actual.ToList()); + + Assert.Equal(expected.FirstOrDefault(), actual.FirstOrDefault()); + Assert.Equal(expected.LastOrDefault(), actual.LastOrDefault()); + + for (int i = 0; i < expected.Length; i++) + { + Assert.Equal(expected[i], actual.ElementAt(i)); + + Assert.Equal(expected.Skip(i), actual.Skip(i)); + Assert.Equal(expected.Take(i), actual.Take(i)); + } + + Assert.Equal(default(T), actual.ElementAtOrDefault(-1)); + Assert.Equal(default(T), actual.ElementAtOrDefault(expected.Length)); + + Assert.Equal(expected, actual.Select(_ => _)); + Assert.Equal(expected, actual.Where(_ => true)); + + Assert.Equal(actual, actual); // Repeat the enumeration against itself. + } + [Theory, MemberData(nameof(ReverseData))] public void RunOnce(IEnumerable source) { From b990653fc545e30356579032c3352fc9e2a6ec21 Mon Sep 17 00:00:00 2001 From: Fred Silberberg Date: Tue, 17 Sep 2024 17:27:20 -0700 Subject: [PATCH 2/3] TSource --- src/libraries/System.Linq/src/System/Linq/Reverse.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Linq/src/System/Linq/Reverse.cs b/src/libraries/System.Linq/src/System/Linq/Reverse.cs index 6c8bd74f8bc9b9..657a18a1bf8f9a 100644 --- a/src/libraries/System.Linq/src/System/Linq/Reverse.cs +++ b/src/libraries/System.Linq/src/System/Linq/Reverse.cs @@ -23,7 +23,7 @@ public static IEnumerable Reverse(this IEnumerable so return new ReverseIterator(source); } - public static IEnumerable Reverse(this T[] source) + public static IEnumerable Reverse(this TSource[] source) { if (source is null) { From 9cea523062ef0f7d4d0ff452f810dfe22df27c62 Mon Sep 17 00:00:00 2001 From: Fred Silberberg Date: Thu, 19 Sep 2024 18:34:04 +0000 Subject: [PATCH 3/3] Add exclusions for Reverse --- src/libraries/System.Linq.Queryable/tests/Queryable.cs | 1 + src/libraries/System.Linq/tests/ConsistencyTests.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libraries/System.Linq.Queryable/tests/Queryable.cs b/src/libraries/System.Linq.Queryable/tests/Queryable.cs index 1ffd4b4fc17fb0..f6b125c984f594 100644 --- a/src/libraries/System.Linq.Queryable/tests/Queryable.cs +++ b/src/libraries/System.Linq.Queryable/tests/Queryable.cs @@ -96,6 +96,7 @@ public static void MatchSequencePattern() nameof(Enumerable.Prepend), nameof(Enumerable.ToHashSet), nameof(Enumerable.TryGetNonEnumeratedCount), + nameof(Enumerable.Reverse), "Fold", "LeftJoin", } diff --git a/src/libraries/System.Linq/tests/ConsistencyTests.cs b/src/libraries/System.Linq/tests/ConsistencyTests.cs index 746efa61439438..99f94d1cae3c35 100644 --- a/src/libraries/System.Linq/tests/ConsistencyTests.cs +++ b/src/libraries/System.Linq/tests/ConsistencyTests.cs @@ -44,6 +44,7 @@ private static IEnumerable GetExcludedMethods() nameof(Enumerable.ToList), nameof(Enumerable.ToHashSet), nameof(Enumerable.TryGetNonEnumeratedCount), + nameof(Enumerable.Reverse), "Fold", "LeftJoin", };