From f6b68e2b523a58331f1025585ce07de416ca4d7e Mon Sep 17 00:00:00 2001 From: Stuart Turner Date: Tue, 24 Jan 2023 20:43:02 -0600 Subject: [PATCH 01/12] Update `ExtensionsGenerator` to not fail on #ifdef's --- bld/ExtensionsGenerator/Program.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/bld/ExtensionsGenerator/Program.cs b/bld/ExtensionsGenerator/Program.cs index aa68f4fa4..efe8ec63b 100644 --- a/bld/ExtensionsGenerator/Program.cs +++ b/bld/ExtensionsGenerator/Program.cs @@ -268,7 +268,17 @@ from md in g select MethodDeclaration(md.ReturnType, md.Identifier) .WithAttributeLists(md.AttributeLists) - .WithModifiers(md.Modifiers) + .WithModifiers( + new SyntaxTokenList( + md.Modifiers[0] + .WithLeadingTrivia( + from lt in md.Modifiers[0].LeadingTrivia + where !lt.IsKind(SyntaxKind.DisabledTextTrivia) + where !lt.IsKind(SyntaxKind.IfDirectiveTrivia) + where !lt.IsKind(SyntaxKind.ElseDirectiveTrivia) + where !lt.IsKind(SyntaxKind.EndIfDirectiveTrivia) + select lt), + md.Modifiers[1])) .WithTypeParameterList(md.TypeParameterList) .WithConstraintClauses(md.ConstraintClauses) .WithParameterList(md.ParameterList) From 56bc8031862bd3bac6b7a3e0adb566723216c7ea Mon Sep 17 00:00:00 2001 From: Stuart Turner Date: Tue, 24 Jan 2023 20:43:24 -0600 Subject: [PATCH 02/12] Update operators to have framework specific support --- MoreLinq/Append.cs | 6 +++++- MoreLinq/DistinctBy.cs | 12 +++++++++++- MoreLinq/ExceptBy.cs | 13 +++++++++++++ MoreLinq/Prepend.cs | 4 ++++ MoreLinq/SkipLast.cs | 4 ++++ MoreLinq/TakeLast.cs | 4 ++++ MoreLinq/ToHashSet.cs | 10 +++++++++- 7 files changed, 50 insertions(+), 3 deletions(-) diff --git a/MoreLinq/Append.cs b/MoreLinq/Append.cs index e0800b364..b6aa4782d 100644 --- a/MoreLinq/Append.cs +++ b/MoreLinq/Append.cs @@ -31,7 +31,11 @@ static partial class MoreEnumerable /// A sequence consisting of the head elements and the given tail element. /// This operator uses deferred execution and streams its results. +#if NET471_OR_GREATER || NETSTANDARD1_6_OR_GREATER || NETCOREAPP2_0_OR_GREATER + public static IEnumerable Append(IEnumerable head, T tail) +#else public static IEnumerable Append(this IEnumerable head, T tail) +#endif { if (head == null) throw new ArgumentNullException(nameof(head)); return head is PendNode node @@ -50,6 +54,6 @@ public static IEnumerable Append(this IEnumerable head, T tail) [Obsolete("Use " + nameof(Append) + " instead.")] public static IEnumerable Concat(this IEnumerable head, T tail) => - head.Append(tail); + Append(head, tail); } } diff --git a/MoreLinq/DistinctBy.cs b/MoreLinq/DistinctBy.cs index a05faab82..1079ff814 100644 --- a/MoreLinq/DistinctBy.cs +++ b/MoreLinq/DistinctBy.cs @@ -38,10 +38,15 @@ static partial class MoreEnumerable /// A sequence consisting of distinct elements from the source sequence, /// comparing them by the specified key projection. +#if NET6_0_OR_GREATER + public static IEnumerable DistinctBy(IEnumerable source, + Func keySelector) +#else public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) +#endif { - return source.DistinctBy(keySelector, null); + return DistinctBy(source, keySelector, null); } /// @@ -62,8 +67,13 @@ public static IEnumerable DistinctBy(this IEnumerableA sequence consisting of distinct elements from the source sequence, /// comparing them by the specified key projection. +#if NET6_0_OR_GREATER + public static IEnumerable DistinctBy(IEnumerable source, + Func keySelector, IEqualityComparer? comparer) +#else public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector, IEqualityComparer? comparer) +#endif { if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); diff --git a/MoreLinq/ExceptBy.cs b/MoreLinq/ExceptBy.cs index 6a5e1f2c6..5918961d5 100644 --- a/MoreLinq/ExceptBy.cs +++ b/MoreLinq/ExceptBy.cs @@ -42,9 +42,15 @@ static partial class MoreEnumerable /// A sequence of elements from whose key was not also a key for /// any element in . +#if NET6_0_OR_GREATER + public static IEnumerable ExceptBy(IEnumerable first, + IEnumerable second, + Func keySelector) +#else public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector) +#endif { return ExceptBy(first, second, keySelector, null); } @@ -70,10 +76,17 @@ public static IEnumerable ExceptBy(this IEnumerableA sequence of elements from whose key was not also a key for /// any element in . +#if NET6_0_OR_GREATER + public static IEnumerable ExceptBy(IEnumerable first, + IEnumerable second, + Func keySelector, + IEqualityComparer? keyComparer) +#else public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer? keyComparer) +#endif { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); diff --git a/MoreLinq/Prepend.cs b/MoreLinq/Prepend.cs index 06f5a0f27..fb82e8538 100644 --- a/MoreLinq/Prepend.cs +++ b/MoreLinq/Prepend.cs @@ -41,7 +41,11 @@ static partial class MoreEnumerable /// The result variable, when iterated over, will yield /// 0, 1, 2 and 3, in turn. +#if NET471_OR_GREATER || NETSTANDARD1_6_OR_GREATER || NETCOREAPP2_0_OR_GREATER + public static IEnumerable Prepend(IEnumerable source, TSource value) +#else public static IEnumerable Prepend(this IEnumerable source, TSource value) +#endif { if (source == null) throw new ArgumentNullException(nameof(source)); return source is PendNode node diff --git a/MoreLinq/SkipLast.cs b/MoreLinq/SkipLast.cs index e97a29c37..c4b3c1fa7 100644 --- a/MoreLinq/SkipLast.cs +++ b/MoreLinq/SkipLast.cs @@ -33,7 +33,11 @@ static partial class MoreEnumerable /// An containing the source sequence elements except for the bypassed ones at the end. /// +#if NETSTANDARD2_1 || NETCOREAPP2_0_OR_GREATER + public static IEnumerable SkipLast(IEnumerable source, int count) +#else public static IEnumerable SkipLast(this IEnumerable source, int count) +#endif { if (source == null) throw new ArgumentNullException(nameof(source)); diff --git a/MoreLinq/TakeLast.cs b/MoreLinq/TakeLast.cs index 0512342dd..615938d9e 100644 --- a/MoreLinq/TakeLast.cs +++ b/MoreLinq/TakeLast.cs @@ -46,7 +46,11 @@ static partial class MoreEnumerable /// 56 and 78 in turn. /// +#if NETSTANDARD2_1 || NETCOREAPP2_0_OR_GREATER + public static IEnumerable TakeLast(IEnumerable source, int count) +#else public static IEnumerable TakeLast(this IEnumerable source, int count) +#endif { if (source == null) throw new ArgumentNullException(nameof(source)); diff --git a/MoreLinq/ToHashSet.cs b/MoreLinq/ToHashSet.cs index 7301ed357..1f6dc8bd1 100644 --- a/MoreLinq/ToHashSet.cs +++ b/MoreLinq/ToHashSet.cs @@ -35,9 +35,13 @@ static partial class MoreEnumerable /// This evaluates the input sequence completely. /// +#if NETSTANDARD2_1 || NET472_OR_GREATER || NETCOREAPP2_0_OR_GREATER + public static HashSet ToHashSet(IEnumerable source) +#else public static HashSet ToHashSet(this IEnumerable source) +#endif { - return source.ToHashSet(null); + return ToHashSet(source, null); } /// @@ -53,7 +57,11 @@ public static HashSet ToHashSet(this IEnumerable sour /// This evaluates the input sequence completely. /// +#if NETSTANDARD2_1 || NET472_OR_GREATER || NETCOREAPP2_0_OR_GREATER + public static HashSet ToHashSet(IEnumerable source, IEqualityComparer? comparer) +#else public static HashSet ToHashSet(this IEnumerable source, IEqualityComparer? comparer) +#endif { if (source == null) throw new ArgumentNullException(nameof(source)); return new HashSet(source, comparer); From d4108e19ad079919642a8080fd0516db09afff86 Mon Sep 17 00:00:00 2001 From: Stuart Turner Date: Tue, 24 Jan 2023 20:43:34 -0600 Subject: [PATCH 03/12] Update unit tests to reflect changes --- MoreLinq.Test/AggregateTest.cs | 7 ++++--- MoreLinq.Test/AppendTest.cs | 4 ++++ MoreLinq.Test/DistinctByTest.cs | 4 ++++ MoreLinq.Test/ExceptByTest.cs | 4 ++++ MoreLinq.Test/GroupAdjacentTest.cs | 3 ++- MoreLinq.Test/PartialSortTest.cs | 1 + MoreLinq.Test/PrependTest.cs | 4 ++++ MoreLinq.Test/SkipLastTest.cs | 4 ++++ MoreLinq.Test/TakeLastTest.cs | 4 ++++ 9 files changed, 31 insertions(+), 4 deletions(-) diff --git a/MoreLinq.Test/AggregateTest.cs b/MoreLinq.Test/AggregateTest.cs index 9ef7b2336..4bb807a2d 100644 --- a/MoreLinq.Test/AggregateTest.cs +++ b/MoreLinq.Test/AggregateTest.cs @@ -17,15 +17,16 @@ namespace MoreLinq.Test { + using Experimental; + using NUnit.Framework; + using NUnit.Framework.Interfaces; using System; using System.Collections.Generic; using System.Globalization; + using System.Linq; using System.Linq.Expressions; - using NUnit.Framework; - using Experimental; using System.Reactive.Linq; using System.Reflection; - using NUnit.Framework.Interfaces; using static FuncModule; [TestFixture] diff --git a/MoreLinq.Test/AppendTest.cs b/MoreLinq.Test/AppendTest.cs index 736ba6498..55ff31597 100644 --- a/MoreLinq.Test/AppendTest.cs +++ b/MoreLinq.Test/AppendTest.cs @@ -15,6 +15,8 @@ // limitations under the License. #endregion +#if !NET471_OR_GREATER && !NETSTANDARD1_6_OR_GREATER && !NETCOREAPP2_0_OR_GREATER + namespace MoreLinq.Test { using System.Collections.Generic; @@ -90,3 +92,5 @@ public void AppendWithSharedSource() } } } + +#endif diff --git a/MoreLinq.Test/DistinctByTest.cs b/MoreLinq.Test/DistinctByTest.cs index 7035578f2..377c9a318 100644 --- a/MoreLinq.Test/DistinctByTest.cs +++ b/MoreLinq.Test/DistinctByTest.cs @@ -15,6 +15,8 @@ // limitations under the License. #endregion +#if !NET6_0_OR_GREATER + namespace MoreLinq.Test { using System; @@ -61,3 +63,5 @@ public void DistinctByIsLazyWithComparer() } } } + +#endif diff --git a/MoreLinq.Test/ExceptByTest.cs b/MoreLinq.Test/ExceptByTest.cs index 43c3fa1a1..d6fb44868 100644 --- a/MoreLinq.Test/ExceptByTest.cs +++ b/MoreLinq.Test/ExceptByTest.cs @@ -15,6 +15,8 @@ // limitations under the License. #endregion +#if !NET6_0_OR_GREATER + namespace MoreLinq.Test { using System; @@ -74,3 +76,5 @@ public void ExceptByIsLazyWithComparer() } } } + +#endif diff --git a/MoreLinq.Test/GroupAdjacentTest.cs b/MoreLinq.Test/GroupAdjacentTest.cs index d6da9909a..5bcad345a 100644 --- a/MoreLinq.Test/GroupAdjacentTest.cs +++ b/MoreLinq.Test/GroupAdjacentTest.cs @@ -19,6 +19,7 @@ namespace MoreLinq.Test { using System; using System.Collections.Generic; + using System.Linq; using NUnit.Framework; [TestFixture] @@ -222,7 +223,7 @@ public void GroupAdjacentSourceSequenceWithSomeNullKeys() reader.ReadEnd(); } - static void AssertGrouping(SequenceReader> reader, + static void AssertGrouping(SequenceReader> reader, TKey key, params TElement[] elements) { var grouping = reader.Read(); diff --git a/MoreLinq.Test/PartialSortTest.cs b/MoreLinq.Test/PartialSortTest.cs index a838efdc3..694850cf8 100644 --- a/MoreLinq.Test/PartialSortTest.cs +++ b/MoreLinq.Test/PartialSortTest.cs @@ -18,6 +18,7 @@ namespace MoreLinq.Test { using System; + using System.Linq; using NUnit.Framework; [TestFixture] diff --git a/MoreLinq.Test/PrependTest.cs b/MoreLinq.Test/PrependTest.cs index eaaad5c81..3a4f938d1 100644 --- a/MoreLinq.Test/PrependTest.cs +++ b/MoreLinq.Test/PrependTest.cs @@ -15,6 +15,8 @@ // limitations under the License. #endregion +#if !NET471_OR_GREATER && !NETSTANDARD1_6_OR_GREATER && !NETCOREAPP2_0_OR_GREATER + namespace MoreLinq.Test { using System.Collections.Generic; @@ -89,3 +91,5 @@ public void PrependWithSharedSource() } } } + +#endif diff --git a/MoreLinq.Test/SkipLastTest.cs b/MoreLinq.Test/SkipLastTest.cs index dfdbad739..3e00c400a 100644 --- a/MoreLinq.Test/SkipLastTest.cs +++ b/MoreLinq.Test/SkipLastTest.cs @@ -15,6 +15,8 @@ // limitations under the License. #endregion +#if !NETSTANDARD2_1 && !NETCOREAPP2_0_OR_GREATER + namespace MoreLinq.Test { using NUnit.Framework; @@ -58,3 +60,5 @@ public void SkipLastIsLazy() } } } + +#endif diff --git a/MoreLinq.Test/TakeLastTest.cs b/MoreLinq.Test/TakeLastTest.cs index fdbd8f923..dbe3f64a4 100644 --- a/MoreLinq.Test/TakeLastTest.cs +++ b/MoreLinq.Test/TakeLastTest.cs @@ -15,6 +15,8 @@ // limitations under the License. #endregion +#if !NETSTANDARD2_1 && !NETCOREAPP2_0_OR_GREATER + namespace MoreLinq.Test { using NUnit.Framework; @@ -80,3 +82,5 @@ static void AssertTakeLast(ICollection input, int count, Action Date: Fri, 3 Mar 2023 00:50:41 +0100 Subject: [PATCH 04/12] Remove "System.Linq" imports --- MoreLinq.Test/AggregateTest.cs | 1 - MoreLinq.Test/Enumerable.cs | 5 +++++ MoreLinq.Test/GroupAdjacentTest.cs | 3 +-- MoreLinq.Test/PartialSortTest.cs | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/MoreLinq.Test/AggregateTest.cs b/MoreLinq.Test/AggregateTest.cs index 4bb807a2d..5d4398ac3 100644 --- a/MoreLinq.Test/AggregateTest.cs +++ b/MoreLinq.Test/AggregateTest.cs @@ -23,7 +23,6 @@ namespace MoreLinq.Test using System; using System.Collections.Generic; using System.Globalization; - using System.Linq; using System.Linq.Expressions; using System.Reactive.Linq; using System.Reflection; diff --git a/MoreLinq.Test/Enumerable.cs b/MoreLinq.Test/Enumerable.cs index f7795af4e..ae22e31cd 100644 --- a/MoreLinq.Test/Enumerable.cs +++ b/MoreLinq.Test/Enumerable.cs @@ -45,6 +45,11 @@ public static bool Any(this IEnumerable source) => public static bool Any(this IEnumerable source, Func predicate) => LinqEnumerable.Any(source, predicate); +#if NET471_OR_GREATER || NET6_0_OR_GREATER + public static IEnumerable Append (this IEnumerable source, TSource element) => + LinqEnumerable.Append(source, element); +#endif + public static IEnumerable AsEnumerable(this IEnumerable source) => LinqEnumerable.AsEnumerable(source); diff --git a/MoreLinq.Test/GroupAdjacentTest.cs b/MoreLinq.Test/GroupAdjacentTest.cs index 5bcad345a..d6da9909a 100644 --- a/MoreLinq.Test/GroupAdjacentTest.cs +++ b/MoreLinq.Test/GroupAdjacentTest.cs @@ -19,7 +19,6 @@ namespace MoreLinq.Test { using System; using System.Collections.Generic; - using System.Linq; using NUnit.Framework; [TestFixture] @@ -223,7 +222,7 @@ public void GroupAdjacentSourceSequenceWithSomeNullKeys() reader.ReadEnd(); } - static void AssertGrouping(SequenceReader> reader, + static void AssertGrouping(SequenceReader> reader, TKey key, params TElement[] elements) { var grouping = reader.Read(); diff --git a/MoreLinq.Test/PartialSortTest.cs b/MoreLinq.Test/PartialSortTest.cs index 694850cf8..a838efdc3 100644 --- a/MoreLinq.Test/PartialSortTest.cs +++ b/MoreLinq.Test/PartialSortTest.cs @@ -18,7 +18,6 @@ namespace MoreLinq.Test { using System; - using System.Linq; using NUnit.Framework; [TestFixture] From 62477ce8a1efaa357ee2739147bf4362f18d39dc Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Thu, 16 Mar 2023 23:12:48 +0100 Subject: [PATCH 05/12] Undo unrelated imports change --- MoreLinq.Test/AggregateTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MoreLinq.Test/AggregateTest.cs b/MoreLinq.Test/AggregateTest.cs index 5d4398ac3..9ef7b2336 100644 --- a/MoreLinq.Test/AggregateTest.cs +++ b/MoreLinq.Test/AggregateTest.cs @@ -17,15 +17,15 @@ namespace MoreLinq.Test { - using Experimental; - using NUnit.Framework; - using NUnit.Framework.Interfaces; using System; using System.Collections.Generic; using System.Globalization; using System.Linq.Expressions; + using NUnit.Framework; + using Experimental; using System.Reactive.Linq; using System.Reflection; + using NUnit.Framework.Interfaces; using static FuncModule; [TestFixture] From f63ec507087610fb3a12f53627ceceffbb7a6aac Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sun, 2 Apr 2023 17:14:15 +0200 Subject: [PATCH 06/12] Inherit all method modifiers during wrapper code gen --- bld/ExtensionsGenerator/Program.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/bld/ExtensionsGenerator/Program.cs b/bld/ExtensionsGenerator/Program.cs index 445449aab..780355c6d 100644 --- a/bld/ExtensionsGenerator/Program.cs +++ b/bld/ExtensionsGenerator/Program.cs @@ -269,16 +269,15 @@ from md in g MethodDeclaration(md.ReturnType, md.Identifier) .WithAttributeLists(md.AttributeLists) .WithModifiers( - new SyntaxTokenList( - md.Modifiers[0] - .WithLeadingTrivia( - from lt in md.Modifiers[0].LeadingTrivia - where !lt.IsKind(SyntaxKind.DisabledTextTrivia) - where !lt.IsKind(SyntaxKind.IfDirectiveTrivia) - where !lt.IsKind(SyntaxKind.ElseDirectiveTrivia) - where !lt.IsKind(SyntaxKind.EndIfDirectiveTrivia) - select lt), - md.Modifiers[1])) + TokenList(md.Modifiers[0] // assume at least one modifier, like public + .WithLeadingTrivia( + from lt in md.Modifiers[0].LeadingTrivia + where lt.Kind() is not (SyntaxKind.DisabledTextTrivia + or SyntaxKind.IfDirectiveTrivia + or SyntaxKind.ElseDirectiveTrivia + or SyntaxKind.EndIfDirectiveTrivia) + select lt)) + .AddRange(md.Modifiers.Skip(1))) .WithTypeParameterList(md.TypeParameterList) .WithConstraintClauses(md.ConstraintClauses) .WithParameterList(md.ParameterList) From ca3a8e26b3d6401f7f3bcd7784f3468adf75c777 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sun, 2 Apr 2023 14:22:37 +0200 Subject: [PATCH 07/12] Remove "Append" and "Prepend" --- MoreLinq.Test/AppendTest.cs | 96 ------------------- MoreLinq.Test/PrependTest.cs | 95 ------------------ MoreLinq/Append.cs | 46 --------- MoreLinq/Extensions.g.cs | 48 ---------- MoreLinq/Prepend.cs | 56 ----------- .../PublicAPI/net6.0/PublicAPI.Unshipped.txt | 6 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 6 +- .../netstandard2.1/PublicAPI.Unshipped.txt | 6 +- README.md | 16 +++- 9 files changed, 24 insertions(+), 351 deletions(-) delete mode 100644 MoreLinq.Test/AppendTest.cs delete mode 100644 MoreLinq.Test/PrependTest.cs delete mode 100644 MoreLinq/Append.cs delete mode 100644 MoreLinq/Prepend.cs diff --git a/MoreLinq.Test/AppendTest.cs b/MoreLinq.Test/AppendTest.cs deleted file mode 100644 index 55ff31597..000000000 --- a/MoreLinq.Test/AppendTest.cs +++ /dev/null @@ -1,96 +0,0 @@ -#region License and Terms -// MoreLINQ - Extensions to LINQ to Objects -// Copyright (c) 2008 Jonathan Skeet. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#endregion - -#if !NET471_OR_GREATER && !NETSTANDARD1_6_OR_GREATER && !NETCOREAPP2_0_OR_GREATER - -namespace MoreLinq.Test -{ - using System.Collections.Generic; - using NUnit.Framework; - - [TestFixture] - public class AppendTest - { - #region Append with single head and tail sequence - [Test] - public void AppendWithNonEmptyHeadSequence() - { - var head = new[] { "first", "second" }; - var tail = "third"; - var whole = head.Append(tail); - whole.AssertSequenceEqual("first", "second", "third"); - } - - [Test] - public void AppendWithEmptyHeadSequence() - { - string[] head = { }; - var tail = "first"; - var whole = head.Append(tail); - whole.AssertSequenceEqual("first"); - } - - [Test] - public void AppendWithNullTail() - { - var head = new[] { "first", "second" }; - string? tail = null; - var whole = head.Append(tail); - whole.AssertSequenceEqual("first", "second", null); - } - - [Test] - public void AppendIsLazyInHeadSequence() - { - _ = new BreakingSequence().Append("tail"); - } - #endregion - - [TestCaseSource(nameof(ContactManySource))] - public void AppendMany(int[] head, int[] tail) - { - tail.Aggregate(head.AsEnumerable(), (xs, x) => xs.Append(x)) - .AssertSequenceEqual(head.Concat(tail)); - } - - public static IEnumerable ContactManySource => - from x in Enumerable.Range(0, 11) - from y in Enumerable.Range(1, 20 - x) - select new - { - Head = Enumerable.Range(1, x).ToArray(), - Tail = Enumerable.Range(x + 1, y).ToArray(), - } - into e - select new TestCaseData(e.Head, - e.Tail).SetName("Head = [" + string.Join(", ", e.Head) + "], " + - "Tail = [" + string.Join(", ", e.Tail) + "]"); - - [Test] - public void AppendWithSharedSource() - { - var first = new[] { 1 }.Append(2); - var second = first.Append(3).Append(4); - var third = first.Append(4).Append(8); - - second.AssertSequenceEqual(1, 2, 3, 4); - third.AssertSequenceEqual(1, 2, 4, 8); - } - } -} - -#endif diff --git a/MoreLinq.Test/PrependTest.cs b/MoreLinq.Test/PrependTest.cs deleted file mode 100644 index 3a4f938d1..000000000 --- a/MoreLinq.Test/PrependTest.cs +++ /dev/null @@ -1,95 +0,0 @@ -#region License and Terms -// MoreLINQ - Extensions to LINQ to Objects -// Copyright (c) 2008 Jonathan Skeet. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#endregion - -#if !NET471_OR_GREATER && !NETSTANDARD1_6_OR_GREATER && !NETCOREAPP2_0_OR_GREATER - -namespace MoreLinq.Test -{ - using System.Collections.Generic; - using NUnit.Framework; - using NUnit.Framework.Interfaces; - - [TestFixture] - public class PrependTest - { - [Test] - public void PrependWithNonEmptyTailSequence() - { - string[] tail = { "second", "third" }; - var head = "first"; - var whole = tail.Prepend(head); - whole.AssertSequenceEqual("first", "second", "third"); - } - - [Test] - public void PrependWithEmptyTailSequence() - { - string[] tail = { }; - var head = "first"; - var whole = tail.Prepend(head); - whole.AssertSequenceEqual("first"); - } - - [Test] - public void PrependWithNullHead() - { - string[] tail = { "second", "third" }; - string? head = null; - var whole = tail.Prepend(head); - whole.AssertSequenceEqual(null, "second", "third"); - } - - [Test] - public void PrependIsLazyInTailSequence() - { - _ = new BreakingSequence().Prepend("head"); - } - - [TestCaseSource(nameof(PrependManySource))] - public int[] PrependMany(int[] head, int[] tail) - { - return tail.Aggregate(head.AsEnumerable(), MoreEnumerable.Prepend).ToArray(); - } - - public static IEnumerable PrependManySource => - from x in Enumerable.Range(0, 11) - from y in Enumerable.Range(1, 11) - select new - { - Head = Enumerable.Range(0, y).Select(n => 0 - n).ToArray(), - Tail = Enumerable.Range(1, x).ToArray(), - } - into e - select new TestCaseData(e.Head, e.Tail) - .SetName("Head = [" + string.Join(", ", e.Head) + "], " + - "Tail = [" + string.Join(", ", e.Tail) + "]") - .Returns(e.Tail.Reverse().Concat(e.Head).ToArray()); - - [Test] - public void PrependWithSharedSource() - { - var first = new[] { 1 }.Prepend(2); - var second = first.Prepend(3).Prepend(4); - var third = first.Prepend(4).Prepend(8); - - second.AssertSequenceEqual(4, 3, 2, 1); - third.AssertSequenceEqual(8, 4, 2, 1); - } - } -} - -#endif diff --git a/MoreLinq/Append.cs b/MoreLinq/Append.cs deleted file mode 100644 index 3a02d376b..000000000 --- a/MoreLinq/Append.cs +++ /dev/null @@ -1,46 +0,0 @@ -#region License and Terms -// MoreLINQ - Extensions to LINQ to Objects -// Copyright (c) 2008 Jonathan Skeet. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#endregion - -namespace MoreLinq -{ - using System; - using System.Collections.Generic; - - static partial class MoreEnumerable - { - /// - /// Returns a sequence consisting of the head elements and the given tail element. - /// - /// Type of sequence - /// All elements of the head. Must not be null. - /// Tail element of the new sequence. - /// A sequence consisting of the head elements and the given tail element. - /// This operator uses deferred execution and streams its results. - -#if NET471_OR_GREATER || NETSTANDARD1_6_OR_GREATER || NETCOREAPP2_0_OR_GREATER - public static IEnumerable Append(IEnumerable head, T tail) -#else - public static IEnumerable Append(this IEnumerable head, T tail) -#endif - { - if (head == null) throw new ArgumentNullException(nameof(head)); - return head is PendNode node - ? node.Concat(tail) - : PendNode.WithSource(head).Concat(tail); - } - } -} diff --git a/MoreLinq/Extensions.g.cs b/MoreLinq/Extensions.g.cs index b25c873fb..4137ef772 100644 --- a/MoreLinq/Extensions.g.cs +++ b/MoreLinq/Extensions.g.cs @@ -430,25 +430,6 @@ public static TResult AggregateRight(this IEnumer } - /// Append extension. - - [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] - public static partial class AppendExtension - { - /// - /// Returns a sequence consisting of the head elements and the given tail element. - /// - /// Type of sequence - /// All elements of the head. Must not be null. - /// Tail element of the new sequence. - /// A sequence consisting of the head elements and the given tail element. - /// This operator uses deferred execution and streams its results. - - public static IEnumerable Append(this IEnumerable head, T tail) - => MoreEnumerable.Append(head, tail); - - } - /// Assert extension. [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] @@ -4559,35 +4540,6 @@ public static IEnumerable Pipe(this IEnumerable source, Action actio } - /// Prepend extension. - - [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] - public static partial class PrependExtension - { - /// - /// Prepends a single value to a sequence. - /// - /// The type of the elements of . - /// The sequence to prepend to. - /// The value to prepend. - /// - /// Returns a sequence where a value is prepended to it. - /// - /// - /// This operator uses deferred execution and streams its results. - /// - /// - /// The result variable, when iterated over, will yield - /// 0, 1, 2 and 3, in turn. - - public static IEnumerable Prepend(this IEnumerable source, TSource value) - => MoreEnumerable.Prepend(source, value); - - } - /// PreScan extension. [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] diff --git a/MoreLinq/Prepend.cs b/MoreLinq/Prepend.cs deleted file mode 100644 index fb82e8538..000000000 --- a/MoreLinq/Prepend.cs +++ /dev/null @@ -1,56 +0,0 @@ -#region License and Terms -// MoreLINQ - Extensions to LINQ to Objects -// Copyright (c) 2009 Atif Aziz. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#endregion - -namespace MoreLinq -{ - using System; - using System.Collections.Generic; - - static partial class MoreEnumerable - { - /// - /// Prepends a single value to a sequence. - /// - /// The type of the elements of . - /// The sequence to prepend to. - /// The value to prepend. - /// - /// Returns a sequence where a value is prepended to it. - /// - /// - /// This operator uses deferred execution and streams its results. - /// - /// - /// The result variable, when iterated over, will yield - /// 0, 1, 2 and 3, in turn. - -#if NET471_OR_GREATER || NETSTANDARD1_6_OR_GREATER || NETCOREAPP2_0_OR_GREATER - public static IEnumerable Prepend(IEnumerable source, TSource value) -#else - public static IEnumerable Prepend(this IEnumerable source, TSource value) -#endif - { - if (source == null) throw new ArgumentNullException(nameof(source)); - return source is PendNode node - ? node.Prepend(value) - : PendNode.WithSource(source).Prepend(value); - } - } -} diff --git a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt index 8595b24fe..10ccccc77 100644 --- a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt @@ -1,4 +1,8 @@ #nullable enable +*REMOVED*MoreLinq.Extensions.AppendExtension +*REMOVED*MoreLinq.Extensions.PrependExtension +*REMOVED*static MoreLinq.Extensions.AppendExtension.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! +*REMOVED*static MoreLinq.Extensions.PrependExtension.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Concat(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! @@ -10,12 +14,10 @@ *REMOVED*static MoreLinq.MoreEnumerable.TakeLast(this System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEqualityComparer? comparer) -> System.Collections.Generic.HashSet! -static MoreLinq.MoreEnumerable.Append(System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.DistinctBy(System.Collections.Generic.IEnumerable! source, System.Func! keySelector) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.DistinctBy(System.Collections.Generic.IEnumerable! source, System.Func! keySelector, System.Collections.Generic.IEqualityComparer? comparer) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.ExceptBy(System.Collections.Generic.IEnumerable! first, System.Collections.Generic.IEnumerable! second, System.Func! keySelector) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.ExceptBy(System.Collections.Generic.IEnumerable! first, System.Collections.Generic.IEnumerable! second, System.Func! keySelector, System.Collections.Generic.IEqualityComparer? keyComparer) -> System.Collections.Generic.IEnumerable! -static MoreLinq.MoreEnumerable.Prepend(System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.SkipLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.TakeLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.ToHashSet(System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! diff --git a/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index 056e1801b..37e54326a 100644 --- a/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,6 +1,8 @@ #nullable enable +*REMOVED*MoreLinq.Extensions.AppendExtension +*REMOVED*MoreLinq.Extensions.PrependExtension +*REMOVED*static MoreLinq.Extensions.AppendExtension.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! +*REMOVED*static MoreLinq.Extensions.PrependExtension.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Concat(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! -static MoreLinq.MoreEnumerable.Append(System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! -static MoreLinq.MoreEnumerable.Prepend(System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! diff --git a/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt index b025e7aed..ebb7ca31b 100644 --- a/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt @@ -1,4 +1,8 @@ #nullable enable +*REMOVED*MoreLinq.Extensions.AppendExtension +*REMOVED*MoreLinq.Extensions.PrependExtension +*REMOVED*static MoreLinq.Extensions.AppendExtension.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! +*REMOVED*static MoreLinq.Extensions.PrependExtension.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Concat(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! @@ -6,8 +10,6 @@ *REMOVED*static MoreLinq.MoreEnumerable.TakeLast(this System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEqualityComparer? comparer) -> System.Collections.Generic.HashSet! -static MoreLinq.MoreEnumerable.Append(System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! -static MoreLinq.MoreEnumerable.Prepend(System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.SkipLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.TakeLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.ToHashSet(System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! diff --git a/README.md b/README.md index 2c9962eda..b2f1c50ad 100644 --- a/README.md +++ b/README.md @@ -103,10 +103,14 @@ This operator is the right-associative version of the Aggregate LINQ operator. This method has 3 overloads. -### Append +### ~~Append~~ Returns a sequence consisting of the head element and the given tail elements. +This extension was removed in version 4.0. Use [`Append`][linq-append] from .NET +instead that's been available since .NET Standard 1.6+, .NET Core 1.0+ and .NET +Framework 4.7.1+. + ### Assert Asserts that all elements of a sequence meet a given condition otherwise @@ -171,8 +175,6 @@ This extension was rendered obsolete in version 3.0 and eventually removed in version 4.0. Use [`Append`][linq-append] from .NET instead that's been available since .NET Standard 1.6+, .NET Core 1.0+ and .NET Framework 4.7.1+. -[linq-append]: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.append - ### Consume Completely consumes the given sequence. This method uses immediate execution, @@ -442,10 +444,14 @@ sequence Executes the given action on each element in the source sequence and yields it -### Prepend +### ~~Prepend~~ Prepends a single value to a sequence +This extension was removed in version 4.0. Use [`Prepend`][linq-prepend] from +.NET instead that's been available since .NET Standard 1.6+, .NET Core 1.0+ and +.NET Framework 4.7.1+. + ### PreScan Performs a pre-scan (exclusive prefix sum) on a sequence of elements @@ -782,3 +788,5 @@ This method has 2 overloads. [lookup]: https://docs.microsoft.com/en-us/dotnet/api/system.linq.lookup-2 [v2.1]: https://github.com/morelinq/MoreLINQ/releases/tag/v2.1.0 [v3.0]: https://github.com/morelinq/MoreLINQ/releases/tag/v3.0.0 +[linq-append]: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.append +[linq-prepend]: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.prepend From 7d341224385450784498acc5e3bc255210fe82a4 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sat, 24 Jun 2023 12:46:54 +0200 Subject: [PATCH 08/12] Unhide "ExceptBy" as it doesn't conflict --- MoreLinq.Test/ExceptByTest.cs | 4 ---- MoreLinq/ExceptBy.cs | 13 ------------- MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt | 4 ---- 3 files changed, 21 deletions(-) diff --git a/MoreLinq.Test/ExceptByTest.cs b/MoreLinq.Test/ExceptByTest.cs index d6fb44868..43c3fa1a1 100644 --- a/MoreLinq.Test/ExceptByTest.cs +++ b/MoreLinq.Test/ExceptByTest.cs @@ -15,8 +15,6 @@ // limitations under the License. #endregion -#if !NET6_0_OR_GREATER - namespace MoreLinq.Test { using System; @@ -76,5 +74,3 @@ public void ExceptByIsLazyWithComparer() } } } - -#endif diff --git a/MoreLinq/ExceptBy.cs b/MoreLinq/ExceptBy.cs index 5918961d5..6a5e1f2c6 100644 --- a/MoreLinq/ExceptBy.cs +++ b/MoreLinq/ExceptBy.cs @@ -42,15 +42,9 @@ static partial class MoreEnumerable /// A sequence of elements from whose key was not also a key for /// any element in . -#if NET6_0_OR_GREATER - public static IEnumerable ExceptBy(IEnumerable first, - IEnumerable second, - Func keySelector) -#else public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector) -#endif { return ExceptBy(first, second, keySelector, null); } @@ -76,17 +70,10 @@ public static IEnumerable ExceptBy(this IEnumerableA sequence of elements from whose key was not also a key for /// any element in . -#if NET6_0_OR_GREATER - public static IEnumerable ExceptBy(IEnumerable first, - IEnumerable second, - Func keySelector, - IEqualityComparer? keyComparer) -#else public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer? keyComparer) -#endif { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); diff --git a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt index 10ccccc77..8efe28e0a 100644 --- a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt @@ -8,16 +8,12 @@ *REMOVED*static MoreLinq.MoreEnumerable.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.DistinctBy(this System.Collections.Generic.IEnumerable! source, System.Func! keySelector) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.DistinctBy(this System.Collections.Generic.IEnumerable! source, System.Func! keySelector, System.Collections.Generic.IEqualityComparer? comparer) -> System.Collections.Generic.IEnumerable! -*REMOVED*static MoreLinq.MoreEnumerable.ExceptBy(this System.Collections.Generic.IEnumerable! first, System.Collections.Generic.IEnumerable! second, System.Func! keySelector) -> System.Collections.Generic.IEnumerable! -*REMOVED*static MoreLinq.MoreEnumerable.ExceptBy(this System.Collections.Generic.IEnumerable! first, System.Collections.Generic.IEnumerable! second, System.Func! keySelector, System.Collections.Generic.IEqualityComparer? keyComparer) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.SkipLast(this System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.TakeLast(this System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEqualityComparer? comparer) -> System.Collections.Generic.HashSet! static MoreLinq.MoreEnumerable.DistinctBy(System.Collections.Generic.IEnumerable! source, System.Func! keySelector) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.DistinctBy(System.Collections.Generic.IEnumerable! source, System.Func! keySelector, System.Collections.Generic.IEqualityComparer? comparer) -> System.Collections.Generic.IEnumerable! -static MoreLinq.MoreEnumerable.ExceptBy(System.Collections.Generic.IEnumerable! first, System.Collections.Generic.IEnumerable! second, System.Func! keySelector) -> System.Collections.Generic.IEnumerable! -static MoreLinq.MoreEnumerable.ExceptBy(System.Collections.Generic.IEnumerable! first, System.Collections.Generic.IEnumerable! second, System.Func! keySelector, System.Collections.Generic.IEqualityComparer? keyComparer) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.SkipLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.TakeLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.ToHashSet(System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! From 24c17a643337b339d2338eb4415ab16816ec9e40 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sat, 24 Jun 2023 12:55:26 +0200 Subject: [PATCH 09/12] Update compatibility suppression file --- MoreLinq/CompatibilitySuppressions.xml | 114 ++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/MoreLinq/CompatibilitySuppressions.xml b/MoreLinq/CompatibilitySuppressions.xml index da1602414..f74744f83 100644 --- a/MoreLinq/CompatibilitySuppressions.xml +++ b/MoreLinq/CompatibilitySuppressions.xml @@ -1,6 +1,69 @@ + + CP0001 + T:MoreLinq.Extensions.AppendExtension + lib/net462/MoreLinq.dll + lib/netstandard2.0/MoreLinq.dll + true + + + CP0001 + T:MoreLinq.Extensions.PrependExtension + lib/net462/MoreLinq.dll + lib/netstandard2.0/MoreLinq.dll + true + + + CP0001 + T:MoreLinq.Extensions.AppendExtension + lib/net6.0/MoreLinq.dll + lib/net6.0/MoreLinq.dll + true + + + CP0001 + T:MoreLinq.Extensions.PrependExtension + lib/net6.0/MoreLinq.dll + lib/net6.0/MoreLinq.dll + true + + + CP0001 + T:MoreLinq.Extensions.AppendExtension + lib/netstandard2.0/MoreLinq.dll + lib/netstandard2.0/MoreLinq.dll + true + + + CP0001 + T:MoreLinq.Extensions.PrependExtension + lib/netstandard2.0/MoreLinq.dll + lib/netstandard2.0/MoreLinq.dll + true + + + CP0001 + T:MoreLinq.Extensions.AppendExtension + lib/netstandard2.1/MoreLinq.dll + lib/netstandard2.1/MoreLinq.dll + true + + + CP0001 + T:MoreLinq.Extensions.PrependExtension + lib/netstandard2.1/MoreLinq.dll + lib/netstandard2.1/MoreLinq.dll + true + + + CP0002 + M:MoreLinq.MoreEnumerable.Append``1(System.Collections.Generic.IEnumerable{``0},``0) + lib/net462/MoreLinq.dll + lib/netstandard2.0/MoreLinq.dll + true + CP0002 M:MoreLinq.MoreEnumerable.Concat``1(System.Collections.Generic.IEnumerable{``0},``0) @@ -8,6 +71,20 @@ lib/netstandard2.0/MoreLinq.dll true + + CP0002 + M:MoreLinq.MoreEnumerable.Prepend``1(System.Collections.Generic.IEnumerable{``0},``0) + lib/net462/MoreLinq.dll + lib/netstandard2.0/MoreLinq.dll + true + + + CP0002 + M:MoreLinq.MoreEnumerable.Append``1(System.Collections.Generic.IEnumerable{``0},``0) + lib/net6.0/MoreLinq.dll + lib/net6.0/MoreLinq.dll + true + CP0002 M:MoreLinq.MoreEnumerable.Concat``1(System.Collections.Generic.IEnumerable{``0},``0) @@ -15,6 +92,20 @@ lib/net6.0/MoreLinq.dll true + + CP0002 + M:MoreLinq.MoreEnumerable.Prepend``1(System.Collections.Generic.IEnumerable{``0},``0) + lib/net6.0/MoreLinq.dll + lib/net6.0/MoreLinq.dll + true + + + CP0002 + M:MoreLinq.MoreEnumerable.Append``1(System.Collections.Generic.IEnumerable{``0},``0) + lib/netstandard2.0/MoreLinq.dll + lib/netstandard2.0/MoreLinq.dll + true + CP0002 M:MoreLinq.MoreEnumerable.Concat``1(System.Collections.Generic.IEnumerable{``0},``0) @@ -22,6 +113,20 @@ lib/netstandard2.0/MoreLinq.dll true + + CP0002 + M:MoreLinq.MoreEnumerable.Prepend``1(System.Collections.Generic.IEnumerable{``0},``0) + lib/netstandard2.0/MoreLinq.dll + lib/netstandard2.0/MoreLinq.dll + true + + + CP0002 + M:MoreLinq.MoreEnumerable.Append``1(System.Collections.Generic.IEnumerable{``0},``0) + lib/netstandard2.1/MoreLinq.dll + lib/netstandard2.1/MoreLinq.dll + true + CP0002 M:MoreLinq.MoreEnumerable.Concat``1(System.Collections.Generic.IEnumerable{``0},``0) @@ -29,8 +134,15 @@ lib/netstandard2.1/MoreLinq.dll true + + CP0002 + M:MoreLinq.MoreEnumerable.Prepend``1(System.Collections.Generic.IEnumerable{``0},``0) + lib/netstandard2.1/MoreLinq.dll + lib/netstandard2.1/MoreLinq.dll + true + PKV006 .NETStandard,Version=v1.0 - + \ No newline at end of file From 0655668a56e8fc8a115d3d71754e56c6d02d5ac0 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sun, 25 Jun 2023 13:16:33 +0200 Subject: [PATCH 10/12] Undo accidental removal of final newline --- MoreLinq/CompatibilitySuppressions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoreLinq/CompatibilitySuppressions.xml b/MoreLinq/CompatibilitySuppressions.xml index f74744f83..227399b89 100644 --- a/MoreLinq/CompatibilitySuppressions.xml +++ b/MoreLinq/CompatibilitySuppressions.xml @@ -145,4 +145,4 @@ PKV006 .NETStandard,Version=v1.0 - \ No newline at end of file + From b9316f7f943cf1897f84a8fd4b9d6277265b82f9 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sun, 25 Jun 2023 13:24:22 +0200 Subject: [PATCH 11/12] Remove unused "Append"/"Prepend"supporting types --- MoreLinq/PendNode.cs | 125 ------------------------------- MoreLinq/UnreachableException.cs | 58 -------------- 2 files changed, 183 deletions(-) delete mode 100644 MoreLinq/PendNode.cs delete mode 100644 MoreLinq/UnreachableException.cs diff --git a/MoreLinq/PendNode.cs b/MoreLinq/PendNode.cs deleted file mode 100644 index 2bf363863..000000000 --- a/MoreLinq/PendNode.cs +++ /dev/null @@ -1,125 +0,0 @@ -#region License and Terms -// MoreLINQ - Extensions to LINQ to Objects -// Copyright (c) 2017 Atif Aziz. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#endregion - -namespace MoreLinq -{ - using System; - using System.Collections; - using System.Collections.Generic; - - /// - /// Prepend-Append node is a single linked-list of the discriminated union - /// of an item to prepend, an item to append and the source. - /// - - abstract class PendNode : IEnumerable - { - public static PendNode WithSource(IEnumerable source) => new Source(source); - - public PendNode Prepend(T item) => new Item(item, isPrepend: true , next: this); - public PendNode Concat(T item) => new Item(item, isPrepend: false, next: this); - - sealed class Item : PendNode - { - public T Value { get; } - public bool IsPrepend { get; } - public int ConcatCount { get; } - public PendNode Next { get; } - - public Item(T item, bool isPrepend, PendNode next) - { - if (next == null) throw new ArgumentNullException(nameof(next)); - - Value = item; - IsPrepend = isPrepend; - ConcatCount = next is Item nextItem - ? nextItem.ConcatCount + (isPrepend ? 0 : 1) - : 1; - Next = next; - } - } - - sealed class Source : PendNode - { - public IEnumerable Value { get; } - public Source(IEnumerable source) => Value = source; - } - - public IEnumerator GetEnumerator() - { - var i = 0; - T[]? concats = null; // Array for > 4 concatenations - var concat1 = default(T); // Slots for up to 4 concatenations - var concat2 = default(T); - var concat3 = default(T); - var concat4 = default(T); - - var current = this; - for (; current is Item item; current = item.Next) - { - if (item.IsPrepend) - { - yield return item.Value; - } - else - { - if (concats == null) - { - if (i == 0 && item.ConcatCount > 4) - { - concats = new T[item.ConcatCount]; - } - else - { - switch (i++) - { - case 0: concat1 = item.Value; break; - case 1: concat2 = item.Value; break; - case 2: concat3 = item.Value; break; - case 3: concat4 = item.Value; break; - default: throw new UnreachableException(); - } - continue; - } - } - - concats[i++] = item.Value; - } - } - - var source = (Source)current; - - foreach (var item in source.Value) - yield return item; - - if (concats == null) - { - if (i == 4) { yield return concat4!; i--; } - if (i == 3) { yield return concat3!; i--; } - if (i == 2) { yield return concat2!; i--; } - if (i == 1) { yield return concat1!; } - yield break; - } - - for (i--; i >= 0; i--) - yield return concats[i]; - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - } -} diff --git a/MoreLinq/UnreachableException.cs b/MoreLinq/UnreachableException.cs deleted file mode 100644 index 80e4cf0eb..000000000 --- a/MoreLinq/UnreachableException.cs +++ /dev/null @@ -1,58 +0,0 @@ -#region License and Terms -// The MIT License (MIT) -// -// Copyright (c) .NET Foundation and Contributors -// -// All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -#if !NET7_0_OR_GREATER - -namespace MoreLinq -{ - using System; - - // Source: https://github.com/dotnet/runtime/blob/v7.0.2/src/libraries/System.Private.CoreLib/src/System/Diagnostics/UnreachableException.cs - - /// - /// Exception thrown when the program executes an instruction that was thought to be unreachable. - /// - -#if !NETSTANDARD1_0 - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -#endif -#pragma warning disable CA1064 // Exceptions should be public - sealed class UnreachableException : Exception -#pragma warning restore CA1064 // Exceptions should be public - { - public UnreachableException() : - this(null) { } - - public UnreachableException(string? message) : - base(message, null) { } - - public UnreachableException(string? message, Exception? innerException) : - base(message ?? "The program executed an instruction that was thought to be unreachable.", - innerException) { } - } -} - -#endif // !NET7_0_OR_GREATER From cf55babce69e6cc601ba6696d80da8c3c5e54a96 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sun, 25 Jun 2023 14:23:08 +0200 Subject: [PATCH 12/12] Revert removal of "Append" and "Prepend" This reverts commits: - Remove unused "Append"/"Prepend"supporting types: b9316f7f943cf1897f84a8fd4b9d6277265b82f9 - Remove "Append" and "Prepend": ca3a8e26b3d6401f7f3bcd7784f3468adf75c777 --- MoreLinq.Test/AppendTest.cs | 96 ++++++++++++++ MoreLinq.Test/PrependTest.cs | 95 +++++++++++++ MoreLinq/Append.cs | 46 +++++++ MoreLinq/Extensions.g.cs | 48 +++++++ MoreLinq/PendNode.cs | 125 ++++++++++++++++++ MoreLinq/Prepend.cs | 56 ++++++++ .../PublicAPI/net6.0/PublicAPI.Unshipped.txt | 6 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 6 +- .../netstandard2.1/PublicAPI.Unshipped.txt | 6 +- MoreLinq/UnreachableException.cs | 58 ++++++++ README.md | 16 +-- 11 files changed, 534 insertions(+), 24 deletions(-) create mode 100644 MoreLinq.Test/AppendTest.cs create mode 100644 MoreLinq.Test/PrependTest.cs create mode 100644 MoreLinq/Append.cs create mode 100644 MoreLinq/PendNode.cs create mode 100644 MoreLinq/Prepend.cs create mode 100644 MoreLinq/UnreachableException.cs diff --git a/MoreLinq.Test/AppendTest.cs b/MoreLinq.Test/AppendTest.cs new file mode 100644 index 000000000..55ff31597 --- /dev/null +++ b/MoreLinq.Test/AppendTest.cs @@ -0,0 +1,96 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2008 Jonathan Skeet. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +#if !NET471_OR_GREATER && !NETSTANDARD1_6_OR_GREATER && !NETCOREAPP2_0_OR_GREATER + +namespace MoreLinq.Test +{ + using System.Collections.Generic; + using NUnit.Framework; + + [TestFixture] + public class AppendTest + { + #region Append with single head and tail sequence + [Test] + public void AppendWithNonEmptyHeadSequence() + { + var head = new[] { "first", "second" }; + var tail = "third"; + var whole = head.Append(tail); + whole.AssertSequenceEqual("first", "second", "third"); + } + + [Test] + public void AppendWithEmptyHeadSequence() + { + string[] head = { }; + var tail = "first"; + var whole = head.Append(tail); + whole.AssertSequenceEqual("first"); + } + + [Test] + public void AppendWithNullTail() + { + var head = new[] { "first", "second" }; + string? tail = null; + var whole = head.Append(tail); + whole.AssertSequenceEqual("first", "second", null); + } + + [Test] + public void AppendIsLazyInHeadSequence() + { + _ = new BreakingSequence().Append("tail"); + } + #endregion + + [TestCaseSource(nameof(ContactManySource))] + public void AppendMany(int[] head, int[] tail) + { + tail.Aggregate(head.AsEnumerable(), (xs, x) => xs.Append(x)) + .AssertSequenceEqual(head.Concat(tail)); + } + + public static IEnumerable ContactManySource => + from x in Enumerable.Range(0, 11) + from y in Enumerable.Range(1, 20 - x) + select new + { + Head = Enumerable.Range(1, x).ToArray(), + Tail = Enumerable.Range(x + 1, y).ToArray(), + } + into e + select new TestCaseData(e.Head, + e.Tail).SetName("Head = [" + string.Join(", ", e.Head) + "], " + + "Tail = [" + string.Join(", ", e.Tail) + "]"); + + [Test] + public void AppendWithSharedSource() + { + var first = new[] { 1 }.Append(2); + var second = first.Append(3).Append(4); + var third = first.Append(4).Append(8); + + second.AssertSequenceEqual(1, 2, 3, 4); + third.AssertSequenceEqual(1, 2, 4, 8); + } + } +} + +#endif diff --git a/MoreLinq.Test/PrependTest.cs b/MoreLinq.Test/PrependTest.cs new file mode 100644 index 000000000..3a4f938d1 --- /dev/null +++ b/MoreLinq.Test/PrependTest.cs @@ -0,0 +1,95 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2008 Jonathan Skeet. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +#if !NET471_OR_GREATER && !NETSTANDARD1_6_OR_GREATER && !NETCOREAPP2_0_OR_GREATER + +namespace MoreLinq.Test +{ + using System.Collections.Generic; + using NUnit.Framework; + using NUnit.Framework.Interfaces; + + [TestFixture] + public class PrependTest + { + [Test] + public void PrependWithNonEmptyTailSequence() + { + string[] tail = { "second", "third" }; + var head = "first"; + var whole = tail.Prepend(head); + whole.AssertSequenceEqual("first", "second", "third"); + } + + [Test] + public void PrependWithEmptyTailSequence() + { + string[] tail = { }; + var head = "first"; + var whole = tail.Prepend(head); + whole.AssertSequenceEqual("first"); + } + + [Test] + public void PrependWithNullHead() + { + string[] tail = { "second", "third" }; + string? head = null; + var whole = tail.Prepend(head); + whole.AssertSequenceEqual(null, "second", "third"); + } + + [Test] + public void PrependIsLazyInTailSequence() + { + _ = new BreakingSequence().Prepend("head"); + } + + [TestCaseSource(nameof(PrependManySource))] + public int[] PrependMany(int[] head, int[] tail) + { + return tail.Aggregate(head.AsEnumerable(), MoreEnumerable.Prepend).ToArray(); + } + + public static IEnumerable PrependManySource => + from x in Enumerable.Range(0, 11) + from y in Enumerable.Range(1, 11) + select new + { + Head = Enumerable.Range(0, y).Select(n => 0 - n).ToArray(), + Tail = Enumerable.Range(1, x).ToArray(), + } + into e + select new TestCaseData(e.Head, e.Tail) + .SetName("Head = [" + string.Join(", ", e.Head) + "], " + + "Tail = [" + string.Join(", ", e.Tail) + "]") + .Returns(e.Tail.Reverse().Concat(e.Head).ToArray()); + + [Test] + public void PrependWithSharedSource() + { + var first = new[] { 1 }.Prepend(2); + var second = first.Prepend(3).Prepend(4); + var third = first.Prepend(4).Prepend(8); + + second.AssertSequenceEqual(4, 3, 2, 1); + third.AssertSequenceEqual(8, 4, 2, 1); + } + } +} + +#endif diff --git a/MoreLinq/Append.cs b/MoreLinq/Append.cs new file mode 100644 index 000000000..3a02d376b --- /dev/null +++ b/MoreLinq/Append.cs @@ -0,0 +1,46 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2008 Jonathan Skeet. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace MoreLinq +{ + using System; + using System.Collections.Generic; + + static partial class MoreEnumerable + { + /// + /// Returns a sequence consisting of the head elements and the given tail element. + /// + /// Type of sequence + /// All elements of the head. Must not be null. + /// Tail element of the new sequence. + /// A sequence consisting of the head elements and the given tail element. + /// This operator uses deferred execution and streams its results. + +#if NET471_OR_GREATER || NETSTANDARD1_6_OR_GREATER || NETCOREAPP2_0_OR_GREATER + public static IEnumerable Append(IEnumerable head, T tail) +#else + public static IEnumerable Append(this IEnumerable head, T tail) +#endif + { + if (head == null) throw new ArgumentNullException(nameof(head)); + return head is PendNode node + ? node.Concat(tail) + : PendNode.WithSource(head).Concat(tail); + } + } +} diff --git a/MoreLinq/Extensions.g.cs b/MoreLinq/Extensions.g.cs index 4137ef772..b25c873fb 100644 --- a/MoreLinq/Extensions.g.cs +++ b/MoreLinq/Extensions.g.cs @@ -430,6 +430,25 @@ public static TResult AggregateRight(this IEnumer } + /// Append extension. + + [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] + public static partial class AppendExtension + { + /// + /// Returns a sequence consisting of the head elements and the given tail element. + /// + /// Type of sequence + /// All elements of the head. Must not be null. + /// Tail element of the new sequence. + /// A sequence consisting of the head elements and the given tail element. + /// This operator uses deferred execution and streams its results. + + public static IEnumerable Append(this IEnumerable head, T tail) + => MoreEnumerable.Append(head, tail); + + } + /// Assert extension. [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] @@ -4540,6 +4559,35 @@ public static IEnumerable Pipe(this IEnumerable source, Action actio } + /// Prepend extension. + + [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] + public static partial class PrependExtension + { + /// + /// Prepends a single value to a sequence. + /// + /// The type of the elements of . + /// The sequence to prepend to. + /// The value to prepend. + /// + /// Returns a sequence where a value is prepended to it. + /// + /// + /// This operator uses deferred execution and streams its results. + /// + /// + /// The result variable, when iterated over, will yield + /// 0, 1, 2 and 3, in turn. + + public static IEnumerable Prepend(this IEnumerable source, TSource value) + => MoreEnumerable.Prepend(source, value); + + } + /// PreScan extension. [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] diff --git a/MoreLinq/PendNode.cs b/MoreLinq/PendNode.cs new file mode 100644 index 000000000..2bf363863 --- /dev/null +++ b/MoreLinq/PendNode.cs @@ -0,0 +1,125 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2017 Atif Aziz. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace MoreLinq +{ + using System; + using System.Collections; + using System.Collections.Generic; + + /// + /// Prepend-Append node is a single linked-list of the discriminated union + /// of an item to prepend, an item to append and the source. + /// + + abstract class PendNode : IEnumerable + { + public static PendNode WithSource(IEnumerable source) => new Source(source); + + public PendNode Prepend(T item) => new Item(item, isPrepend: true , next: this); + public PendNode Concat(T item) => new Item(item, isPrepend: false, next: this); + + sealed class Item : PendNode + { + public T Value { get; } + public bool IsPrepend { get; } + public int ConcatCount { get; } + public PendNode Next { get; } + + public Item(T item, bool isPrepend, PendNode next) + { + if (next == null) throw new ArgumentNullException(nameof(next)); + + Value = item; + IsPrepend = isPrepend; + ConcatCount = next is Item nextItem + ? nextItem.ConcatCount + (isPrepend ? 0 : 1) + : 1; + Next = next; + } + } + + sealed class Source : PendNode + { + public IEnumerable Value { get; } + public Source(IEnumerable source) => Value = source; + } + + public IEnumerator GetEnumerator() + { + var i = 0; + T[]? concats = null; // Array for > 4 concatenations + var concat1 = default(T); // Slots for up to 4 concatenations + var concat2 = default(T); + var concat3 = default(T); + var concat4 = default(T); + + var current = this; + for (; current is Item item; current = item.Next) + { + if (item.IsPrepend) + { + yield return item.Value; + } + else + { + if (concats == null) + { + if (i == 0 && item.ConcatCount > 4) + { + concats = new T[item.ConcatCount]; + } + else + { + switch (i++) + { + case 0: concat1 = item.Value; break; + case 1: concat2 = item.Value; break; + case 2: concat3 = item.Value; break; + case 3: concat4 = item.Value; break; + default: throw new UnreachableException(); + } + continue; + } + } + + concats[i++] = item.Value; + } + } + + var source = (Source)current; + + foreach (var item in source.Value) + yield return item; + + if (concats == null) + { + if (i == 4) { yield return concat4!; i--; } + if (i == 3) { yield return concat3!; i--; } + if (i == 2) { yield return concat2!; i--; } + if (i == 1) { yield return concat1!; } + yield break; + } + + for (i--; i >= 0; i--) + yield return concats[i]; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + } +} diff --git a/MoreLinq/Prepend.cs b/MoreLinq/Prepend.cs new file mode 100644 index 000000000..fb82e8538 --- /dev/null +++ b/MoreLinq/Prepend.cs @@ -0,0 +1,56 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2009 Atif Aziz. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace MoreLinq +{ + using System; + using System.Collections.Generic; + + static partial class MoreEnumerable + { + /// + /// Prepends a single value to a sequence. + /// + /// The type of the elements of . + /// The sequence to prepend to. + /// The value to prepend. + /// + /// Returns a sequence where a value is prepended to it. + /// + /// + /// This operator uses deferred execution and streams its results. + /// + /// + /// The result variable, when iterated over, will yield + /// 0, 1, 2 and 3, in turn. + +#if NET471_OR_GREATER || NETSTANDARD1_6_OR_GREATER || NETCOREAPP2_0_OR_GREATER + public static IEnumerable Prepend(IEnumerable source, TSource value) +#else + public static IEnumerable Prepend(this IEnumerable source, TSource value) +#endif + { + if (source == null) throw new ArgumentNullException(nameof(source)); + return source is PendNode node + ? node.Prepend(value) + : PendNode.WithSource(source).Prepend(value); + } + } +} diff --git a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt index 8efe28e0a..8959c7eec 100644 --- a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt @@ -1,8 +1,4 @@ #nullable enable -*REMOVED*MoreLinq.Extensions.AppendExtension -*REMOVED*MoreLinq.Extensions.PrependExtension -*REMOVED*static MoreLinq.Extensions.AppendExtension.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! -*REMOVED*static MoreLinq.Extensions.PrependExtension.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Concat(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! @@ -12,8 +8,10 @@ *REMOVED*static MoreLinq.MoreEnumerable.TakeLast(this System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEqualityComparer? comparer) -> System.Collections.Generic.HashSet! +static MoreLinq.MoreEnumerable.Append(System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.DistinctBy(System.Collections.Generic.IEnumerable! source, System.Func! keySelector) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.DistinctBy(System.Collections.Generic.IEnumerable! source, System.Func! keySelector, System.Collections.Generic.IEqualityComparer? comparer) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.Prepend(System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.SkipLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.TakeLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.ToHashSet(System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! diff --git a/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index 37e54326a..056e1801b 100644 --- a/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,8 +1,6 @@ #nullable enable -*REMOVED*MoreLinq.Extensions.AppendExtension -*REMOVED*MoreLinq.Extensions.PrependExtension -*REMOVED*static MoreLinq.Extensions.AppendExtension.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! -*REMOVED*static MoreLinq.Extensions.PrependExtension.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Concat(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.Append(System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.Prepend(System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! diff --git a/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt index ebb7ca31b..b025e7aed 100644 --- a/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt @@ -1,8 +1,4 @@ #nullable enable -*REMOVED*MoreLinq.Extensions.AppendExtension -*REMOVED*MoreLinq.Extensions.PrependExtension -*REMOVED*static MoreLinq.Extensions.AppendExtension.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! -*REMOVED*static MoreLinq.Extensions.PrependExtension.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Append(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Concat(this System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.Prepend(this System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! @@ -10,6 +6,8 @@ *REMOVED*static MoreLinq.MoreEnumerable.TakeLast(this System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! *REMOVED*static MoreLinq.MoreEnumerable.ToHashSet(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEqualityComparer? comparer) -> System.Collections.Generic.HashSet! +static MoreLinq.MoreEnumerable.Append(System.Collections.Generic.IEnumerable! head, T tail) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.Prepend(System.Collections.Generic.IEnumerable! source, TSource value) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.SkipLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.TakeLast(System.Collections.Generic.IEnumerable! source, int count) -> System.Collections.Generic.IEnumerable! static MoreLinq.MoreEnumerable.ToHashSet(System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.HashSet! diff --git a/MoreLinq/UnreachableException.cs b/MoreLinq/UnreachableException.cs new file mode 100644 index 000000000..80e4cf0eb --- /dev/null +++ b/MoreLinq/UnreachableException.cs @@ -0,0 +1,58 @@ +#region License and Terms +// The MIT License (MIT) +// +// Copyright (c) .NET Foundation and Contributors +// +// All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NET7_0_OR_GREATER + +namespace MoreLinq +{ + using System; + + // Source: https://github.com/dotnet/runtime/blob/v7.0.2/src/libraries/System.Private.CoreLib/src/System/Diagnostics/UnreachableException.cs + + /// + /// Exception thrown when the program executes an instruction that was thought to be unreachable. + /// + +#if !NETSTANDARD1_0 + [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +#endif +#pragma warning disable CA1064 // Exceptions should be public + sealed class UnreachableException : Exception +#pragma warning restore CA1064 // Exceptions should be public + { + public UnreachableException() : + this(null) { } + + public UnreachableException(string? message) : + base(message, null) { } + + public UnreachableException(string? message, Exception? innerException) : + base(message ?? "The program executed an instruction that was thought to be unreachable.", + innerException) { } + } +} + +#endif // !NET7_0_OR_GREATER diff --git a/README.md b/README.md index b2f1c50ad..2c9962eda 100644 --- a/README.md +++ b/README.md @@ -103,14 +103,10 @@ This operator is the right-associative version of the Aggregate LINQ operator. This method has 3 overloads. -### ~~Append~~ +### Append Returns a sequence consisting of the head element and the given tail elements. -This extension was removed in version 4.0. Use [`Append`][linq-append] from .NET -instead that's been available since .NET Standard 1.6+, .NET Core 1.0+ and .NET -Framework 4.7.1+. - ### Assert Asserts that all elements of a sequence meet a given condition otherwise @@ -175,6 +171,8 @@ This extension was rendered obsolete in version 3.0 and eventually removed in version 4.0. Use [`Append`][linq-append] from .NET instead that's been available since .NET Standard 1.6+, .NET Core 1.0+ and .NET Framework 4.7.1+. +[linq-append]: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.append + ### Consume Completely consumes the given sequence. This method uses immediate execution, @@ -444,14 +442,10 @@ sequence Executes the given action on each element in the source sequence and yields it -### ~~Prepend~~ +### Prepend Prepends a single value to a sequence -This extension was removed in version 4.0. Use [`Prepend`][linq-prepend] from -.NET instead that's been available since .NET Standard 1.6+, .NET Core 1.0+ and -.NET Framework 4.7.1+. - ### PreScan Performs a pre-scan (exclusive prefix sum) on a sequence of elements @@ -788,5 +782,3 @@ This method has 2 overloads. [lookup]: https://docs.microsoft.com/en-us/dotnet/api/system.linq.lookup-2 [v2.1]: https://github.com/morelinq/MoreLINQ/releases/tag/v2.1.0 [v3.0]: https://github.com/morelinq/MoreLINQ/releases/tag/v3.0.0 -[linq-append]: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.append -[linq-prepend]: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.prepend