├── .config └── dotnet-tools.json ├── .devcontainer ├── README.md └── devcontainer.json ├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── COPYING.txt ├── Directory.Build.props ├── MoreLinq.Test.Aot ├── MoreLinq.Test.Aot.csproj └── ToDataTableTest.cs ├── MoreLinq.Test ├── .editorconfig ├── AcquireTest.cs ├── AggregateRightTest.cs ├── AggregateTest.cs ├── AppendTest.cs ├── AssertCountTest.cs ├── AssertTest.cs ├── Async │ ├── AsyncEnumerable.cs │ ├── MergeTest.cs │ ├── TestExtensions.cs │ ├── TestingAsyncSequence.cs │ └── WatchableEnumerator.cs ├── AtLeastTest.cs ├── AtMostTest.cs ├── BacksertTest.cs ├── BatchTest.cs ├── BreakingAction.cs ├── BreakingCollection.cs ├── BreakingFunc.cs ├── BreakingList.cs ├── BreakingReadOnlyCollection.cs ├── BreakingReadOnlyList.cs ├── BreakingSequence.cs ├── CartesianTest.cs ├── ChooseTest.cs ├── Combinatorics.cs ├── Comparable.cs ├── CompareCountTest.cs ├── ConsumeTest.cs ├── CountBetweenTest.cs ├── CountByTest.cs ├── CountDownTest.cs ├── CurrentThreadCultureScope.cs ├── DistinctByTest.cs ├── DuplicatesTest.cs ├── EndsWithTest.cs ├── Enumerable.cs ├── EqualityComparer.cs ├── EquiZipTest.cs ├── EvaluateTest.cs ├── ExactlyTest.cs ├── ExceptByTest.cs ├── ExcludeTest.cs ├── Extensions.cs ├── FallbackIfEmptyTest.cs ├── FillBackwardTest.cs ├── FillForwardTest.cs ├── FlattenTest.cs ├── FoldTest.cs ├── ForEachTest.cs ├── FromTest.cs ├── FullGroupJoinTest.cs ├── FullJoinTest.cs ├── FuncModule.cs ├── GenerateTest.cs ├── GroupAdjacentTest.cs ├── IndexByTest.cs ├── IndexTest.cs ├── InsertTest.cs ├── InterleaveTest.cs ├── KeyValuePair.cs ├── LagTest.cs ├── LeadTest.cs ├── LeftJoinTest.cs ├── Make.cs ├── MaximaTest.cs ├── MemoizeTest.cs ├── MinimaTest.cs ├── MoreLinq.Test.csproj ├── MoveTest.cs ├── NullArgumentTest.cs ├── OrderByTest.cs ├── OrderedMergeTest.cs ├── PadStartTest.cs ├── PadTest.cs ├── PairwiseTest.cs ├── PartialSortByTest.cs ├── PartialSortTest.cs ├── PartitionTest.cs ├── PermutationsTest.cs ├── PipeTest.cs ├── PreScanTest.cs ├── PrependTest.cs ├── Program.cs ├── RandomSubsetTest.cs ├── RandomTest.cs ├── RankTest.cs ├── ReadOnlyCollection.cs ├── RepeatTest.cs ├── ReturnTest.cs ├── RightJoinTest.cs ├── RunLengthEncodeTest.cs ├── SampleData.cs ├── ScanByTest.cs ├── ScanRightTest.cs ├── ScanTest.cs ├── Scope.cs ├── SegmentTest.cs ├── SequenceReader.cs ├── SequenceTest.cs ├── ShuffleTest.cs ├── SkipLastTest.cs ├── SkipLastWhileTest.cs ├── SkipUntilTest.cs ├── SliceTest.cs ├── SortedMergeTest.cs ├── SplitTest.cs ├── StartsWithTest.cs ├── SubjectTest.cs ├── SubsetTest.cs ├── TagFirstLastTest.cs ├── TakeEveryTest.cs ├── TakeLastTest.cs ├── TakeUntilTest.cs ├── TestException.cs ├── TestExtensions.cs ├── TestingSequence.cs ├── Throws.cs ├── ToArrayByIndexTest.cs ├── ToDataTableTest.cs ├── ToDelimitedStringTest.cs ├── ToDictionaryTest.cs ├── ToLookupTest.cs ├── TraceTest.cs ├── TransposeTest.cs ├── TraverseTest.cs ├── TrySingleTest.cs ├── UnfoldTest.cs ├── WatchableEnumerator.cs ├── WindowLeftTest.cs ├── WindowRightTest.cs ├── WindowTest.cs ├── ZipLongestTest.cs ├── ZipShortestTest.cs └── coverlet.runsettings ├── MoreLinq.shfbproj ├── MoreLinq.sln ├── MoreLinq ├── Acquire.cs ├── Aggregate.g.cs ├── Aggregate.g.tt ├── AggregateRight.cs ├── Append.cs ├── AssemblyInfo.cs ├── Assert.cs ├── AssertCount.cs ├── Assume.cs ├── Backsert.cs ├── Batch.cs ├── Cartesian.g.cs ├── Cartesian.g.tt ├── Choose.cs ├── CollectionLike.cs ├── Collections │ └── Dictionary.cs ├── CompatibilitySuppressions.xml ├── Consume.cs ├── CountBy.cs ├── CountDown.cs ├── CountMethods.cs ├── Debug.cs ├── Delegating.cs ├── Disposable.cs ├── DistinctBy.cs ├── Duplicates.cs ├── EndsWith.cs ├── EquiZip.cs ├── Evaluate.cs ├── ExceptBy.cs ├── Exclude.cs ├── Experimental │ ├── Aggregate.cs │ ├── Async │ │ ├── ExperimentalEnumerable.cs │ │ └── Merge.cs │ ├── Await.cs │ ├── Batch.cs │ ├── CurrentBuffer.cs │ ├── ExperimentalEnumerable.cs │ ├── Memoize.cs │ └── TrySingle.cs ├── Extensions.ToDataTable.g.cs ├── Extensions.g.cs ├── ExtremaMembers.cs ├── FallbackIfEmpty.cs ├── FillBackward.cs ├── FillForward.cs ├── Flatten.cs ├── Fold.cs ├── Fold.g.cs ├── Fold.g.tt ├── ForEach.cs ├── From.cs ├── FullGroupJoin.cs ├── FullJoin.cs ├── Generate.cs ├── GenerateByIndex.cs ├── GlobalRandom.cs ├── GroupAdjacent.cs ├── IdFn.cs ├── Index.cs ├── IndexBy.cs ├── Insert.cs ├── Interleave.cs ├── Lag.cs ├── Lead.cs ├── LeftJoin.cs ├── ListLike.cs ├── Lock.cs ├── Lookup.cs ├── MaxBy.cs ├── Maxima.cs ├── MinBy.cs ├── Minima.cs ├── MoreEnumerable.cs ├── MoreLinq.csproj ├── Move.cs ├── OrderBy.cs ├── OrderByDirection.cs ├── OrderedMerge.cs ├── Pad.cs ├── PadStart.cs ├── Pairwise.cs ├── PartialSort.cs ├── Partition.cs ├── PendNode.cs ├── Permutations.cs ├── Pipe.cs ├── PreScan.cs ├── Prepend.cs ├── PublicAPI │ ├── net8.0 │ │ ├── PublicAPI.Shipped.txt │ │ └── PublicAPI.Unshipped.txt │ ├── net9.0 │ │ ├── PublicAPI.Shipped.txt │ │ └── PublicAPI.Unshipped.txt │ ├── netstandard2.0 │ │ ├── PublicAPI.Shipped.txt │ │ └── PublicAPI.Unshipped.txt │ └── netstandard2.1 │ │ ├── PublicAPI.Shipped.txt │ │ └── PublicAPI.Unshipped.txt ├── Random.cs ├── RandomSubset.cs ├── Rank.cs ├── Reactive │ ├── Observable.cs │ └── Subject.cs ├── Repeat.cs ├── Return.cs ├── ReverseComparer.cs ├── RightJoin.cs ├── RunLengthEncode.cs ├── Scan.cs ├── ScanBy.cs ├── ScanRight.cs ├── Segment.cs ├── Sequence.cs ├── SequenceException.cs ├── Shuffle.cs ├── SkipLast.cs ├── SkipLastWhile.cs ├── SkipUntil.cs ├── Slice.cs ├── SortedMerge.cs ├── Split.cs ├── StartsWith.cs ├── Subsets.cs ├── TagFirstLast.cs ├── TakeEvery.cs ├── TakeLast.cs ├── TakeUntil.cs ├── ToArrayByIndex.cs ├── ToDataTable.cs ├── ToDelimitedString.cs ├── ToDelimitedString.g.cs ├── ToDelimitedString.g.tt ├── ToDictionary.cs ├── ToHashSet.cs ├── ToLookup.cs ├── Trace.cs ├── Transpose.cs ├── Traverse.cs ├── Unfold.cs ├── UnreachableException.cs ├── Window.cs ├── WindowLeft.cs ├── WindowRight.cs ├── ZipImpl.cs ├── ZipLongest.cs ├── ZipShortest.cs ├── key.snk ├── tt.cmd └── tt.sh ├── README.md ├── appveyor.yml ├── bld ├── Copyright.props └── ExtensionsGenerator │ ├── .editorconfig │ ├── MoreLinq.ExtensionsGenerator.csproj │ └── Program.cs ├── build.cmd ├── build.sh ├── builddocs.cmd ├── eclint.ps1 ├── global.json ├── msbuild.cmd ├── pack.cmd ├── pack.sh ├── test.cmd ├── test.sh └── tools ├── dotnet-install.ps1 ├── dotnet-install.sh ├── mark-shipped.cmd └── mark-shipped.ps1 /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "dotnet-t4": { 6 | "version": "3.0.0", 7 | "commands": [ 8 | "t4" 9 | ], 10 | "rollForward": false 11 | }, 12 | "dotnet-reportgenerator-globaltool": { 13 | "version": "5.3.9", 14 | "commands": [ 15 | "reportgenerator" 16 | ], 17 | "rollForward": false 18 | }, 19 | "meziantou.framework.nugetpackagevalidation.tool": { 20 | "version": "1.0.16", 21 | "commands": [ 22 | "meziantou.validate-nuget-package" 23 | ], 24 | "rollForward": false 25 | }, 26 | "powershell": { 27 | "version": "7.4.5", 28 | "commands": [ 29 | "pwsh" 30 | ], 31 | "rollForward": false 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.devcontainer/README.md: -------------------------------------------------------------------------------- 1 | # Dev Container 2 | 3 | [![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/morelinq/MoreLINQ) 4 | 5 | For a consistent development experience, you can use [Visual Studio Code] with 6 | the [Dev Containers extension]. A [dev container] provides a ready-to-use 7 | development environment with all the necessary dependencies. 8 | 9 | To use [the dev container]: 10 | 11 | 1. Install [Visual Studio Code] 12 | 2. Install the [Dev Containers extension] 13 | 3. Clone the repository and open it in VS Code 14 | 4. When prompted, click **Reopen in Container** or run the **Dev Containers: 15 | Reopen in Container** command 16 | 17 | Alternatively, you can use [GitHub Codespaces] to develop in the cloud without 18 | installing anything locally. Simply click the **Code** button in [the GitHub 19 | repository] and select **Open with Codespaces** to get started with the same 20 | development environment. 21 | 22 | The dev container uses an Ubuntu-based image and automatically installs: 23 | 24 | - .NET SDK based on the version in [`global.json`] 25 | - Supported .NET runtimes targets for testing 26 | - Git and GitHub CLI 27 | - All necessary VS Code extensions for .NET development 28 | 29 | Once the container environment is up and running, build and test the solution by 30 | executing: 31 | 32 | ```sh 33 | ./test.sh 34 | ``` 35 | 36 | [`global.json`]: ../global.json 37 | [dev container]: https://containers.dev/ 38 | [the dev container]: devcontainer.json 39 | [Visual Studio Code]: https://code.visualstudio.com/ 40 | [Dev Containers extension]: https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers 41 | [GitHub Codespaces]: https://github.com/features/codespaces 42 | [the GitHub repository]: https://github.com/morelinq/MoreLINQ 43 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MoreLINQ", 3 | "image": "mcr.microsoft.com/devcontainers/base:ubuntu-22.04", 4 | "customizations": { 5 | "vscode": { 6 | "extensions": [ 7 | "ms-dotnettools.csdevkit", 8 | "ms-dotnettools.csharp", 9 | "ms-dotnettools.vscode-dotnet-runtime", 10 | "editorconfig.editorconfig", 11 | "github.copilot", 12 | "streetsidesoftware.code-spell-checker" 13 | ], 14 | "settings": { 15 | "dotnet.defaultSolution": "MoreLinq.sln", 16 | "editor.formatOnSave": true, 17 | "omnisharp.enableRoslynAnalyzers": true, 18 | "omnisharp.enableEditorConfigSupport": true 19 | } 20 | } 21 | }, 22 | "features": { 23 | "ghcr.io/devcontainers/features/git:1": { 24 | "version": "latest" 25 | }, 26 | "ghcr.io/devcontainers/features/github-cli:1": { 27 | "version": "latest" 28 | }, 29 | "ghcr.io/devcontainers/features/dotnet:2": { 30 | "version": "9.0.300", 31 | "dotnetRuntimeVersions": "8.0.14" 32 | }, 33 | "ghcr.io/devcontainers/features/common-utils:2": { 34 | "installZsh": false, 35 | "configureZshAsDefaultShell": false, 36 | "installOhMyZsh": false, 37 | "username": "vscode", 38 | "userUid": "1000", 39 | "userGid": "1000", 40 | "upgradePackages": true 41 | } 42 | }, 43 | "postCreateCommand": "dotnet restore", 44 | "remoteUser": "vscode" 45 | } 46 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | *.sh eol=lf 5 | 6 | # Custom for Visual Studio 7 | *.cs diff=csharp 8 | 9 | # Standard to msysgit 10 | *.doc diff=astextplain 11 | *.DOC diff=astextplain 12 | *.docx diff=astextplain 13 | *.DOCX diff=astextplain 14 | *.dot diff=astextplain 15 | *.DOT diff=astextplain 16 | *.pdf diff=astextplain 17 | *.PDF diff=astextplain 18 | *.rtf diff=astextplain 19 | *.RTF diff=astextplain 20 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 4 | enable 5 | true 6 | 8.0-all 7 | true 8 | 9 | EnableGenerateDocumentationFile 10 | 11 | 12 | -------------------------------------------------------------------------------- /MoreLinq.Test.Aot/MoreLinq.Test.Aot.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0;net8.0 5 | exe 6 | false 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /MoreLinq.Test/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # CA1034: Nested types should not be visible 4 | dotnet_diagnostic.CA1034.severity = none 5 | 6 | # CA1062: Validate arguments of public methods 7 | dotnet_diagnostic.CA1062.severity = none 8 | 9 | # CA1825: Avoid zero-length array allocations 10 | dotnet_diagnostic.CA1825.severity = suggestion 11 | 12 | # CA1032: Implement standard exception constructors 13 | dotnet_diagnostic.CA1032.severity = none 14 | 15 | # CA1064: Exceptions should be public 16 | dotnet_diagnostic.CA1064.severity = none 17 | 18 | # CA1303: Do not pass literals as localized parameters 19 | dotnet_diagnostic.CA1303.severity = none 20 | 21 | # CA5394: Do not use insecure randomness 22 | dotnet_diagnostic.CA5394.severity = none 23 | 24 | # CA1707: Identifiers should not contain underscores 25 | dotnet_diagnostic.CA1707.severity = none 26 | 27 | # CA1308: Normalize strings to uppercase 28 | dotnet_diagnostic.CA1308.severity = none 29 | 30 | # CA2007: Consider calling ConfigureAwait on the awaited task 31 | dotnet_diagnostic.CA2007.severity = suggestion 32 | 33 | # IDE0047: Remove unnecessary parentheses 34 | dotnet_diagnostic.IDE0047.severity = suggestion 35 | 36 | [*{Test,Tests}.cs] 37 | 38 | # CA1861: Avoid constant arrays as arguments 39 | dotnet_diagnostic.CA1861.severity = none 40 | 41 | # IDE0022: Use expression/block body for methods 42 | dotnet_diagnostic.IDE0022.severity = none 43 | -------------------------------------------------------------------------------- /MoreLinq.Test/AcquireTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class AcquireTest 25 | { 26 | [Test] 27 | public void AcquireAll() 28 | { 29 | Disposable? a = null; 30 | Disposable? b = null; 31 | Disposable? c = null; 32 | 33 | var allocators = MoreEnumerable.From(() => a = new Disposable(), 34 | () => b = new Disposable(), 35 | () => c = new Disposable()); 36 | 37 | var disposables = allocators.Acquire(); 38 | 39 | Assert.That(disposables.Length, Is.EqualTo(3)); 40 | 41 | foreach (var disposable in disposables.ZipShortest([a, b, c], (act, exp) => new { Actual = act, Expected = exp })) 42 | { 43 | Assert.That(disposable.Actual, Is.SameAs(disposable.Expected)); 44 | Assert.That(disposable.Actual.Disposed, Is.False); 45 | } 46 | } 47 | 48 | [Test] 49 | public void AcquireSome() 50 | { 51 | Disposable? a = null; 52 | Disposable? b = null; 53 | Disposable? c = null; 54 | 55 | var allocators = MoreEnumerable.From(() => a = new Disposable(), 56 | () => b = new Disposable(), 57 | () => throw new TestException(), 58 | () => c = new Disposable()); 59 | 60 | Assert.That(allocators.Acquire, Throws.TypeOf()); 61 | 62 | Assert.That(a, Is.Not.Null); 63 | Assert.That(a.Disposed, Is.True); 64 | Assert.That(b, Is.Not.Null); 65 | Assert.That(b.Disposed, Is.True); 66 | Assert.That(c, Is.Null); 67 | } 68 | 69 | sealed class Disposable : IDisposable 70 | { 71 | public bool Disposed { get; private set; } 72 | public void Dispose() => Disposed = true; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /MoreLinq.Test/AssertTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2013 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class AssertTest 25 | { 26 | [Test] 27 | public void AssertIsLazy() 28 | { 29 | _ = new BreakingSequence().Assert(BreakingFunc.Of()); 30 | _ = new BreakingSequence().Assert(BreakingFunc.Of(), BreakingFunc.Of()); 31 | } 32 | 33 | [Test] 34 | public void AssertSequenceWithValidAllElements() 35 | { 36 | var source = new[] { 2, 4, 6, 8 }; 37 | source.Assert(n => n % 2 == 0).AssertSequenceEqual(source); 38 | } 39 | 40 | [Test] 41 | public void AssertSequenceWithValidSomeInvalidElements() 42 | { 43 | var source = new[] { 2, 4, 6, 7, 8, 9 }; 44 | Assert.That(() => source.Assert(n => n % 2 == 0).Consume(), 45 | Throws.InvalidOperationException); 46 | } 47 | 48 | [Test] 49 | public void AssertSequenceWithInvalidElementsAndCustomErrorReturningNull() 50 | { 51 | var source = new[] { 2, 4, 6, 7, 8, 9 }; 52 | Assert.That(() => source.Assert(n => n % 2 == 0, _ => null!).Consume(), 53 | Throws.InvalidOperationException); 54 | } 55 | 56 | [Test] 57 | public void AssertSequenceWithInvalidElementsAndCustomError() 58 | { 59 | var source = new[] { 2, 4, 6, 7, 8, 9 }; 60 | Assert.That(() => 61 | source.Assert(n => n % 2 == 0, n => new ValueException(n)).Consume(), 62 | Throws.TypeOf() 63 | .With.Property(nameof(ValueException.Value)).EqualTo(7)); 64 | } 65 | 66 | sealed class ValueException(object value) : Exception 67 | { 68 | public object Value { get; } = value; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /MoreLinq.Test/Async/TestExtensions.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2020 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test.Async 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Runtime.CompilerServices; 23 | using System.Threading; 24 | using System.Threading.Tasks; 25 | 26 | static partial class TestExtensions 27 | { 28 | public static IAsyncEnumerable Yield(this IAsyncEnumerable source) => 29 | Yield(source, _ => true); 30 | 31 | public static IAsyncEnumerable 32 | Yield(this IAsyncEnumerable source, 33 | Func predicate) => 34 | Yield(source, shouldEndSynchronously: false, predicate); 35 | 36 | public static IAsyncEnumerable 37 | Yield(this IAsyncEnumerable source, 38 | bool shouldEndSynchronously, 39 | Func predicate) 40 | { 41 | if (source is null) throw new ArgumentNullException(nameof(source)); 42 | if (predicate is null) throw new ArgumentNullException(nameof(predicate)); 43 | 44 | return Async(); 45 | 46 | async IAsyncEnumerable Async([EnumeratorCancellation]CancellationToken cancellationToken = default) 47 | { 48 | await foreach (var item in source.WithCancellation(cancellationToken)) 49 | { 50 | if (predicate(item)) 51 | await Task.Yield(); 52 | yield return item; 53 | } 54 | 55 | if (!shouldEndSynchronously) 56 | await Task.Yield(); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq.Test/Async/WatchableEnumerator.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2021 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test.Async 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Threading.Tasks; 23 | 24 | partial class TestExtensions 25 | { 26 | public static WatchableEnumerator AsWatchable(this IAsyncEnumerator source) => new(source); 27 | } 28 | 29 | sealed class WatchableEnumerator(IAsyncEnumerator source) : 30 | IAsyncEnumerator 31 | { 32 | readonly IAsyncEnumerator source = source ?? throw new ArgumentNullException(nameof(source)); 33 | 34 | public event EventHandler? Disposed; 35 | public event EventHandler? MoveNextCalled; 36 | 37 | public T Current => this.source.Current; 38 | 39 | public async ValueTask MoveNextAsync() 40 | { 41 | var moved = await this.source.MoveNextAsync(); 42 | MoveNextCalled?.Invoke(this, moved); 43 | return moved; 44 | } 45 | 46 | public async ValueTask DisposeAsync() 47 | { 48 | await this.source.DisposeAsync(); 49 | Disposed?.Invoke(this, EventArgs.Empty); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /MoreLinq.Test/AtLeastTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2015 "sholland". All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | using System.Collections.Generic; 22 | 23 | [TestFixture] 24 | public class AtLeastTest 25 | { 26 | [Test] 27 | public void AtLeastWithNegativeCount() 28 | { 29 | Assert.That(() => new[] { 1 }.AtLeast(-1), 30 | Throws.ArgumentOutOfRangeException("count")); 31 | } 32 | 33 | public static IEnumerable AtLeastSource => 34 | from k in SourceKinds.Sequence.Concat(SourceKinds.Collection) 35 | from e in new[] 36 | { 37 | (Size: 0, Count: 0), 38 | (Size: 0, Count: 1), 39 | (Size: 0, Count: 2), 40 | (Size: 1, Count: 0), 41 | (Size: 1, Count: 1), 42 | (Size: 1, Count: 2), 43 | (Size: 3, Count: 0), 44 | (Size: 3, Count: 1), 45 | (Size: 3, Count: 2) 46 | } 47 | select new TestCaseData(k, e.Size, e.Count) 48 | .Returns(e.Size >= e.Count) 49 | .SetName($"{{m}}({k}[{e.Size}], {e.Count})"); 50 | 51 | [TestCaseSource(nameof(AtLeastSource))] 52 | public bool AtLeast(SourceKind sourceKind, int sequenceSize, int atLeastAssertCount) => 53 | Enumerable.Range(0, sequenceSize).ToSourceKind(sourceKind).AtLeast(atLeastAssertCount); 54 | 55 | [Test] 56 | public void AtLeastDoesNotIterateUnnecessaryElements() 57 | { 58 | var source = MoreEnumerable.From(() => 1, 59 | () => 2, 60 | () => throw new TestException()); 61 | Assert.That(source.AtLeast(2), Is.True); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MoreLinq.Test/AtMostTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | using System.Collections.Generic; 22 | 23 | [TestFixture] 24 | public class AtMostTest 25 | { 26 | [Test] 27 | public void AtMostWithNegativeCount() 28 | { 29 | Assert.That(() => new[] { 1 }.AtMost(-1), 30 | Throws.ArgumentOutOfRangeException("count")); 31 | } 32 | 33 | public static IEnumerable AtMostSource => 34 | from k in SourceKinds.Sequence.Concat(SourceKinds.Collection) 35 | from e in new[] 36 | { 37 | (Size: 0, Count: 0), 38 | (Size: 0, Count: 1), 39 | (Size: 1, Count: 0), 40 | (Size: 1, Count: 1), 41 | (Size: 1, Count: 2), 42 | (Size: 3, Count: 1) 43 | } 44 | select new TestCaseData(k, e.Size, e.Count) 45 | .Returns(e.Size <= e.Count) 46 | .SetName($"{{m}}({k}[{e.Size}], {e.Count})"); 47 | 48 | [TestCaseSource(nameof(AtMostSource))] 49 | public bool AtMost(SourceKind sourceKind, int sequenceSize, int atMostAssertCount) => 50 | Enumerable.Range(0, sequenceSize).ToSourceKind(sourceKind).AtMost(atMostAssertCount); 51 | 52 | [Test] 53 | public void AtMostDoesNotIterateUnnecessaryElements() 54 | { 55 | var source = MoreEnumerable.From(() => 1, 56 | () => 2, 57 | () => 3, 58 | () => throw new TestException()); 59 | Assert.That(source.AtMost(2), Is.False); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /MoreLinq.Test/BacksertTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class BacksertTest 25 | { 26 | [Test] 27 | public void BacksertIsLazy() 28 | { 29 | _ = new BreakingSequence().Backsert(new BreakingSequence(), 0); 30 | } 31 | 32 | [Test] 33 | public void BacksertWithNegativeIndex() 34 | { 35 | Assert.That(() => Enumerable.Range(1, 10).Backsert([97, 98, 99], -1), 36 | Throws.ArgumentOutOfRangeException("index")); 37 | } 38 | 39 | [TestCase(new[] { 1, 2, 3 }, 4, new[] { 9 })] 40 | public void BacksertWithIndexGreaterThanSourceLength(int[] seq1, int index, int[] seq2) 41 | { 42 | using var test1 = seq1.AsTestingSequence(); 43 | using var test2 = seq2.AsTestingSequence(); 44 | 45 | var result = test1.Backsert(test2, index); 46 | 47 | Assert.That(() => result.ElementAt(0), 48 | Throws.ArgumentOutOfRangeException()); 49 | } 50 | 51 | [TestCase(new[] { 1, 2, 3 }, 0, new[] { 8, 9 }, ExpectedResult = new[] { 1, 2, 3, 8, 9 })] 52 | [TestCase(new[] { 1, 2, 3 }, 1, new[] { 8, 9 }, ExpectedResult = new[] { 1, 2, 8, 9, 3 })] 53 | [TestCase(new[] { 1, 2, 3 }, 2, new[] { 8, 9 }, ExpectedResult = new[] { 1, 8, 9, 2, 3 })] 54 | [TestCase(new[] { 1, 2, 3 }, 3, new[] { 8, 9 }, ExpectedResult = new[] { 8, 9, 1, 2, 3 })] 55 | public IEnumerable Backsert(int[] seq1, int index, int[] seq2) 56 | { 57 | using var test1 = seq1.AsTestingSequence(); 58 | using var test2 = seq2.AsTestingSequence(); 59 | 60 | return [..test1.Backsert(test2, index)]; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingAction.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | 22 | /// 23 | /// Actions which throw NotImplementedException if they're ever called. 24 | /// 25 | static class BreakingAction 26 | { 27 | internal static Action WithoutArguments => 28 | () => throw new NotImplementedException(); 29 | 30 | internal static Action Of() => 31 | _ => throw new NotImplementedException(); 32 | 33 | internal static Action Of() => 34 | (_, _) => throw new NotImplementedException(); 35 | 36 | internal static Action Of() => 37 | (_, _, _) => throw new NotImplementedException(); 38 | 39 | internal static Action Of() => 40 | (_, _, _, _) => throw new NotImplementedException(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingCollection.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Jonas Nyrup. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | class BreakingCollection(IList list) : 24 | BreakingSequence, ICollection 25 | { 26 | public BreakingCollection(params T[] values) : this((IList)values) { } 27 | 28 | protected IList List { get; } = list; 29 | 30 | public int Count => List.Count; 31 | 32 | public void Add(T item) => throw new NotImplementedException(); 33 | public void Clear() => throw new NotImplementedException(); 34 | public bool Contains(T item) => List.Contains(item); 35 | public void CopyTo(T[] array, int arrayIndex) => List.CopyTo(array, arrayIndex); 36 | public bool Remove(T item) => throw new NotImplementedException(); 37 | public bool IsReadOnly => true; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingFunc.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | 22 | /// 23 | /// Functions which throw NotImplementedException if they're ever called. 24 | /// 25 | static class BreakingFunc 26 | { 27 | internal static Func Of() => 28 | () => throw new NotImplementedException(); 29 | 30 | internal static Func Of() => 31 | _ => throw new NotImplementedException(); 32 | 33 | internal static Func Of() => 34 | (_, _) => throw new NotImplementedException(); 35 | 36 | internal static Func Of() => 37 | (_, _, _) => throw new NotImplementedException(); 38 | 39 | internal static Func Of() => 40 | (_, _, _, _) => throw new NotImplementedException(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingList.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Avi Levin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections; 22 | using System.Collections.Generic; 23 | 24 | /// 25 | /// This class implement but specifically prohibits enumeration using GetEnumerator(). 26 | /// It is provided to assist in testing extension methods that MUST NOT call the GetEnumerator() 27 | /// method of - either because they should be using the indexer or because they are 28 | /// expected to be lazily evaluated. 29 | /// 30 | 31 | sealed class BreakingList(List list) : 32 | BreakingCollection(list), 33 | IList 34 | { 35 | public BreakingList() : this([]) { } 36 | 37 | public int IndexOf(T item) => List.IndexOf(item); 38 | public void Insert(int index, T item) => throw new NotImplementedException(); 39 | public void RemoveAt(int index) => throw new NotImplementedException(); 40 | 41 | public T this[int index] 42 | { 43 | get => List[index]; 44 | set => throw new NotImplementedException(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingReadOnlyCollection.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Leandro F. Vieira. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | 22 | class BreakingReadOnlyCollection(IReadOnlyCollection collection) : 23 | BreakingSequence, IReadOnlyCollection 24 | { 25 | readonly IReadOnlyCollection collection = collection; 26 | 27 | public BreakingReadOnlyCollection(params T[] values) : this((IReadOnlyCollection)values) { } 28 | 29 | public int Count => this.collection.Count; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingReadOnlyList.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Avi Levin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections; 21 | using System.Collections.Generic; 22 | 23 | /// 24 | /// This class implement but specifically prohibits enumeration using GetEnumerator(). 25 | /// It is provided to assist in testing extension methods that MUST NOT call the GetEnumerator() 26 | /// method of - either because they should be using the indexer or because they are 27 | /// expected to be lazily evaluated. 28 | /// 29 | 30 | sealed class BreakingReadOnlyList(IReadOnlyList list) : 31 | BreakingReadOnlyCollection(list), 32 | IReadOnlyList 33 | { 34 | readonly IReadOnlyList list = list; 35 | 36 | public BreakingReadOnlyList(params T[] values) : this((IReadOnlyList)values) { } 37 | 38 | public T this[int index] => this.list[index]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingSequence.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections; 22 | using System.Collections.Generic; 23 | 24 | /// 25 | /// Enumerable sequence which throws InvalidOperationException as soon as its 26 | /// enumerator is requested. Used to check lazy evaluation. 27 | /// 28 | class BreakingSequence : IEnumerable 29 | { 30 | public IEnumerator GetEnumerator() => throw new BreakException(); 31 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 32 | } 33 | 34 | sealed class BreakException : Exception 35 | { 36 | public BreakException() { } 37 | public BreakException(string message) : base(message) { } 38 | public BreakException(string message, Exception inner) : base(message, inner) { } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /MoreLinq.Test/ChooseTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Globalization; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class ChooseTest 25 | { 26 | [Test] 27 | public void IsLazy() 28 | { 29 | _ = new BreakingSequence().Choose(BreakingFunc.Of()); 30 | } 31 | 32 | [Test] 33 | public void WithEmptySource() 34 | { 35 | using var xs = Enumerable.Empty().AsTestingSequence(); 36 | Assert.That(xs.Choose(BreakingFunc.Of()), Is.Empty); 37 | } 38 | 39 | [Test] 40 | public void None() 41 | { 42 | using var xs = Enumerable.Range(1, 10).AsTestingSequence(); 43 | Assert.That(xs.Choose(_ => (false, 0)), Is.Empty); 44 | } 45 | 46 | [Test] 47 | public void ThoseParsable() 48 | { 49 | using var xs = 50 | "O,l,2,3,4,S,6,7,B,9" 51 | .Split(',') 52 | .Choose(s => (int.TryParse(s, NumberStyles.Integer, 53 | CultureInfo.InvariantCulture, 54 | out var n), n)) 55 | .AsTestingSequence(); 56 | 57 | xs.AssertSequenceEqual(2, 3, 4, 6, 7, 9); 58 | } 59 | 60 | // A cheap trick to masquerade a tuple as an option 61 | 62 | static class Option 63 | { 64 | public static (bool IsSome, T Value) Some(T value) => (true, value); 65 | } 66 | 67 | static class Option 68 | { 69 | #pragma warning disable CA1805 // Do not initialize unnecessarily (avoids CS0649) 70 | public static readonly (bool IsSome, T Value) None = default; 71 | #pragma warning restore CA1805 // Do not initialize unnecessarily 72 | } 73 | 74 | [Test] 75 | public void ThoseThatAreIntegers() 76 | { 77 | new int?[] { 0, 1, 2, null, 4, null, 6, null, null, 9 } 78 | .Choose(e => e is { } n ? Option.Some(n) : Option.None) 79 | .AssertSequenceEqual(0, 1, 2, 4, 6, 9); 80 | } 81 | 82 | [Test] 83 | public void ThoseEven() 84 | { 85 | Enumerable.Range(1, 10) 86 | .Choose(x => x % 2 is 0 ? Option.Some(x) : Option.None) 87 | .AssertSequenceEqual(2, 4, 6, 8, 10); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /MoreLinq.Test/Combinatorics.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2010 Leopold Bushkin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | static class Combinatorics 21 | { 22 | public static double Factorial(int n) 23 | { 24 | var fac = 1.0d; 25 | while (n > 0) 26 | fac *= n--; 27 | return fac; 28 | } 29 | 30 | public static double Binomial(int n, int k) => 31 | Factorial(n) / (Factorial(n - k) * Factorial(k)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /MoreLinq.Test/Comparable.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2020 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static class Comparable where T : IComparable 24 | { 25 | public static readonly IComparer DescendingOrderComparer = 26 | Comparer.Create((x, y) => -Math.Sign(x.CompareTo(y))); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /MoreLinq.Test/ConsumeTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class ConsumeTest 24 | { 25 | [Test] 26 | public void ConsumeReallyConsumes() 27 | { 28 | var counter = 0; 29 | var sequence = Enumerable.Range(0, 10).Pipe(_ => counter++); 30 | sequence.Consume(); 31 | Assert.That(counter, Is.EqualTo(10)); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /MoreLinq.Test/CountBetweenTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | using System.Collections.Generic; 22 | 23 | [TestFixture] 24 | public class CountBetweenTest 25 | { 26 | [Test] 27 | public void CountBetweenWithNegativeMin() 28 | { 29 | Assert.That(() => new[] { 1 }.CountBetween(-1, 0), 30 | Throws.ArgumentOutOfRangeException("min")); 31 | } 32 | 33 | [Test] 34 | public void CountBetweenWithNegativeMax() 35 | { 36 | Assert.That(() => new[] { 1 }.CountBetween(0, -1), 37 | Throws.ArgumentOutOfRangeException("max")); 38 | } 39 | 40 | [Test] 41 | public void CountBetweenWithMaxLesserThanMin() 42 | { 43 | Assert.That(() => new[] { 1 }.CountBetween(1, 0), 44 | Throws.ArgumentOutOfRangeException("max")); 45 | } 46 | 47 | static IEnumerable CountBetweenSource => 48 | from args in new[] 49 | { 50 | (Count: 1, Min: 1, Max: 1), 51 | (Count: 1, Min: 2, Max: 4), 52 | (Count: 2, Min: 2, Max: 4), 53 | (Count: 3, Min: 2, Max: 4), 54 | (Count: 4, Min: 2, Max: 4), 55 | (Count: 5, Min: 2, Max: 4), 56 | } 57 | from type in SourceKinds.Sequence.Concat(SourceKinds.Collection) 58 | select new TestCaseData(type, args.Count, args.Min, args.Max) 59 | .Returns(args.Count >= args.Min && args.Count <= args.Max) 60 | .SetName($"{{m}}({type}[{args.Count}], {args.Min}, {args.Max})"); 61 | 62 | [TestCaseSource(nameof(CountBetweenSource))] 63 | public bool CountBetween(SourceKind sourceKind, int count, int min, int max) 64 | { 65 | return Enumerable.Range(0, count).ToSourceKind(sourceKind).CountBetween(min, max); 66 | } 67 | 68 | [Test] 69 | public void CountBetweenDoesNotIterateUnnecessaryElements() 70 | { 71 | var source = MoreEnumerable.From(() => 1, 72 | () => 2, 73 | () => 3, 74 | () => 4, 75 | () => throw new TestException()); 76 | Assert.That(source.CountBetween(2, 3), Is.False); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /MoreLinq.Test/CurrentThreadCultureScope.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Globalization; 21 | 22 | sealed class CurrentThreadCultureScope : Scope 23 | { 24 | public CurrentThreadCultureScope(CultureInfo @new) : 25 | base(CultureInfo.CurrentCulture) => Install(@new); 26 | 27 | protected override void Restore(CultureInfo old) => Install(old); 28 | static void Install(CultureInfo value) => CultureInfo.CurrentCulture = value; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /MoreLinq.Test/DistinctByTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | using static MoreLinq.Extensions.DistinctByExtension; 23 | 24 | [TestFixture] 25 | public class DistinctByTest 26 | { 27 | [Test] 28 | public void DistinctBy() 29 | { 30 | string[] source = ["first", "second", "third", "fourth", "fifth"]; 31 | var distinct = source.DistinctBy(word => word.Length); 32 | distinct.AssertSequenceEqual("first", "second"); 33 | } 34 | 35 | [Test] 36 | public void DistinctByIsLazy() 37 | { 38 | _ = new BreakingSequence().DistinctBy(BreakingFunc.Of()); 39 | } 40 | 41 | [Test] 42 | public void DistinctByWithComparer() 43 | { 44 | string[] source = ["first", "FIRST", "second", "second", "third"]; 45 | var distinct = source.DistinctBy(word => word, StringComparer.OrdinalIgnoreCase); 46 | distinct.AssertSequenceEqual("first", "second", "third"); 47 | } 48 | 49 | [Test] 50 | public void DistinctByNullComparer() 51 | { 52 | string[] source = ["first", "second", "third", "fourth", "fifth"]; 53 | var distinct = source.DistinctBy(word => word.Length, null); 54 | distinct.AssertSequenceEqual("first", "second"); 55 | } 56 | 57 | [Test] 58 | public void DistinctByIsLazyWithComparer() 59 | { 60 | var bs = new BreakingSequence(); 61 | _ = bs.DistinctBy(BreakingFunc.Of(), StringComparer.Ordinal); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MoreLinq.Test/EqualityComparer.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | #if !NET8_0_OR_GREATER 19 | 20 | namespace MoreLinq.Test 21 | { 22 | using System; 23 | using System.Collections.Generic; 24 | 25 | static class EqualityComparer 26 | { 27 | public static System.Collections.Generic.EqualityComparer 28 | Default => System.Collections.Generic.EqualityComparer.Default; 29 | 30 | /// 31 | /// Creates an given a 32 | /// . 33 | /// 34 | 35 | public static IEqualityComparer Create(Func comparer) => 36 | new DelegatingComparer(comparer); 37 | 38 | sealed class DelegatingComparer : IEqualityComparer 39 | { 40 | readonly Func comparer; 41 | readonly Func hasher; 42 | 43 | public DelegatingComparer(Func comparer) 44 | : this(comparer, x => x == null ? 0 : x.GetHashCode()) { } 45 | 46 | DelegatingComparer(Func comparer, Func hasher) 47 | { 48 | this.comparer = comparer ?? throw new ArgumentNullException(nameof(comparer)); 49 | this.hasher = hasher ?? throw new ArgumentNullException(nameof(hasher)); 50 | } 51 | 52 | public bool Equals(T? x, T? y) => this.comparer(x, y); 53 | public int GetHashCode(T obj) => this.hasher(obj); 54 | } 55 | } 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /MoreLinq.Test/EvaluateTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Felipe Sateler. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | public class EvaluateTest 24 | { 25 | [Test] 26 | public void TestEvaluateIsLazy() 27 | { 28 | _ = new BreakingSequence>().Evaluate(); 29 | } 30 | 31 | [Test] 32 | public void TestEvaluateInvokesMethods() 33 | { 34 | var factories = new Func[] 35 | { 36 | () => -2, 37 | () => 4, 38 | () => int.MaxValue, 39 | () => int.MinValue, 40 | }; 41 | var results = factories.Evaluate(); 42 | 43 | results.AssertSequenceEqual(-2, 4, int.MaxValue, int.MinValue); 44 | } 45 | 46 | [Test] 47 | public void TestEvaluateInvokesMethodsMultipleTimes() 48 | { 49 | var evals = 0; 50 | var factories = new Func[] 51 | { 52 | () => { evals++; return -2; }, 53 | }; 54 | var results = factories.Evaluate(); 55 | 56 | results.Consume(); 57 | results.Consume(); 58 | results.Consume(); 59 | 60 | Assert.That(evals, Is.EqualTo(3)); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MoreLinq.Test/ExactlyTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | using System.Collections.Generic; 22 | 23 | [TestFixture] 24 | public class ExactlyTest 25 | { 26 | [Test] 27 | public void ExactlyWithNegativeCount() 28 | { 29 | Assert.That(() => new[] { 1 }.Exactly(-1), 30 | Throws.ArgumentOutOfRangeException("count")); 31 | } 32 | 33 | static IEnumerable ExactlySource => 34 | from k in SourceKinds.Sequence.Concat(SourceKinds.Collection) 35 | from e in new[] 36 | { 37 | (Size: 0, Count: 0), 38 | (Size: 0, Count: 1), 39 | (Size: 1, Count: 1), 40 | (Size: 3, Count: 1) 41 | } 42 | select new TestCaseData(k, e.Size, e.Count) 43 | .Returns(e.Size == e.Count) 44 | .SetName($"{{m}}({k}[{e.Size}], {e.Count})"); 45 | 46 | [TestCaseSource(nameof(ExactlySource))] 47 | public bool Exactly(SourceKind sourceKind, int sequenceSize, int exactlyAssertCount) => 48 | Enumerable.Range(0, sequenceSize).ToSourceKind(sourceKind).Exactly(exactlyAssertCount); 49 | 50 | 51 | [Test] 52 | public void ExactlyDoesNotIterateUnnecessaryElements() 53 | { 54 | var source = MoreEnumerable.From(() => 1, 55 | () => 2, 56 | () => 3, 57 | () => throw new TestException()); 58 | Assert.That(source.Exactly(2), Is.False); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /MoreLinq.Test/ExceptByTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class ExceptByTest 25 | { 26 | [Test] 27 | public void SimpleExceptBy() 28 | { 29 | string[] first = ["aaa", "bb", "c", "dddd"]; 30 | string[] second = ["xx", "y"]; 31 | var result = first.ExceptBy(second, x => x.Length); 32 | result.AssertSequenceEqual("aaa", "dddd"); 33 | } 34 | 35 | [Test] 36 | public void ExceptByIsLazy() 37 | { 38 | var bs = new BreakingSequence(); 39 | _ = bs.ExceptBy(bs, BreakingFunc.Of()); 40 | } 41 | 42 | [Test] 43 | public void ExceptByDoesNotRepeatSourceElementsWithDuplicateKeys() 44 | { 45 | string[] first = ["aaa", "bb", "c", "a", "b", "c", "dddd"]; 46 | string[] second = ["xx"]; 47 | var result = first.ExceptBy(second, x => x.Length); 48 | result.AssertSequenceEqual("aaa", "c", "dddd"); 49 | } 50 | 51 | [Test] 52 | public void ExceptByWithComparer() 53 | { 54 | string[] first = ["first", "second", "third", "fourth"]; 55 | string[] second = ["FIRST", "thiRD", "FIFTH"]; 56 | var result = first.ExceptBy(second, word => word, StringComparer.OrdinalIgnoreCase); 57 | result.AssertSequenceEqual("second", "fourth"); 58 | } 59 | 60 | [Test] 61 | public void ExceptByNullComparer() 62 | { 63 | string[] first = ["aaa", "bb", "c", "dddd"]; 64 | string[] second = ["xx", "y"]; 65 | var result = first.ExceptBy(second, x => x.Length, null); 66 | result.AssertSequenceEqual("aaa", "dddd"); 67 | } 68 | 69 | [Test] 70 | public void ExceptByIsLazyWithComparer() 71 | { 72 | var bs = new BreakingSequence(); 73 | _ = bs.ExceptBy(bs, BreakingFunc.Of(), StringComparer.Ordinal); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /MoreLinq.Test/Extensions.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Diagnostics; 22 | using System.Globalization; 23 | 24 | static class Extensions 25 | { 26 | /// 27 | /// Formats the value of this object using the invariant culture. 28 | /// 29 | 30 | [DebuggerStepThrough] 31 | public static string ToInvariantString(this T formattable) where T : IFormattable => 32 | formattable.ToInvariantString(null); 33 | 34 | /// 35 | /// Formats the value of this object using a specific format and the 36 | /// invariant culture. 37 | /// 38 | 39 | [DebuggerStepThrough] 40 | public static string ToInvariantString(this T formattable, string? format) where T : IFormattable 41 | { 42 | if (formattable is null) throw new ArgumentNullException(nameof(formattable)); 43 | return formattable.ToString(format, CultureInfo.InvariantCulture); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /MoreLinq.Test/FallbackIfEmptyTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2016 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class FallbackIfEmptyTest 25 | { 26 | [Test] 27 | public void FallbackIfEmptyWithEmptySequence() 28 | { 29 | var source = Enumerable.Empty().Select(x => x); 30 | // ReSharper disable PossibleMultipleEnumeration 31 | source.FallbackIfEmpty(12).AssertSequenceEqual(12); 32 | source.FallbackIfEmpty(12, 23).AssertSequenceEqual(12, 23); 33 | source.FallbackIfEmpty(12, 23, 34).AssertSequenceEqual(12, 23, 34); 34 | source.FallbackIfEmpty(12, 23, 34, 45).AssertSequenceEqual(12, 23, 34, 45); 35 | source.FallbackIfEmpty(12, 23, 34, 45, 56).AssertSequenceEqual(12, 23, 34, 45, 56); 36 | source.FallbackIfEmpty(12, 23, 34, 45, 56, 67).AssertSequenceEqual(12, 23, 34, 45, 56, 67); 37 | // ReSharper restore PossibleMultipleEnumeration 38 | } 39 | 40 | [Test] 41 | public void FallbackIfEmptyWithEmptyNullableSequence() 42 | { 43 | var source = Enumerable.Empty().Select(x => x); 44 | var fallback = (int?)null; 45 | source.FallbackIfEmpty(fallback).AssertSequenceEqual(fallback); 46 | } 47 | 48 | [Test] 49 | public void FallbackUsesCollectionCountAtIterationTime() 50 | { 51 | var source = new List(); 52 | 53 | var results = new[] 54 | { 55 | source.FallbackIfEmpty(-1), 56 | source.FallbackIfEmpty(-1, -2), 57 | source.FallbackIfEmpty(-1, -2, -3), 58 | source.FallbackIfEmpty(-1, -2, -3, -4), 59 | source.FallbackIfEmpty(-1, -2, -3, -4, -5), 60 | }; 61 | 62 | source.Add(123); 63 | 64 | foreach (var result in results) 65 | result.AssertSequenceEqual(123); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /MoreLinq.Test/FillBackwardTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class FillBackwardTest 24 | { 25 | [Test] 26 | public void FillBackwardIsLazy() 27 | { 28 | _ = new BreakingSequence().FillBackward(); 29 | } 30 | 31 | [Test] 32 | public void FillBackward() 33 | { 34 | int? na = null; 35 | var input = new[] { na, na, 1, 2, na, na, na, 3, 4, na, na }; 36 | var result = input.FillBackward(); 37 | Assert.That(result, Is.EqualTo(new[] { 1, 1, 1, 2, 3, 3, 3, 3, 4, na, na })); 38 | } 39 | 40 | [Test] 41 | public void FillBackwardWithFillSelector() 42 | { 43 | var xs = new[] { 0, 0, 1, 2, 0, 0, 0, 3, 4, 0, 0 }; 44 | 45 | var result = 46 | xs.Select(x => new { X = x, Y = x }) 47 | .FillBackward(e => e.X == 0, (m, nm) => new { m.X, nm.Y }); 48 | 49 | Assert.That(result, Is.EqualTo(new[] 50 | { 51 | new { X = 0, Y = 1 }, 52 | new { X = 0, Y = 1 }, 53 | new { X = 1, Y = 1 }, 54 | new { X = 2, Y = 2 }, 55 | new { X = 0, Y = 3 }, 56 | new { X = 0, Y = 3 }, 57 | new { X = 0, Y = 3 }, 58 | new { X = 3, Y = 3 }, 59 | new { X = 4, Y = 4 }, 60 | new { X = 0, Y = 0 }, 61 | new { X = 0, Y = 0 }, 62 | })); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /MoreLinq.Test/ForEachTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class ForEachTest 25 | { 26 | [Test] 27 | public void ForEachWithSequence() 28 | { 29 | var results = new List(); 30 | new[] { 1, 2, 3 }.ForEach(results.Add); 31 | results.AssertSequenceEqual(1, 2, 3); 32 | } 33 | 34 | [Test] 35 | public void ForEachIndexedWithSequence() 36 | { 37 | var valueResults = new List(); 38 | var indexResults = new List(); 39 | new[] { 9, 7, 8 }.ForEach((x, index) => { valueResults.Add(x); indexResults.Add(index); }); 40 | valueResults.AssertSequenceEqual(9, 7, 8); 41 | indexResults.AssertSequenceEqual(0, 1, 2); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /MoreLinq.Test/FuncModule.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2020 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | 22 | // This type is designed to be imported statically. 23 | // 24 | // Its members enable replacing explicit instantiations of `Func<...>`, 25 | // as in: 26 | // 27 | // new Func((a, b) => a + b) 28 | // 29 | // with the shorter version: 30 | // 31 | // Func((string a, object b) => a + b) 32 | // 33 | // The `new` is no longer required and the return type can be omitted 34 | // as it can be inferred through the type of the lambda expression. 35 | 36 | static class FuncModule 37 | { 38 | public static Func Func(Func f) => f; 39 | public static Func Func(Func f) => f; 40 | public static Func Func(Func f) => f; 41 | public static Func Func(Func f) => f; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /MoreLinq.Test/GenerateTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class GenerateTest 24 | { 25 | [Test] 26 | public void GenerateTerminatesWhenCheckReturnsFalse() 27 | { 28 | var result = MoreEnumerable.Generate(1, n => n + 2).TakeWhile(n => n < 10); 29 | 30 | result.AssertSequenceEqual(1, 3, 5, 7, 9); 31 | } 32 | 33 | [Test] 34 | public void GenerateProcessesNonNumerics() 35 | { 36 | var result = MoreEnumerable.Generate("", s => s + 'a').TakeWhile(s => s.Length < 5); 37 | 38 | result.AssertSequenceEqual("", "a", "aa", "aaa", "aaaa"); 39 | } 40 | 41 | [Test] 42 | public void GenerateIsLazy() 43 | { 44 | _ = MoreEnumerable.Generate(0, BreakingFunc.Of()); 45 | } 46 | 47 | [Test] 48 | public void GenerateFuncIsNotInvokedUnnecessarily() 49 | { 50 | MoreEnumerable.Generate(0, BreakingFunc.Of()) 51 | .Take(1) 52 | .Consume(); 53 | } 54 | 55 | [Test] 56 | public void GenerateByIndexIsLazy() 57 | { 58 | _ = MoreEnumerable.GenerateByIndex(BreakingFunc.Of()); 59 | } 60 | 61 | [Test] 62 | public void GenerateByIndex() 63 | { 64 | var sequence = MoreEnumerable.GenerateByIndex(x => x.ToInvariantString()).Take(3); 65 | sequence.AssertSequenceEqual("0", "1", "2"); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /MoreLinq.Test/IndexTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class IndexTest 24 | { 25 | [Test] 26 | public void IndexIsLazy() 27 | { 28 | var bs = new BreakingSequence(); 29 | _ = bs.Index(); 30 | _ = bs.Index(0); 31 | } 32 | 33 | [Test] 34 | public void IndexSequence() 35 | { 36 | const string one = "one"; 37 | const string two = "two"; 38 | const string three = "three"; 39 | var result = new[] { one, two, three }.Index(); 40 | result.AssertSequenceEqual( 41 | KeyValuePair.Create(0, one), 42 | KeyValuePair.Create(1, two), 43 | KeyValuePair.Create(2, three)); 44 | } 45 | 46 | [Test] 47 | public void IndexSequenceStartIndex() 48 | { 49 | const string one = "one"; 50 | const string two = "two"; 51 | const string three = "three"; 52 | var result = new[] { one, two, three }.Index(10); 53 | result.AssertSequenceEqual( 54 | KeyValuePair.Create(10, one), 55 | KeyValuePair.Create(11, two), 56 | KeyValuePair.Create(12, three)); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /MoreLinq.Test/KeyValuePair.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | 22 | static class KeyValuePair 23 | { 24 | public static KeyValuePair Create(TKey key, TValue value) => new(key, value); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MoreLinq.Test/Make.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | global using static MoreLinq.Test.Make; 19 | 20 | namespace MoreLinq.Test 21 | { 22 | using System.Collections.Generic; 23 | 24 | static class Make 25 | { 26 | public static IEnumerable Seq(params T[] values) => 27 | from value in values 28 | select value; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /MoreLinq.Test/MoreLinq.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | MoreLinq.Test 5 | net9.0;net8.0;net471 6 | portable 7 | MoreLinq.Test 8 | Exe 9 | true 10 | false 11 | 12 | 618 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | runtime; build; native; contentfiles; analyzers; buildtransitive 22 | all 23 | 24 | 25 | 26 | runtime; build; native; contentfiles; analyzers 27 | all 28 | 29 | 30 | 31 | all 32 | runtime; build; native; contentfiles; analyzers; buildtransitive 33 | 34 | 35 | 36 | all 37 | runtime; build; native; contentfiles; analyzers; buildtransitive 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /MoreLinq.Test/OrderedMergeTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2019 Pierre Lando. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class OrderedMergeTest 25 | { 26 | public static readonly IEnumerable TestData = 27 | from e in new[] 28 | { 29 | new 30 | { 31 | A = Seq(0, 2, 4), 32 | B = Seq(0, 1, 2, 3, 4), 33 | R = Seq(0, 1, 2, 3, 4) 34 | }, 35 | new 36 | { 37 | A = Seq(0, 1, 2, 3, 4), 38 | B = Seq(0, 2, 4), 39 | R = Seq(0, 1, 2, 3, 4) 40 | }, 41 | new 42 | { 43 | A = Seq(0, 2, 4), 44 | B = Seq(1, 3, 5), 45 | R = Seq(0, 1, 2, 3, 4, 5) 46 | }, 47 | new 48 | { 49 | A = Seq(), 50 | B = Seq(0, 1, 2), 51 | R = Seq(0, 1, 2) 52 | }, 53 | new 54 | { 55 | A = Seq(0, 1, 2), 56 | B = Seq(), 57 | R = Seq(0, 1, 2) 58 | } 59 | } 60 | select new TestCaseData(e.A.AsTestingSequence(), e.B.AsTestingSequence()).Returns(e.R); 61 | 62 | [Test, TestCaseSource(nameof(TestData))] 63 | public IEnumerable OrderedMerge(IEnumerable first, 64 | IEnumerable second) 65 | { 66 | return first.OrderedMerge(second); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /MoreLinq.Test/PairwiseTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class PairwiseTest 24 | { 25 | [Test] 26 | public void PairwiseIsLazy() 27 | { 28 | _ = new BreakingSequence().Pairwise(BreakingFunc.Of()); 29 | } 30 | 31 | [TestCase(0)] 32 | [TestCase(1)] 33 | public void PairwiseWithSequenceShorterThanTwo(int count) 34 | { 35 | var source = Enumerable.Range(0, count); 36 | var result = source.Pairwise(BreakingFunc.Of()); 37 | 38 | Assert.That(result, Is.Empty); 39 | } 40 | 41 | [Test] 42 | public void PairwiseWideSourceSequence() 43 | { 44 | using var source = new[] { "a", "b", "c", "d" }.AsTestingSequence(); 45 | var result = source.Pairwise((x, y) => x + y); 46 | result.AssertSequenceEqual("ab", "bc", "cd"); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /MoreLinq.Test/PipeTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using System.Text; 22 | using NUnit.Framework; 23 | 24 | [TestFixture] 25 | public class PipeTest 26 | { 27 | [Test] 28 | public void PipeWithSequence() 29 | { 30 | var results = new List(); 31 | var returned = new[] { 1, 2, 3 }.Pipe(results.Add); 32 | // Lazy - nothing has executed yet 33 | Assert.That(results, Is.Empty); 34 | returned.AssertSequenceEqual(1, 2, 3); 35 | // Now it has... 36 | results.AssertSequenceEqual(1, 2, 3); 37 | } 38 | 39 | [Test] 40 | public void PipeIsLazy() 41 | { 42 | _ = new BreakingSequence().Pipe(BreakingAction.Of()); 43 | } 44 | 45 | [Test] 46 | public void PipeActionOccursBeforeYield() 47 | { 48 | var source = new[] { new StringBuilder(), new StringBuilder() }; 49 | // The action will occur "in" the pipe, so by the time Where gets it, the 50 | // sequence will be empty. 51 | Assert.That(source.Pipe(sb => sb.Append('x')) 52 | .Where(x => x.Length == 0), 53 | Is.Empty); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /MoreLinq.Test/PreScanTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class PreScanTest 24 | { 25 | [Test] 26 | public void PreScanIsLazy() 27 | { 28 | _ = new BreakingSequence().PreScan(BreakingFunc.Of(), 0); 29 | } 30 | 31 | [Test] 32 | public void PreScanWithEmptySequence() 33 | { 34 | var source = Enumerable.Empty(); 35 | var result = source.PreScan(BreakingFunc.Of(), 0); 36 | 37 | Assert.That(result, Is.Empty); 38 | } 39 | 40 | [Test] 41 | public void PreScanWithSingleElement() 42 | { 43 | var source = new[] { 111 }; 44 | var result = source.PreScan(BreakingFunc.Of(), 999); 45 | result.AssertSequenceEqual(999); 46 | } 47 | 48 | [Test] 49 | public void PreScanSum() 50 | { 51 | var result = SampleData.Values.PreScan(SampleData.Plus, 0); 52 | result.AssertSequenceEqual(0, 1, 3, 6, 10, 15, 21, 28, 36, 45); 53 | } 54 | 55 | [Test] 56 | public void PreScanMul() 57 | { 58 | var seq = new[] { 1, 2, 3 }; 59 | var result = seq.PreScan(SampleData.Mul, 1); 60 | result.AssertSequenceEqual(1, 1, 2); 61 | } 62 | 63 | [Test] 64 | public void PreScanFuncIsNotInvokedUnnecessarily() 65 | { 66 | var count = 0; 67 | var gold = new[] { 0, 1, 3 }; 68 | var sequence = Enumerable.Range(1, 3).PreScan((a, b) => 69 | ++count == gold.Length ? throw new TestException() : a + b, 0); 70 | 71 | sequence.AssertSequenceEqual(gold); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /MoreLinq.Test/Program.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | #pragma warning disable CA1852 // Seal internal types (false positive) 19 | 20 | using System; 21 | using System.Reflection; 22 | using NUnit.Common; 23 | using NUnitLite; 24 | 25 | using var writer = new ExtendedTextWrapper(Console.Out); 26 | return new AutoRun(typeof(Program).GetTypeInfo().Assembly).Execute(args, writer, Console.In); 27 | -------------------------------------------------------------------------------- /MoreLinq.Test/ReadOnlyCollection.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2019 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections; 21 | using System.Collections.Generic; 22 | 23 | static class ReadOnlyCollection 24 | { 25 | public static IReadOnlyCollection From(params T[] items) => 26 | new ListCollection(items); 27 | 28 | sealed class ListCollection(TList list) : 29 | IReadOnlyCollection 30 | where TList : IList 31 | { 32 | readonly TList list = list; 33 | 34 | public IEnumerator GetEnumerator() => this.list.GetEnumerator(); 35 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 36 | 37 | public int Count => this.list.Count; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /MoreLinq.Test/SampleData.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections.ObjectModel; 22 | 23 | /// 24 | /// Data and functions to use throughout tests. 25 | /// 26 | static class SampleData 27 | { 28 | internal static readonly ReadOnlyCollection 29 | Strings = new(["ax", "hello", "world", "aa", "ab", "ay", "az"]); 30 | 31 | internal static readonly ReadOnlyCollection 32 | Values = new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 33 | 34 | internal static readonly Func Plus = (a, b) => a + b; 35 | internal static readonly Func Mul = (a, b) => a * b; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MoreLinq.Test/ScanTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class ScanTest 24 | { 25 | [Test] 26 | public void ScanEmpty() 27 | { 28 | Assert.That(new int[0].Scan(SampleData.Plus), Is.Empty); 29 | } 30 | 31 | [Test] 32 | public void ScanSum() 33 | { 34 | var result = Enumerable.Range(1, 10).Scan(SampleData.Plus); 35 | var gold = new[] { 1, 3, 6, 10, 15, 21, 28, 36, 45, 55 }; 36 | result.AssertSequenceEqual(gold); 37 | } 38 | 39 | [Test] 40 | public void ScanIsLazy() 41 | { 42 | _ = new BreakingSequence().Scan(BreakingFunc.Of()); 43 | } 44 | 45 | [Test] 46 | public void ScanDoesNotIterateExtra() 47 | { 48 | var sequence = Enumerable.Range(1, 3).Concat(new BreakingSequence()).Scan(SampleData.Plus); 49 | var gold = new[] { 1, 3, 6 }; 50 | Assert.That(sequence.Consume, Throws.BreakException); 51 | sequence.Take(3).AssertSequenceEqual(gold); 52 | } 53 | 54 | [Test] 55 | public void SeededScanEmpty() 56 | { 57 | Assert.That(new int[0].Scan(-1, SampleData.Plus).Single(), Is.EqualTo(-1)); 58 | } 59 | 60 | [Test] 61 | public void SeededScanSum() 62 | { 63 | var result = Enumerable.Range(1, 10).Scan(0, SampleData.Plus); 64 | var gold = new[] { 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55 }; 65 | result.AssertSequenceEqual(gold); 66 | } 67 | 68 | [Test] 69 | public void SeededScanIsLazy() 70 | { 71 | _ = new BreakingSequence().Scan(null, BreakingFunc.Of()); 72 | } 73 | 74 | [Test] 75 | public void SeededScanDoesNotIterateExtra() 76 | { 77 | var sequence = Enumerable.Range(1, 3).Concat(new BreakingSequence()).Scan(0, SampleData.Plus); 78 | var gold = new[] { 0, 1, 3, 6 }; 79 | Assert.That(sequence.Consume, Throws.BreakException); 80 | sequence.Take(4).AssertSequenceEqual(gold); 81 | } 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /MoreLinq.Test/Scope.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | 22 | abstract class Scope(T current) : IDisposable 23 | { 24 | public virtual void Dispose() => Restore(current); 25 | protected abstract void Restore(T old); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /MoreLinq.Test/SkipLastTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using NUnit.Framework; 22 | using static MoreLinq.Extensions.SkipLastExtension; 23 | 24 | [TestFixture] 25 | public class SkipLastTest 26 | { 27 | [TestCase( 0)] 28 | [TestCase(-1)] 29 | public void SkipLastWithCountLesserThanOne(int skip) 30 | { 31 | var numbers = Enumerable.Range(1, 5); 32 | 33 | Assert.That(numbers.SkipLast(skip), Is.EqualTo(numbers)); 34 | } 35 | 36 | [Test] 37 | public void SkipLast() 38 | { 39 | const int take = 100; 40 | const int skip = 20; 41 | 42 | var sequence = Enumerable.Range(1, take); 43 | 44 | var expectations = sequence.Take(take - skip); 45 | 46 | Assert.That(expectations, Is.EqualTo(sequence.SkipLast(skip))); 47 | } 48 | 49 | [TestCase(5)] 50 | [TestCase(6)] 51 | public void SkipLastWithSequenceShorterThanCount(int skip) 52 | { 53 | Assert.That(Enumerable.Range(1, 5).SkipLast(skip), Is.Empty); 54 | } 55 | 56 | [Test] 57 | public void SkipLastIsLazy() 58 | { 59 | _ = new BreakingSequence().SkipLast(1); 60 | } 61 | 62 | [Test] 63 | public void SkipLastUsesCollectionCountAtIterationTime() 64 | { 65 | var list = new List { 1, 2, 3, 4 }; 66 | var result = list.SkipLast(2); 67 | list.Add(5); 68 | result.AssertSequenceEqual(1, 2, 3); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /MoreLinq.Test/SplitTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class SplitTest 24 | { 25 | [Test] 26 | public void SplitWithSeparatorAndResultTransformation() 27 | { 28 | var result = "the quick brown fox".ToCharArray().Split(' ', chars => new string([..chars])); 29 | result.AssertSequenceEqual("the", "quick", "brown", "fox"); 30 | } 31 | 32 | [Test] 33 | public void SplitUptoMaxCount() 34 | { 35 | var result = "the quick brown fox".ToCharArray().Split(' ', 2, chars => new string([..chars])); 36 | result.AssertSequenceEqual("the", "quick", "brown fox"); 37 | } 38 | 39 | [Test] 40 | public void SplitWithSeparatorSelector() 41 | { 42 | var result = new int?[] { 1, 2, null, 3, null, 4, 5, 6 }.Split(n => n == null); 43 | 44 | using var reader = result.Read(); 45 | reader.Read().AssertSequenceEqual(1, 2); 46 | reader.Read().AssertSequenceEqual(3); 47 | reader.Read().AssertSequenceEqual(4, 5, 6); 48 | reader.ReadEnd(); 49 | } 50 | 51 | [Test] 52 | public void SplitWithSeparatorSelectorUptoMaxCount() 53 | { 54 | var result = new int?[] { 1, 2, null, 3, null, 4, 5, 6 }.Split(n => n == null, 1); 55 | 56 | using var reader = result.Read(); 57 | reader.Read().AssertSequenceEqual(1, 2); 58 | reader.Read().AssertSequenceEqual(3, null, 4, 5, 6); 59 | reader.ReadEnd(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /MoreLinq.Test/TakeEveryTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class TakeEveryTest 24 | { 25 | [Test] 26 | public void TakeEveryNegativeSkip() 27 | { 28 | Assert.That(() => new object[0].TakeEvery(-1), 29 | Throws.ArgumentOutOfRangeException("step")); 30 | } 31 | 32 | [Test] 33 | public void TakeEveryOutOfRangeZeroStep() 34 | { 35 | Assert.That(() => new object[0].TakeEvery(0), 36 | Throws.ArgumentOutOfRangeException("step")); 37 | } 38 | 39 | [Test] 40 | public void TakeEveryEmptySequence() 41 | { 42 | Assert.That(new object[0].TakeEvery(1), Is.Empty); 43 | } 44 | 45 | [Test] 46 | public void TakeEveryNonEmptySequence() 47 | { 48 | var result = new[] { 1, 2, 3, 4, 5 }.TakeEvery(1); 49 | result.AssertSequenceEqual(1, 2, 3, 4, 5); 50 | } 51 | 52 | [Test] 53 | public void TakeEveryOtherOnNonEmptySequence() 54 | { 55 | var result = new[] { 1, 2, 3, 4, 5 }.TakeEvery(2); 56 | result.AssertSequenceEqual(1, 3, 5); 57 | } 58 | 59 | [Test] 60 | public void TakeEveryThirdOnNonEmptySequence() 61 | { 62 | var result = new[] { 1, 2, 3, 4, 5 }.TakeEvery(3); 63 | result.AssertSequenceEqual(1, 4); 64 | } 65 | 66 | [Test] 67 | public void TakeEveryIsLazy() 68 | { 69 | _ = new BreakingSequence().TakeEvery(1); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /MoreLinq.Test/TakeUntilTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class TakeUntilTest 24 | { 25 | [Test] 26 | public void TakeUntilPredicateNeverFalse() 27 | { 28 | var sequence = Enumerable.Range(0, 5).TakeUntil(x => x != 100); 29 | sequence.AssertSequenceEqual(0); 30 | } 31 | 32 | [Test] 33 | public void TakeUntilPredicateNeverTrue() 34 | { 35 | var sequence = Enumerable.Range(0, 5).TakeUntil(x => x == 100); 36 | sequence.AssertSequenceEqual(0, 1, 2, 3, 4); 37 | } 38 | 39 | [Test] 40 | public void TakeUntilPredicateBecomesTrueHalfWay() 41 | { 42 | var sequence = Enumerable.Range(0, 5).TakeUntil(x => x == 2); 43 | sequence.AssertSequenceEqual(0, 1, 2); 44 | } 45 | 46 | [Test] 47 | public void TakeUntilEvaluatesSourceLazily() 48 | { 49 | _ = new BreakingSequence().TakeUntil(x => x.Length == 0); 50 | } 51 | 52 | [Test] 53 | public void TakeUntilEvaluatesPredicateLazily() 54 | { 55 | // Predicate would explode at x == 0, but we never need to evaluate it due to the Take call. 56 | var sequence = Enumerable.Range(-2, 5).TakeUntil(x => 1 / x == 1).Take(3); 57 | sequence.AssertSequenceEqual(-2, -1, 0); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq.Test/TestException.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | /// 21 | /// Reserved for use within tests. 22 | /// 23 | 24 | sealed class TestException(string? message) : System.Exception(message) 25 | { 26 | public TestException() : this(null) { } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /MoreLinq.Test/Throws.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2022 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework.Constraints; 22 | 23 | static class Throws 24 | { 25 | public static ThrowsNothingConstraint Nothing => NUnit.Framework.Throws.Nothing; 26 | public static ExactTypeConstraint InvalidOperationException => NUnit.Framework.Throws.InvalidOperationException; 27 | public static ExactTypeConstraint ObjectDisposedException => TypeOf(); 28 | public static ExactTypeConstraint BreakException => TypeOf(); 29 | 30 | public static InstanceOfTypeConstraint InstanceOf() 31 | where T : Exception => 32 | NUnit.Framework.Throws.InstanceOf(); 33 | 34 | public static ExactTypeConstraint TypeOf() 35 | where T : Exception => 36 | NUnit.Framework.Throws.TypeOf(); 37 | 38 | public static EqualStringConstraint ArgumentException(string expectedParamName) => 39 | NUnit.Framework.Throws.ArgumentException.With.ParamName(expectedParamName); 40 | 41 | public static EqualStringConstraint ArgumentNullException(string expectedParamName) => 42 | NUnit.Framework.Throws.ArgumentNullException.With.ParamName(expectedParamName); 43 | 44 | public static ExactTypeConstraint ArgumentOutOfRangeException() => 45 | TypeOf(); 46 | 47 | public static EqualStringConstraint ArgumentOutOfRangeException(string expectedParamName) => 48 | ArgumentOutOfRangeException().With.ParamName(expectedParamName); 49 | 50 | public static EqualStringConstraint ParamName(this ConstraintExpression constraint, string expectedParamName) => 51 | constraint.ParamName().EqualTo(expectedParamName); 52 | 53 | static ResolvableConstraintExpression ParamName(this ConstraintExpression constraint) => 54 | constraint.Property(nameof(System.ArgumentException.ParamName)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /MoreLinq.Test/ToDelimitedStringTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class ToDelimitedStringTest 24 | { 25 | [Test] 26 | public void ToDelimitedStringWithNonEmptySequenceAndDelimiter() 27 | { 28 | var result = new[] { 1, 2, 3 }.ToDelimitedString("-"); 29 | Assert.That(result, Is.EqualTo("1-2-3")); 30 | } 31 | 32 | [Test] 33 | public void ToDelimitedStringWithNonEmptySequenceContainingNulls() 34 | { 35 | var result = new object?[] { 1, null, "foo", true }.ToDelimitedString(","); 36 | Assert.That(result, Is.EqualTo("1,,foo,True")); 37 | } 38 | 39 | [Test] 40 | public void ToDelimitedStringWithNonEmptySequenceContainingNullsAtStart() 41 | { 42 | // See: https://github.com/morelinq/MoreLINQ/issues/43 43 | var result = new object?[] { null, null, "foo" }.ToDelimitedString(","); 44 | Assert.That(result, Is.EqualTo(",,foo")); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /MoreLinq.Test/WatchableEnumerator.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections; 22 | using System.Collections.Generic; 23 | 24 | partial class TestExtensions 25 | { 26 | public static WatchableEnumerator AsWatchable(this IEnumerator source) => new(source); 27 | } 28 | 29 | sealed class WatchableEnumerator(IEnumerator source) : 30 | IEnumerator 31 | { 32 | readonly IEnumerator source = source ?? throw new ArgumentNullException(nameof(source)); 33 | 34 | public event EventHandler? Disposed; 35 | public event EventHandler? GetCurrentCalled; 36 | public event EventHandler? MoveNextCalled; 37 | 38 | public T Current 39 | { 40 | get 41 | { 42 | GetCurrentCalled?.Invoke(this, EventArgs.Empty); 43 | return this.source.Current; 44 | } 45 | } 46 | 47 | object? IEnumerator.Current => this.Current; 48 | 49 | public void Reset() => this.source.Reset(); 50 | 51 | public bool MoveNext() 52 | { 53 | var moved = this.source.MoveNext(); 54 | MoveNextCalled?.Invoke(this, moved); 55 | return moved; 56 | } 57 | 58 | public void Dispose() 59 | { 60 | this.source.Dispose(); 61 | Disposed?.Invoke(this, EventArgs.Empty); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MoreLinq.Test/coverlet.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | opencover 7 | [NUnit*]*,[MoreLinq]MoreLinq.Extensions.*,[MoreLinq]MoreLinq.Experimental.* 8 | **/System.*.g.cs 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /MoreLinq/Acquire.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Ensures that a source sequence of 27 | /// objects are all acquired successfully. If the acquisition of any 28 | /// one fails then those successfully 29 | /// acquired till that point are disposed. 30 | /// 31 | /// Type of elements in sequence. 32 | /// Source sequence of objects. 33 | /// 34 | /// Returns an array of all the acquired 35 | /// objects in source order. 36 | /// 37 | /// 38 | /// This operator executes immediately. 39 | /// 40 | 41 | public static TSource[] Acquire(this IEnumerable source) 42 | where TSource : IDisposable 43 | { 44 | if (source == null) throw new ArgumentNullException(nameof(source)); 45 | 46 | var disposables = new List(); 47 | try 48 | { 49 | disposables.AddRange(source); 50 | return [..disposables]; 51 | } 52 | catch 53 | { 54 | foreach (var disposable in disposables) 55 | disposable.Dispose(); 56 | throw; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq/Append.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Returns a sequence consisting of the head elements and the given tail element. 27 | /// 28 | /// Type of sequence 29 | /// All elements of the head. Must not be null. 30 | /// Tail element of the new sequence. 31 | /// A sequence consisting of the head elements and the given tail element. 32 | /// This operator uses deferred execution and streams its results. 33 | 34 | #if NET471_OR_GREATER || NETSTANDARD1_6_OR_GREATER || NETCOREAPP2_0_OR_GREATER 35 | public static IEnumerable Append(IEnumerable head, T tail) 36 | #else 37 | public static IEnumerable Append(this IEnumerable head, T tail) 38 | #endif 39 | { 40 | if (head == null) throw new ArgumentNullException(nameof(head)); 41 | return head is PendNode node 42 | ? node.Concat(tail) 43 | : PendNode.WithSource(head).Concat(tail); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /MoreLinq/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | using System; 19 | using System.Reflection; 20 | 21 | [assembly: AssemblyTitle("MoreLINQ")] 22 | [assembly: AssemblyDescription("Extensions to LINQ to Objects")] 23 | [assembly: AssemblyCompany("")] 24 | [assembly: AssemblyProduct("MoreLINQ")] 25 | [assembly: AssemblyTrademark("")] 26 | [assembly: AssemblyCulture("")] 27 | 28 | // Debug or release configuration? 29 | 30 | #if DEBUG 31 | [assembly: AssemblyConfiguration("DEBUG")] 32 | #else 33 | [assembly: AssemblyConfiguration("RELEASE")] 34 | #endif 35 | 36 | // CLS compliance and COM visibility 37 | 38 | [assembly: CLSCompliant(true)] 39 | [assembly: System.Runtime.InteropServices.ComVisible(false)] 40 | 41 | // ID of the typelib if this project is exposed to COM. 42 | 43 | [assembly: System.Runtime.InteropServices.Guid("fc632c9d-390e-4902-8c1c-3e57b08c1d38")] 44 | -------------------------------------------------------------------------------- /MoreLinq/Assume.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2022 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System.Runtime.CompilerServices; 21 | 22 | static class Assume 23 | { 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static T NotNull(T? obj) where T : class 26 | { 27 | Debug.Assert(obj is not null); 28 | return obj; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MoreLinq/Choose.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Applies a function to each element of the source sequence and 27 | /// returns a new sequence of result elements for source elements 28 | /// where the function returns a couple (2-tuple) having a true 29 | /// as its first element and result as the second. 30 | /// 31 | /// 32 | /// The type of the elements in . 33 | /// 34 | /// The type of the elements in the returned sequence. 35 | /// The source sequence. 36 | /// The function that is applied to each source 37 | /// element. 38 | /// A sequence elements. 39 | /// 40 | /// This method uses deferred execution semantics and streams its 41 | /// results. 42 | /// 43 | /// 44 | /// (int.TryParse(s, out var n), n)); 47 | /// ]]> 48 | /// The xs variable will be a sequence of the integers 2, 3, 4, 49 | /// 6, 7 and 9. 50 | /// 51 | 52 | public static IEnumerable Choose(this IEnumerable source, 53 | Func chooser) 54 | { 55 | if (source == null) throw new ArgumentNullException(nameof(source)); 56 | if (chooser == null) throw new ArgumentNullException(nameof(chooser)); 57 | 58 | return _(source, chooser); 59 | 60 | static IEnumerable _( 61 | IEnumerable source, 62 | Func chooser) 63 | { 64 | foreach (var item in source) 65 | { 66 | var (some, value) = chooser(item); 67 | if (some) 68 | yield return value; 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /MoreLinq/CollectionLike.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2023 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | /// 25 | /// Represents a union over list types implementing either or , 27 | /// allowing both to be treated the same. 28 | /// 29 | 30 | readonly struct CollectionLike 31 | { 32 | readonly ICollection? rw; 33 | readonly IReadOnlyCollection? ro; 34 | 35 | public CollectionLike(ICollection collection) 36 | { 37 | this.rw = collection ?? throw new ArgumentNullException(nameof(collection)); 38 | this.ro = null; 39 | } 40 | 41 | public CollectionLike(IReadOnlyCollection collection) 42 | { 43 | this.rw = null; 44 | this.ro = collection ?? throw new ArgumentNullException(nameof(collection)); 45 | } 46 | 47 | public int Count => this.rw?.Count ?? this.ro?.Count ?? 0; 48 | 49 | public IEnumerator GetEnumerator() => 50 | this.rw?.GetEnumerator() ?? this.ro?.GetEnumerator() ?? Enumerable.Empty().GetEnumerator(); 51 | } 52 | 53 | static class CollectionLike 54 | { 55 | public static CollectionLike? TryAsCollectionLike(this IEnumerable source) => 56 | source switch 57 | { 58 | null => throw new ArgumentNullException(nameof(source)), 59 | ICollection collection => new(collection), 60 | IReadOnlyCollection collection => new(collection), 61 | _ => null 62 | }; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MoreLinq/Collections/Dictionary.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2020 Atif Aziz, Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Collections 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Diagnostics.CodeAnalysis; 23 | 24 | /// 25 | /// A minimal wrapper that 26 | /// allows a null key. 27 | /// 28 | 29 | // Add members if and when needed to keep coverage. 30 | 31 | sealed class Dictionary 32 | { 33 | readonly System.Collections.Generic.Dictionary, TValue> dict; 34 | 35 | public Dictionary(IEqualityComparer comparer) 36 | { 37 | var keyComparer = ReferenceEquals(comparer, EqualityComparer.Default) 38 | ? null 39 | : new ValueTupleItemComparer(comparer); 40 | this.dict = new System.Collections.Generic.Dictionary, TValue>(keyComparer); 41 | } 42 | 43 | public TValue this[TKey key] 44 | { 45 | get => this.dict[ValueTuple.Create(key)]; 46 | set => this.dict[ValueTuple.Create(key)] = value; 47 | } 48 | 49 | public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) => 50 | this.dict.TryGetValue(ValueTuple.Create(key), out value); 51 | 52 | sealed class ValueTupleItemComparer(IEqualityComparer comparer) : 53 | IEqualityComparer> 54 | { 55 | public bool Equals(ValueTuple x, ValueTuple y) => comparer.Equals(x.Item1, y.Item1); 56 | public int GetHashCode(ValueTuple obj) => obj.Item1 is { } some ? comparer.GetHashCode(some) : 0; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /MoreLinq/Consume.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Completely consumes the given sequence. This method uses immediate execution, 27 | /// and doesn't store any data during execution. 28 | /// 29 | /// Element type of the sequence 30 | /// Source to consume 31 | 32 | public static void Consume(this IEnumerable source) 33 | { 34 | if (source == null) throw new ArgumentNullException(nameof(source)); 35 | foreach (var _ in source) 36 | { 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /MoreLinq/Debug.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2022 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System.Diagnostics; 21 | using System.Diagnostics.CodeAnalysis; 22 | using System.Runtime.CompilerServices; 23 | 24 | static class Debug 25 | { 26 | [Conditional("DEBUG")] 27 | public static void Assert([DoesNotReturnIf(false)] bool condition, 28 | [CallerArgumentExpression(nameof(condition))] string? message = null) => 29 | System.Diagnostics.Debug.Assert(condition, message); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MoreLinq/Delegating.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (C) 2017 Atif Aziz. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | #endregion 22 | 23 | // https://github.com/atifaziz/Delegating 24 | 25 | #pragma warning disable IDE0130 // Namespace does not match folder structure 26 | 27 | namespace Delegating 28 | { 29 | using System; 30 | using System.Threading; 31 | 32 | static class Delegate 33 | { 34 | public static IDisposable Disposable(Action delegatee) => 35 | new DelegatingDisposable(delegatee); 36 | 37 | public static IObserver Observer(Action onNext, 38 | Action? onError = null, 39 | Action? onCompleted = null) => 40 | new DelegatingObserver(onNext, onError, onCompleted); 41 | } 42 | 43 | sealed class DelegatingDisposable(Action delegatee) : IDisposable 44 | { 45 | Action? delegatee = delegatee ?? throw new ArgumentNullException(nameof(delegatee)); 46 | 47 | public void Dispose() 48 | { 49 | var delegatee = this.delegatee; 50 | if (delegatee == null || Interlocked.CompareExchange(ref this.delegatee, null, delegatee) != delegatee) 51 | return; 52 | delegatee(); 53 | } 54 | } 55 | 56 | sealed class DelegatingObserver(Action onNext, 57 | Action? onError = null, 58 | Action? onCompleted = null) : 59 | IObserver 60 | { 61 | readonly Action onNext = onNext ?? throw new ArgumentNullException(nameof(onNext)); 62 | 63 | public void OnCompleted() => onCompleted?.Invoke(); 64 | public void OnError(Exception error) => onError?.Invoke(error); 65 | public void OnNext(T value) => this.onNext(value); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /MoreLinq/Disposable.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using Delegate = Delegating.Delegate; 22 | 23 | static class Disposable 24 | { 25 | public static readonly IDisposable Nop = Delegate.Disposable(delegate { }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /MoreLinq/Duplicates.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2023 Julien Aspirot. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns all duplicate elements of the given source. 28 | /// 29 | /// The source sequence. 30 | /// The type of the elements in the source sequence. 31 | /// is . 32 | /// All elements that are duplicated. 33 | /// This operator uses deferred execution and streams its results. 34 | 35 | public static IEnumerable Duplicates(this IEnumerable source) => 36 | Duplicates(source, null); 37 | 38 | /// 39 | /// Returns all duplicate elements of the given source, using the specified equality 40 | /// comparer. 41 | /// 42 | /// The source sequence. 43 | /// 44 | /// The equality comparer to use to determine whether one 45 | /// equals another. If , the default equality comparer for 46 | /// is used. 47 | /// The type of the elements in the source sequence. 48 | /// is . 49 | /// All elements that are duplicated. 50 | /// This operator uses deferred execution and streams its results. 51 | 52 | public static IEnumerable Duplicates(this IEnumerable source, IEqualityComparer? comparer) 53 | { 54 | if (source is null) throw new ArgumentNullException(nameof(source)); 55 | 56 | return from e in source.ScanBy(static e => e, 57 | static _ => 0, 58 | static (count, _, _) => unchecked(Math.Min(count + 1, 3)), 59 | comparer) 60 | where e.Value is 2 61 | select e.Key; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MoreLinq/Evaluate.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Felipe Sateler. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a sequence containing the values resulting from invoking (in order) each function in the source sequence of functions. 28 | /// 29 | /// 30 | /// This operator uses deferred execution and streams the results. 31 | /// If the resulting sequence is enumerated multiple times, the functions will be 32 | /// evaluated multiple times too. 33 | /// 34 | /// The type of the object returned by the functions. 35 | /// The functions to evaluate. 36 | /// A sequence with results from invoking . 37 | /// When is null. 38 | 39 | public static IEnumerable Evaluate(this IEnumerable> functions) => 40 | from f in functions ?? throw new ArgumentNullException(nameof(functions)) 41 | select f(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /MoreLinq/Exclude.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2010 Leopold Bushkin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | public static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Excludes a contiguous number of elements from a sequence starting 27 | /// at a given index. 28 | /// 29 | /// The type of the elements of the sequence 30 | /// The sequence to exclude elements from 31 | /// The zero-based index at which to begin excluding elements 32 | /// The number of elements to exclude 33 | /// A sequence that excludes the specified portion of elements 34 | 35 | public static IEnumerable Exclude(this IEnumerable sequence, int startIndex, int count) 36 | { 37 | if (sequence == null) throw new ArgumentNullException(nameof(sequence)); 38 | if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex)); 39 | 40 | return count switch 41 | { 42 | < 0 => throw new ArgumentOutOfRangeException(nameof(count)), 43 | 0 => sequence, 44 | _ => _(sequence, startIndex, count) 45 | }; 46 | 47 | static IEnumerable _(IEnumerable sequence, int startIndex, int count) 48 | { 49 | var index = 0; 50 | var endIndex = startIndex + count; 51 | using var iter = sequence.GetEnumerator(); 52 | 53 | // yield the first part of the sequence 54 | for (; index < startIndex; index++) 55 | { 56 | if (!iter.MoveNext()) 57 | yield break; 58 | yield return iter.Current; 59 | } 60 | 61 | // skip the next part (up to count items) 62 | for (; index < endIndex; index++) 63 | { 64 | if (!iter.MoveNext()) 65 | yield break; 66 | } 67 | 68 | // yield the remainder of the sequence 69 | while (iter.MoveNext()) 70 | yield return iter.Current; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /MoreLinq/Experimental/Aggregate.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Experimental 19 | { 20 | using System; 21 | using Reactive; 22 | 23 | static partial class ExperimentalEnumerable 24 | { 25 | static IDisposable SubscribeSingle(Func, IObservable> aggregatorSelector, IObservable subject, (bool Defined, TResult)[] r, string paramName) 26 | { 27 | var aggregator = aggregatorSelector(subject); 28 | return ReferenceEquals(aggregator, subject) 29 | ? throw new ArgumentException("Aggregator cannot be identical to the source.", paramName) 30 | : aggregator.Subscribe(s => 31 | r[0] = r[0].Defined 32 | ? throw new InvalidOperationException( 33 | $"Aggregator supplied for parameter \"{paramName}\" produced multiple results when only one is allowed.") 34 | : (true, s)); 35 | } 36 | 37 | static T GetAggregateResult((bool Defined, T Value) result, string paramName) => 38 | !result.Defined 39 | ? throw new InvalidOperationException($"Aggregator supplied for parameter \"{paramName}\" has an undefined result.") 40 | : result.Value; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /MoreLinq/Experimental/Async/ExperimentalEnumerable.cs: -------------------------------------------------------------------------------- 1 | #if !NO_ASYNC_STREAMS 2 | 3 | namespace MoreLinq.Experimental.Async 4 | { 5 | using System.Collections.Generic; 6 | 7 | /// 8 | /// 9 | /// Provides a set of static methods for querying objects that 10 | /// implement . 11 | /// 12 | /// THE METHODS ARE EXPERIMENTAL. THEY MAY BE UNSTABLE AND 13 | /// UNTESTED. THEY MAY BE REMOVED FROM A FUTURE MAJOR OR MINOR RELEASE AND 14 | /// POSSIBLY WITHOUT NOTICE. USE THEM AT YOUR OWN RISK. THE METHODS ARE 15 | /// PUBLISHED FOR FIELD EXPERIMENTATION TO SOLICIT FEEDBACK ON THEIR 16 | /// UTILITY AND DESIGN/IMPLEMENTATION DEFECTS. 17 | /// 18 | 19 | public static partial class ExperimentalEnumerable 20 | { 21 | } 22 | } 23 | 24 | #endif // !NO_ASYNC_STREAMS 25 | -------------------------------------------------------------------------------- /MoreLinq/Experimental/ExperimentalEnumerable.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Experimental 19 | { 20 | using System.Collections.Generic; 21 | 22 | /// 23 | /// 24 | /// Provides a set of static methods for querying objects that 25 | /// implement . 26 | /// 27 | /// THE METHODS ARE EXPERIMENTAL. THEY MAY BE UNSTABLE AND 28 | /// UNTESTED. THEY MAY BE REMOVED FROM A FUTURE MAJOR OR MINOR RELEASE AND 29 | /// POSSIBLY WITHOUT NOTICE. USE THEM AT YOUR OWN RISK. THE METHODS ARE 30 | /// PUBLISHED FOR FIELD EXPERIMENTATION TO SOLICIT FEEDBACK ON THEIR 31 | /// UTILITY AND DESIGN/IMPLEMENTATION DEFECTS. 32 | /// 33 | 34 | public static partial class ExperimentalEnumerable 35 | { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MoreLinq/ExtremaMembers.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2023 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | static class ExtremaMembers 21 | { 22 | public const string Minima = nameof(MoreEnumerable.Minima); 23 | public const string Maxima = nameof(MoreEnumerable.Maxima); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MoreLinq/Fold.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2013 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | static T[] Fold(this IEnumerable source, int count) 26 | { 27 | var elements = new T[count]; 28 | var i = 0; 29 | 30 | foreach (var item in source) 31 | { 32 | elements[i] = i < count ? item : throw LengthError(1); 33 | i++; 34 | } 35 | 36 | if (i < count) 37 | throw LengthError(-1); 38 | 39 | return elements; 40 | 41 | InvalidOperationException LengthError(int cmp) => new(FormatSequenceLengthErrorMessage(cmp, count)); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /MoreLinq/ForEach.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Immediately executes the given action on each element in the source sequence. 27 | /// 28 | /// The type of the elements in the sequence 29 | /// The sequence of elements 30 | /// The action to execute on each element 31 | 32 | public static void ForEach(this IEnumerable source, Action action) 33 | { 34 | if (source == null) throw new ArgumentNullException(nameof(source)); 35 | if (action == null) throw new ArgumentNullException(nameof(action)); 36 | 37 | foreach (var element in source) 38 | action(element); 39 | } 40 | 41 | /// 42 | /// Immediately executes the given action on each element in the source sequence. 43 | /// Each element's index is used in the logic of the action. 44 | /// 45 | /// The type of the elements in the sequence 46 | /// The sequence of elements 47 | /// The action to execute on each element; the second parameter 48 | /// of the action represents the index of the source element. 49 | 50 | public static void ForEach(this IEnumerable source, Action action) 51 | { 52 | if (source == null) throw new ArgumentNullException(nameof(source)); 53 | if (action == null) throw new ArgumentNullException(nameof(action)); 54 | 55 | var index = 0; 56 | foreach (var element in source) 57 | action(element, index++); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq/Generate.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Chris Ammerman. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Returns a sequence of values consecutively generated by a generator function. 27 | /// 28 | /// Type of elements to generate. 29 | /// Value of first element in sequence 30 | /// 31 | /// Generator function which takes the previous series element and uses it to generate the next element. 32 | /// 33 | /// A sequence containing the generated values. 34 | /// 35 | /// This function defers element generation until needed and streams the results. 36 | /// 37 | /// 38 | /// n * n).Take(5); 40 | /// ]]> 41 | /// The result variable, when iterated over, will yield 2, 4, 16, 256, and 65536, in turn. 42 | /// 43 | 44 | public static IEnumerable Generate(TResult initial, Func generator) 45 | { 46 | if (generator == null) throw new ArgumentNullException(nameof(generator)); 47 | 48 | return _(initial, generator); 49 | 50 | static IEnumerable _(TResult initial, Func generator) 51 | { 52 | var current = initial; 53 | while (true) 54 | { 55 | yield return current; 56 | current = generator(current); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /MoreLinq/GenerateByIndex.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a sequence of values based on indexes. 28 | /// 29 | /// 30 | /// The type of the value returned by 31 | /// and therefore the elements of the generated sequence. 32 | /// 33 | /// Generation function to apply to each index. 34 | /// A sequence of generated results. 35 | /// 36 | /// 37 | /// The sequence is (practically) infinite where the index ranges from 38 | /// zero to inclusive. 39 | /// 40 | /// This function defers execution and streams the results. 41 | /// 42 | 43 | public static IEnumerable GenerateByIndex(Func generator) 44 | { 45 | if (generator == null) throw new ArgumentNullException(nameof(generator)); 46 | 47 | return MoreEnumerable.Sequence(0, int.MaxValue) 48 | .Select(generator); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /MoreLinq/IdFn.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2022 Turning Code, LLC. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | static partial class MoreEnumerable 21 | { 22 | static T IdFn(T x) => x; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /MoreLinq/Index.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a sequence of 28 | /// where the key is the zero-based index of the value in the source 29 | /// sequence. 30 | /// 31 | /// Type of elements in sequence. 32 | /// The source sequence. 33 | /// A sequence of . 34 | /// This operator uses deferred execution and streams its 35 | /// results. 36 | 37 | public static IEnumerable> Index(this IEnumerable source) 38 | { 39 | return source.Index(0); 40 | } 41 | 42 | /// 43 | /// Returns a sequence of 44 | /// where the key is the index of the value in the source sequence. 45 | /// An additional parameter specifies the starting index. 46 | /// 47 | /// Type of elements in sequence. 48 | /// The source sequence. 49 | /// 50 | /// A sequence of . 51 | /// This operator uses deferred execution and streams its 52 | /// results. 53 | 54 | public static IEnumerable> Index(this IEnumerable source, int startIndex) 55 | { 56 | if (source == null) throw new ArgumentNullException(nameof(source)); 57 | return source.Select((item, index) => new KeyValuePair(startIndex + index, item)); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq/ListLike.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | /// 25 | /// Represents a union over list types implementing either 26 | /// or , allowing 27 | /// both to be treated the same. 28 | /// 29 | 30 | readonly struct ListLike 31 | { 32 | readonly IList? rw; 33 | readonly IReadOnlyList? ro; 34 | 35 | public ListLike(IList list) 36 | { 37 | this.rw = list ?? throw new ArgumentNullException(nameof(list)); 38 | this.ro = null; 39 | } 40 | 41 | public ListLike(IReadOnlyList list) 42 | { 43 | this.rw = null; 44 | this.ro = list ?? throw new ArgumentNullException(nameof(list)); 45 | } 46 | 47 | public int Count => this.rw?.Count ?? this.ro?.Count ?? 0; 48 | 49 | public T this[int index] => this.rw is { } rw ? rw[index] 50 | : this.ro is { } rx ? rx[index] 51 | : throw new ArgumentOutOfRangeException(nameof(index)); 52 | } 53 | 54 | static class ListLike 55 | { 56 | public static ListLike AsListLike(this List list) => new((IList)list); 57 | 58 | public static ListLike ToListLike(this IEnumerable source) 59 | => source.TryAsListLike() ?? source.ToList().AsListLike(); 60 | 61 | public static ListLike? TryAsListLike(this IEnumerable source) => 62 | source switch 63 | { 64 | null => throw new ArgumentNullException(nameof(source)), 65 | IList list => new(list), 66 | IReadOnlyList list => new(list), 67 | _ => null 68 | }; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /MoreLinq/Lock.cs: -------------------------------------------------------------------------------- 1 | #if NET9_0_OR_GREATER 2 | // https://learn.microsoft.com/dotnet/csharp/language-reference/statements/lock#guidelines 3 | global using Lock = System.Threading.Lock; 4 | #else 5 | // For why "System.Object" instead of "object", see: 6 | // https://github.com/dotnet/runtime/issues/110242 7 | global using Lock = System.Object; 8 | #endif 9 | -------------------------------------------------------------------------------- /MoreLinq/MoreEnumerable.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | /// 24 | /// Provides a set of static methods for querying objects that 25 | /// implement . 26 | /// 27 | 28 | public static partial class MoreEnumerable 29 | { 30 | static int CountUpTo(this IEnumerable source, int max) 31 | { 32 | if (source == null) throw new ArgumentNullException(nameof(source)); 33 | if (max < 0) throw new ArgumentOutOfRangeException(nameof(max), "The maximum count argument cannot be negative."); 34 | 35 | var count = 0; 36 | 37 | using var e = source.GetEnumerator(); 38 | while (count < max && e.MoveNext()) 39 | count++; 40 | 41 | return count; 42 | } 43 | 44 | // See https://github.com/atifaziz/Optuple 45 | 46 | static (bool HasValue, T Value) Some(T value) => (true, value); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /MoreLinq/OrderByDirection.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2010 Leopold Bushkin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | /// 21 | /// Enumeration that defines values representing valid ordering directions for a sequence. 22 | /// 23 | 24 | public enum OrderByDirection 25 | { 26 | /// 27 | /// Elements are ordered by increasing value 28 | /// 29 | Ascending = 0, 30 | /// 31 | /// Elements are ordered by decreasing value 32 | /// 33 | Descending = 1, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /MoreLinq/Pairwise.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Returns a sequence resulting from applying a function to each 27 | /// element in the source sequence and its 28 | /// predecessor, with the exception of the first element which is 29 | /// only returned as the predecessor of the second element. 30 | /// 31 | /// The type of the elements of . 32 | /// The type of the element of the returned sequence. 33 | /// The source sequence. 34 | /// A transform function to apply to 35 | /// each pair of sequence. 36 | /// 37 | /// Returns the resulting sequence. 38 | /// 39 | /// 40 | /// This operator uses deferred execution and streams its results. 41 | /// 42 | /// 43 | /// a + b); 46 | /// ]]> 47 | /// The result variable, when iterated over, will yield 48 | /// "ab", "bc" and "cd", in turn. 49 | /// 50 | 51 | public static IEnumerable Pairwise(this IEnumerable source, Func resultSelector) 52 | { 53 | if (source == null) throw new ArgumentNullException(nameof(source)); 54 | if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); 55 | 56 | return _(source, resultSelector); 57 | 58 | static IEnumerable _(IEnumerable source, Func resultSelector) 59 | { 60 | using var e = source.GetEnumerator(); 61 | 62 | if (!e.MoveNext()) 63 | yield break; 64 | 65 | var previous = e.Current; 66 | while (e.MoveNext()) 67 | { 68 | yield return resultSelector(previous, e.Current); 69 | previous = e.Current; 70 | } 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /MoreLinq/Pipe.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Executes the given action on each element in the source sequence 27 | /// and yields it. 28 | /// 29 | /// The type of the elements in the sequence 30 | /// The sequence of elements 31 | /// The action to execute on each element 32 | /// A sequence with source elements in their original order. 33 | /// 34 | /// The returned sequence is essentially a duplicate of 35 | /// the original, but with the extra action being executed while the 36 | /// sequence is evaluated. The action is always taken before the element 37 | /// is yielded, so any changes made by the action will be visible in the 38 | /// returned sequence. This operator uses deferred execution and streams it results. 39 | /// 40 | 41 | public static IEnumerable Pipe(this IEnumerable source, Action action) 42 | { 43 | if (source == null) throw new ArgumentNullException(nameof(source)); 44 | if (action == null) throw new ArgumentNullException(nameof(action)); 45 | 46 | return _(source, action); 47 | 48 | static IEnumerable _(IEnumerable source, Action action) 49 | { 50 | foreach (var element in source) 51 | { 52 | action(element); 53 | yield return element; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /MoreLinq/Prepend.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Prepends a single value to a sequence. 27 | /// 28 | /// The type of the elements of . 29 | /// The sequence to prepend to. 30 | /// The value to prepend. 31 | /// 32 | /// Returns a sequence where a value is prepended to it. 33 | /// 34 | /// 35 | /// This operator uses deferred execution and streams its results. 36 | /// 37 | /// 41 | /// The result variable, when iterated over, will yield 42 | /// 0, 1, 2 and 3, in turn. 43 | 44 | #if NET471_OR_GREATER || NETSTANDARD1_6_OR_GREATER || NETCOREAPP2_0_OR_GREATER 45 | public static IEnumerable Prepend(IEnumerable source, TSource value) 46 | #else 47 | public static IEnumerable Prepend(this IEnumerable source, TSource value) 48 | #endif 49 | { 50 | if (source == null) throw new ArgumentNullException(nameof(source)); 51 | return source is PendNode node 52 | ? node.Prepend(value) 53 | : PendNode.WithSource(source).Prepend(value); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /MoreLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | -------------------------------------------------------------------------------- /MoreLinq/PublicAPI/net9.0/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | -------------------------------------------------------------------------------- /MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | -------------------------------------------------------------------------------- /MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | -------------------------------------------------------------------------------- /MoreLinq/Reactive/Observable.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2019 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Reactive 19 | { 20 | using System; 21 | using Delegate = Delegating.Delegate; 22 | 23 | /// 24 | /// Provides a set of static methods for writing in-memory queries over observable sequences. 25 | /// 26 | 27 | static partial class Observable 28 | { 29 | /// 30 | /// Subscribes an element handler and a completion handler to an 31 | /// observable sequence. 32 | /// 33 | /// Type of elements in . 34 | /// Observable sequence to subscribe to. 35 | /// 36 | /// Action to invoke for each element in . 37 | /// 38 | /// Action to invoke upon exceptional termination of the 39 | /// . 40 | /// 41 | /// Action to invoke upon graceful termination of . 42 | /// The subscription, which when disposed, will unsubscribe 43 | /// from . 44 | 45 | public static IDisposable Subscribe(this IObservable source, Action onNext, Action? onError = null, Action? onCompleted = null) => 46 | source == null 47 | ? throw new ArgumentNullException(nameof(source)) 48 | : source.Subscribe(Delegate.Observer(onNext, onError, onCompleted)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /MoreLinq/Repeat.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2010 Leopold Bushkin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using Experimental; 23 | 24 | public static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Repeats the sequence the specified number of times. 28 | /// 29 | /// Type of elements in sequence 30 | /// The sequence to repeat 31 | /// Number of times to repeat the sequence 32 | /// A sequence produced from the repetition of the original source sequence 33 | 34 | public static IEnumerable Repeat(this IEnumerable sequence, int count) 35 | { 36 | if (sequence == null) throw new ArgumentNullException(nameof(sequence)); 37 | if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Repeat count must be greater than or equal to zero."); 38 | return RepeatImpl(sequence, count); 39 | } 40 | 41 | /// 42 | /// Repeats the sequence forever. 43 | /// 44 | /// Type of elements in sequence 45 | /// The sequence to repeat 46 | /// A sequence produced from the infinite repetition of the original source sequence 47 | 48 | public static IEnumerable Repeat(this IEnumerable sequence) 49 | { 50 | if (sequence == null) throw new ArgumentNullException(nameof(sequence)); 51 | return RepeatImpl(sequence, null); 52 | } 53 | 54 | 55 | static IEnumerable RepeatImpl(IEnumerable sequence, int? count) 56 | { 57 | var memo = sequence.Memoize(); 58 | using (memo as IDisposable) 59 | { 60 | while (count == null || count-- > 0) 61 | { 62 | #pragma warning disable CA1851 // Possible multiple enumerations of 'IEnumerable' collection 63 | foreach (var item in memo) 64 | #pragma warning restore CA1851 // Possible multiple enumerations of 'IEnumerable' collection 65 | { 66 | yield return item; 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /MoreLinq/Return.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2019 Mitch Bodmer. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections; 22 | using System.Collections.Generic; 23 | 24 | partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a single-element sequence containing the item provided. 28 | /// 29 | /// The type of the item. 30 | /// The item to return in a sequence. 31 | /// A sequence containing only . 32 | 33 | public static IEnumerable Return(T item) => new SingleElementList(item); 34 | 35 | sealed class SingleElementList(T item) : IList, IReadOnlyList 36 | { 37 | readonly T item = item; 38 | 39 | public int Count => 1; 40 | public bool IsReadOnly => true; 41 | 42 | public T this[int index] 43 | { 44 | get => index == 0 ? this.item : throw new ArgumentOutOfRangeException(nameof(index)); 45 | set => throw ReadOnlyException(); 46 | } 47 | 48 | public IEnumerator GetEnumerator() { yield return this.item; } 49 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 50 | 51 | public int IndexOf(T item) => Contains(item) ? 0 : -1; 52 | public bool Contains(T item) => EqualityComparer.Default.Equals(this.item, item); 53 | 54 | public void CopyTo(T[] array, int arrayIndex) => array[arrayIndex] = this.item; 55 | 56 | // Following methods are unsupported as this is a read-only list. 57 | 58 | public void Add(T item) => throw ReadOnlyException(); 59 | public void Clear() => throw ReadOnlyException(); 60 | public bool Remove(T item) => throw ReadOnlyException(); 61 | public void Insert(int index, T item) => throw ReadOnlyException(); 62 | public void RemoveAt(int index) => throw ReadOnlyException(); 63 | 64 | static NotSupportedException ReadOnlyException() => new("Single element list is immutable."); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /MoreLinq/ReverseComparer.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2016 Felipe Sateler. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System.Collections.Generic; 21 | 22 | sealed class ReverseComparer(IComparer? underlying) : IComparer 23 | { 24 | readonly IComparer underlying = underlying ?? Comparer.Default; 25 | 26 | public int Compare 27 | #if NETCOREAPP3_1_OR_GREATER 28 | (T? x, T? y) 29 | #else 30 | (T x, T y) 31 | #endif 32 | { 33 | var result = this.underlying.Compare(x, y); 34 | return result < 0 ? 1 : result > 0 ? -1 : 0; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MoreLinq/Shuffle.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | public static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Returns a sequence of elements in random order from the original 27 | /// sequence. 28 | /// 29 | /// The type of source sequence elements. 30 | /// 31 | /// The sequence from which to return random elements. 32 | /// 33 | /// A sequence of elements randomized in 34 | /// their order. 35 | /// 36 | /// 37 | /// This method uses deferred execution and streams its results. The 38 | /// source sequence is entirely buffered before the results are 39 | /// streamed. 40 | /// 41 | 42 | public static IEnumerable Shuffle(this IEnumerable source) 43 | { 44 | return Shuffle(source, GlobalRandom.Instance); 45 | } 46 | 47 | /// 48 | /// Returns a sequence of elements in random order from the original 49 | /// sequence. An additional parameter specifies a random generator to be 50 | /// used for the random selection algorithm. 51 | /// 52 | /// The type of source sequence elements. 53 | /// 54 | /// The sequence from which to return random elements. 55 | /// 56 | /// A random generator used as part of the selection algorithm. 57 | /// 58 | /// A sequence of elements randomized in 59 | /// their order. 60 | /// 61 | /// 62 | /// This method uses deferred execution and streams its results. The 63 | /// source sequence is entirely buffered before the results are 64 | /// streamed. 65 | /// 66 | 67 | public static IEnumerable Shuffle(this IEnumerable source, Random rand) 68 | { 69 | if (source == null) throw new ArgumentNullException(nameof(source)); 70 | if (rand == null) throw new ArgumentNullException(nameof(rand)); 71 | 72 | return RandomSubsetImpl(source, rand, subsetSize: null); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /MoreLinq/SkipLast.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Bypasses a specified number of elements at the end of the sequence. 28 | /// 29 | /// Type of the source sequence 30 | /// The source sequence. 31 | /// The number of elements to bypass at the end of the source sequence. 32 | /// 33 | /// An containing the source sequence elements except for the bypassed ones at the end. 34 | /// 35 | 36 | #if NETSTANDARD2_1 || NETCOREAPP2_0_OR_GREATER 37 | public static IEnumerable SkipLast(IEnumerable source, int count) 38 | #else 39 | public static IEnumerable SkipLast(this IEnumerable source, int count) 40 | #endif 41 | { 42 | if (source == null) throw new ArgumentNullException(nameof(source)); 43 | 44 | return count < 1 ? source 45 | : source.CountDown(count, (e, cd) => (Element: e, Countdown: cd)) 46 | .TakeWhile(e => e.Countdown == null) 47 | .Select(e => e.Element); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /MoreLinq/TakeEvery.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns every N-th element of a sequence. 28 | /// 29 | /// Type of the source sequence 30 | /// Source sequence 31 | /// Number of elements to bypass before returning the next element. 32 | /// 33 | /// A sequence with every N-th element of the input sequence. 34 | /// 35 | /// 36 | /// This operator uses deferred execution and streams its results. 37 | /// 38 | /// 39 | /// 43 | /// The result variable, when iterated over, will yield 1, 3 and 5, in turn. 44 | /// 45 | 46 | public static IEnumerable TakeEvery(this IEnumerable source, int step) 47 | { 48 | if (source == null) throw new ArgumentNullException(nameof(source)); 49 | if (step <= 0) throw new ArgumentOutOfRangeException(nameof(step)); 50 | return source.Where((_, i) => i % step == 0); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /MoreLinq/TakeLast.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Linq; 22 | using System.Collections.Generic; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a specified number of contiguous elements from the end of 28 | /// a sequence. 29 | /// 30 | /// The type of the elements of . 31 | /// The sequence to return the last element of. 32 | /// The number of elements to return. 33 | /// 34 | /// An that contains the specified number of 35 | /// elements from the end of the input sequence. 36 | /// 37 | /// 38 | /// This operator uses deferred execution and streams its results. 39 | /// 40 | /// 41 | /// 45 | /// The result variable, when iterated over, will yield 46 | /// 56 and 78 in turn. 47 | /// 48 | 49 | #if NETSTANDARD2_1 || NETCOREAPP2_0_OR_GREATER 50 | public static IEnumerable TakeLast(IEnumerable source, int count) 51 | #else 52 | public static IEnumerable TakeLast(this IEnumerable source, int count) 53 | #endif 54 | { 55 | if (source == null) throw new ArgumentNullException(nameof(source)); 56 | 57 | return count < 1 ? [] 58 | : source.CountDown(count, (e, cd) => (Element: e, Countdown: cd)) 59 | .SkipWhile(e => e.Countdown == null) 60 | .Select(e => e.Element); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MoreLinq/ToDelimitedString.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Text; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Creates a delimited string from a sequence of values and 28 | /// a given delimiter. 29 | /// 30 | /// Type of element in the source sequence 31 | /// The sequence of items to delimit. Each is converted to a string using the 32 | /// simple ToString() conversion. 33 | /// The delimiter to inject between elements. 34 | /// 35 | /// A string that consists of the elements in 36 | /// delimited by . If the source sequence 37 | /// is empty, the method returns an empty string. 38 | /// 39 | /// 40 | /// or is null. 41 | /// 42 | /// 43 | /// This operator uses immediate execution and effectively buffers the sequence. 44 | /// 45 | 46 | public static string ToDelimitedString(this IEnumerable source, string delimiter) 47 | { 48 | if (source == null) throw new ArgumentNullException(nameof(source)); 49 | if (delimiter == null) throw new ArgumentNullException(nameof(delimiter)); 50 | return ToDelimitedStringImpl(source, delimiter, (sb, e) => sb.Append(e)); 51 | } 52 | 53 | static string ToDelimitedStringImpl(IEnumerable source, string delimiter, Func append) 54 | { 55 | var sb = new StringBuilder(); 56 | var i = 0; 57 | 58 | foreach (var value in source) 59 | { 60 | if (i++ > 0) 61 | _ = sb.Append(delimiter); 62 | _ = append(sb, value); 63 | } 64 | 65 | return sb.ToString(); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /MoreLinq/UnreachableException.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) .NET Foundation and Contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | #endregion 26 | 27 | #if NET7_0_OR_GREATER 28 | 29 | global using UnreachableException = System.Diagnostics.UnreachableException; 30 | 31 | #else 32 | 33 | namespace MoreLinq 34 | { 35 | using System; 36 | 37 | // Source: https://github.com/dotnet/runtime/blob/v7.0.2/src/libraries/System.Private.CoreLib/src/System/Diagnostics/UnreachableException.cs 38 | 39 | /// 40 | /// Exception thrown when the program executes an instruction that was thought to be unreachable. 41 | /// 42 | 43 | #if !NETSTANDARD1_0 44 | [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] 45 | #endif 46 | #pragma warning disable CA1064 // Exceptions should be public 47 | sealed class UnreachableException : Exception 48 | #pragma warning restore CA1064 // Exceptions should be public 49 | { 50 | public UnreachableException() : 51 | this(null) { } 52 | 53 | public UnreachableException(string? message) : 54 | base(message, null) { } 55 | 56 | public UnreachableException(string? message, Exception? innerException) : 57 | base(message ?? "The program executed an instruction that was thought to be unreachable.", 58 | innerException) { } 59 | } 60 | } 61 | 62 | #endif // NET7_0_OR_GREATER 63 | -------------------------------------------------------------------------------- /MoreLinq/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morelinq/MoreLINQ/c386fd3a94e05dd9566a2e576e22687baae2b652/MoreLinq/key.snk -------------------------------------------------------------------------------- /MoreLinq/tt.cmd: -------------------------------------------------------------------------------- 1 | @dotnet build "%~dp0MoreLinq.csproj" -t:TransformTextTemplates %* 2 | -------------------------------------------------------------------------------- /MoreLinq/tt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | cd "$(dirname "$0")" 4 | dotnet build -t:TransformTextTemplates "$@" 5 | -------------------------------------------------------------------------------- /bld/Copyright.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | © 2008 Jonathan Skeet. 5 | Portions © 2009 Atif Aziz, Chris Ammerman, Konrad Rudolph. 6 | Portions © 2010 Johannes Rudolph, Leopold Bushkin. 7 | Portions © 2015 Felipe Sateler, “sholland”. 8 | Portions © 2016 Andreas Gullberg Larsen, Leandro F. Vieira (leandromoh). 9 | Portions © 2017 Jonas Nyrup (jnyrup). 10 | Portions © 2023 Julien Aspirot (julienasp). 11 | Portions © 2024 Andy Romero (armorynode). 12 | Portions © Microsoft. All rights reserved. 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /bld/ExtensionsGenerator/.editorconfig: -------------------------------------------------------------------------------- 1 | [ProgramArguments.cs] 2 | dotnet_analyzer_diagnostic.category-Style.severity = suggestion 3 | -------------------------------------------------------------------------------- /bld/ExtensionsGenerator/MoreLinq.ExtensionsGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net9.0 5 | false 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | pushd "%~dp0" 3 | call :main %* 4 | popd & exit /b %ERRORLEVEL% 5 | 6 | :main 7 | setlocal 8 | set MSBUILDTERMINALLOGGER=off 9 | for %%i in (dotnet.exe) do set dotnet=%%~dpnx$PATH:i 10 | if "%dotnet%"=="" goto :nodotnet 11 | if "%1"=="docs" shift & goto :docs 12 | :build 13 | dotnet restore && dotnet tool restore ^ 14 | && call :codegen MoreLinq\Extensions.g.cs -x "[/\\]ToDataTable\.cs$" -u System.Linq -u System.Collections MoreLinq ^ 15 | && call :codegen MoreLinq\Extensions.ToDataTable.g.cs -i "[/\\]ToDataTable\.cs$" -u System.Data -u System.Linq.Expressions MoreLinq ^ 16 | && call MoreLinq\tt ^ 17 | && for %%i in (debug release) do dotnet build -c %%i --no-restore %* || exit /b 1 18 | exit /b %ERRORLEVEL% 19 | 20 | :docs 21 | call :build && call msbuild.cmd MoreLinq.shfbproj %1 %2 %3 %4 %5 %6 %7 %8 %9 22 | exit /b %ERRORLEVEL% 23 | 24 | :nodotnet 25 | echo>&2 dotnet executable not found in PATH 26 | echo>&2 For more on dotnet, see https://www.microsoft.com/net/core 27 | exit /b 2 28 | 29 | :codegen 30 | echo | set /p=Generating extensions wrappers (%1)... 31 | dotnet build bld\ExtensionsGenerator\MoreLinq.ExtensionsGenerator.csproj -c Release >build.log 2>&1 || ( 32 | echo Failed! 33 | type build.log 34 | del build.log 35 | exit /b 1 36 | ) 37 | del build.log 38 | dotnet bld\ExtensionsGenerator\bin\Release\MoreLinq.ExtensionsGenerator.dll %2 %3 %4 %5 %6 %7 %8 %9 > "%temp%\%~nx1" ^ 39 | && move "%temp%\%~nx1" "%~dp1" > nul ^ 40 | && echo Done. 41 | exit /b %ERRORLEVEL% 42 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | cd "$(dirname "$0")" 4 | export MSBUILDTERMINALLOGGER=off 5 | dotnet restore 6 | dotnet tool restore 7 | codegen() { 8 | dest="$1" 9 | printf "Generating extensions wrappers (%s)..." "$1" 10 | shift 11 | dotnet build bld/ExtensionsGenerator/MoreLinq.ExtensionsGenerator.csproj -c Release >build.log || ( 12 | printf "Failed!\n" 13 | cat build.log 14 | rm build.log 15 | exit 1 16 | ) 17 | dotnet bld/ExtensionsGenerator/bin/Release/MoreLinq.ExtensionsGenerator.dll "$@" > "$dest" 18 | printf "Done.\n" 19 | } 20 | codegen MoreLinq/Extensions.g.cs -x "[/\\\\]ToDataTable\.cs$" -u System.Linq -u System.Collections MoreLinq 21 | codegen MoreLinq/Extensions.ToDataTable.g.cs -i "[/\\\\]ToDataTable\.cs$" -u System.Data -u System.Linq.Expressions MoreLinq 22 | MoreLinq/tt.sh 23 | if [[ -z "$1" ]]; then 24 | configs="Debug Release" 25 | else 26 | configs="$1" 27 | fi 28 | for c in $configs; do 29 | dotnet build --no-restore -c $c 30 | done 31 | -------------------------------------------------------------------------------- /builddocs.cmd: -------------------------------------------------------------------------------- 1 | @call "%~dp0build" docs 2 | -------------------------------------------------------------------------------- /eclint.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(DefaultParameterSetName='Default')] 2 | param ( 3 | [Parameter(ParameterSetName='Default')] 4 | [switch]$TrimTrailingWhitespace, 5 | [Parameter(ParameterSetName='Default')] 6 | [switch]$InsertFinalNewline, 7 | 8 | [Parameter(Mandatory=$true, ParameterSetName='ShowGlob')] 9 | [switch]$ShowGlob 10 | ) 11 | 12 | $ErrorActionPreference = 'Stop' 13 | 14 | $exts = 15 | git ls-files --eol | # get versioned file paths with line endings 16 | ? { $_ -notmatch '/-text\b' } | # exclude binary files 17 | % { ($_ -split '\t', 2)[1] } | # get file path 18 | Split-Path -Extension | # get file extension 19 | ? { $_.Length -gt 1 } | # exclude those without an extension 20 | Sort-Object | # sort alphabetically 21 | Select-Object -Unique | # remove duplicates 22 | % { $_.Substring(1) } # remove leading dot 23 | 24 | $glob = "**/*.{$($exts -join ',')}" 25 | 26 | if ($PSCmdlet.ParameterSetName -eq 'ShowGlob') { 27 | Write-Output $glob 28 | return 29 | } 30 | 31 | if (-not (Get-Command eclint -ErrorAction SilentlyContinue)) { 32 | throw 'ECLint is not installed. To install, run: npm install -g eclint' 33 | } 34 | 35 | $rules = @() 36 | 37 | if ($trimTrailingWhitespace) { 38 | $rules += '--trim_trailing_whitespace' 39 | } 40 | 41 | if ($insertFinalNewline) { 42 | $rules += '--insert_final_newline' 43 | } 44 | 45 | $rules | % { 46 | 47 | Write-Verbose "eclint check $rule $glob" 48 | 49 | # https://github.com/jednano/eclint 50 | eclint check $_ $glob 51 | 52 | if ($LASTEXITCODE) { 53 | throw "eclint terminated with a non-zero exit code ($LASTEXITCODE)." 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.300", 4 | "rollForward": "latestPatch" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /msbuild.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | for %%e in (Community Professional Enterprise) do ( 4 | if exist "%ProgramFiles%\Microsoft Visual Studio\2022\%%e\MSBuild\Current\Bin\MSBuild.exe" ( 5 | set "MSBUILD=%ProgramFiles%\Microsoft Visual Studio\2022\%%e\MSBuild\Current\Bin\MSBuild.exe" 6 | ) 7 | ) 8 | if exist "%MSBUILD%" goto :build 9 | set MSBUILD= 10 | for %%i in (MSBuild.exe) do set MSBUILD=%%~dpnx$PATH:i 11 | if not defined MSBUILD goto :nomsbuild 12 | set MSBUILD_VERSION_MAJOR= 13 | set MSBUILD_VERSION_MINOR= 14 | for /f "delims=. tokens=1,2,3,4" %%m in ('msbuild /version /nologo') do ( 15 | set MSBUILD_VERSION_MAJOR=%%m 16 | ) 17 | if not defined MSBUILD_VERSION_MAJOR goto :nomsbuild 18 | if %MSBUILD_VERSION_MAJOR% lss 17 goto :nomsbuild 19 | :build 20 | "%MSBUILD%" %* 21 | exit /b %ERRORLEVEL% 22 | 23 | :nomsbuild 24 | echo>&2 Microsoft Build Engine 17.0 or a later version is required to build 25 | echo>&2 the solution. For installation instructions, see: 26 | echo>&2 https://docs.microsoft.com/en-us/visualstudio/install/use-command-line-parameters-to-install-visual-studio 27 | echo>&2 At the very least, you will want to install the MSBuilt Tool workload 28 | echo>&2 that has the identifier "Microsoft.VisualStudio.Workload.MSBuildTools": 29 | echo>&2 https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools#msbuild-tools 30 | exit /b 1 31 | -------------------------------------------------------------------------------- /pack.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | pushd "%~dp0" 3 | call :main %* 4 | popd & exit /b %ERRORLEVEL% 5 | 6 | :main 7 | setlocal 8 | if not exist dist md dist 9 | if not %ERRORLEVEL%==0 exit /b %ERRORLEVEL% 10 | set VERSION_SUFFIX= 11 | if not "%~1"=="" set VERSION_SUFFIX=/p:VersionSuffix=%1 12 | call build ^ 13 | && dotnet pack --no-build -c Release %VERSION_SUFFIX% 14 | exit /b %ERRORLEVEL% 15 | -------------------------------------------------------------------------------- /pack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | cd "$(dirname "$0")" 4 | VERSION_SUFFIX= 5 | if [ ! -z "$1" ]; then VERSION_SUFFIX="--version-suffix $1"; fi 6 | ./build.sh 7 | if [ ! -d dist ]; then mkdir dist; fi 8 | dotnet pack --no-build -c Release $VERSION_SUFFIX 9 | -------------------------------------------------------------------------------- /test.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | pushd "%~dp0" 3 | call :main %* 4 | popd & exit /b %ERRORLEVEL% 5 | 6 | :main 7 | setlocal 8 | if not defined SKIP_TEST_BUILD set SKIP_TEST_BUILD=false 9 | if %SKIP_TEST_BUILD%==false call build || exit /b 1 10 | if not "%~1"=="aot" goto :test-all 11 | call :test-aot net8.0 && call :test-aot net9.0 12 | exit /b %ERRORLEVEL% 13 | :test-all 14 | call :clean ^ 15 | && call :test net9.0 Debug ^ 16 | && call :test net9.0 Release ^ 17 | && call :test net8.0 Debug ^ 18 | && call :test net8.0 Release ^ 19 | && call :test net471 Debug ^ 20 | && call :test net471 Release ^ 21 | && call :report-cover ^ 22 | && call :test-aot net8.0 ^ 23 | && call :test-aot net9.0 24 | exit /b %ERRORLEVEL% 25 | 26 | :clean 27 | setlocal 28 | cd MoreLinq.Test 29 | if exist TestResults rd /s /q TestResults || exit /b 1 30 | if exist TestResult.xml del TestResult.xml || exit /b 1 31 | exit /b %ERRORLEVEL% 32 | 33 | :test 34 | setlocal 35 | cd MoreLinq.Test 36 | echo Testing %1 (%2)... 37 | if %1==net471 ( 38 | bin\%2\net471\MoreLinq.Test.exe 39 | exit /b %ERRORLEVEL% 40 | ) 41 | dotnet test --no-build -f %1 -c %2 --settings coverlet.runsettings || exit /b 1 42 | cd TestResults 43 | set TEST_RESULTS_DIR= 44 | for /f %%d in ('dir /b /od /ad') do if not defined TEST_RESULTS_DIR set TEST_RESULTS_DIR=%%~d 45 | if not defined TEST_RESULTS_DIR ( 46 | echo>&2 Test coverage XML not found! 47 | exit /b 1 48 | ) 49 | copy "%TEST_RESULTS_DIR%\coverage.opencover.xml" coverage-%1-%2.opencover.xml > nul 50 | exit /b %ERRORLEVEL% 51 | 52 | :report-cover 53 | setlocal 54 | cd MoreLinq.Test\TestResults 55 | dotnet reportgenerator -reports:coverage-*.opencover.xml ^ 56 | -reporttypes:Html;TextSummary ^ 57 | -targetdir:reports ^ 58 | && type reports\Summary.txt 59 | exit /b %ERRORLEVEL% 60 | 61 | :test-aot 62 | setlocal 63 | cd MoreLinq.Test.Aot 64 | dotnet publish -f %1 65 | if not ERRORLEVEL==0 exit /b %ERRORLEVEL% 66 | set AOT_TEST_PUBLISH_DIR= 67 | for /f %%d in ('cmd /c "dir /ad /s /b publish | findstr /c:%1"') do if not defined AOT_TEST_PUBLISH_DIR set AOT_TEST_PUBLISH_DIR=%%~d 68 | if not defined AOT_TEST_PUBLISH_DIR ( 69 | echo>&2 Published binary directory not found! 70 | exit /b 1 71 | ) 72 | "%AOT_TEST_PUBLISH_DIR%\MoreLinq.Test.Aot.exe" 73 | exit /b %ERRORLEVEL% 74 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | cd "$(dirname "$0")" 4 | if [[ "${SKIP_TEST_BUILD:=false}" == "false" ]]; then 5 | ./build.sh $c 6 | fi 7 | if [[ -d "MoreLinq.Test/TestResults" ]]; then 8 | rm -rf MoreLinq.Test/TestResults 9 | fi 10 | if [[ -z "$1" ]]; then 11 | configs="Debug Release" 12 | else 13 | configs="$1" 14 | fi 15 | for f in net8.0 net9.0; do 16 | for c in $configs; do 17 | dotnet test --no-build -c $c -f $f --settings MoreLinq.Test/coverlet.runsettings MoreLinq.Test 18 | TEST_RESULTS_DIR="$(ls -dc MoreLinq.Test/TestResults/* | head -1)" 19 | cp "$TEST_RESULTS_DIR/coverage.opencover.xml" "MoreLinq.Test/TestResults/coverage-$f-$c.opencover.xml" 20 | done 21 | done 22 | dotnet reportgenerator -reports:MoreLinq.Test/TestResults/coverage-*.opencover.xml \ 23 | -reporttypes:Html\;TextSummary \ 24 | -targetdir:MoreLinq.Test/TestResults/reports 25 | cat MoreLinq.Test/TestResults/reports/Summary.txt 26 | for f in net8.0 net9.0; do 27 | dotnet publish -f $f MoreLinq.Test.Aot 28 | "$(find MoreLinq.Test.Aot -type d -name publish | grep -F $f)/MoreLinq.Test.Aot" 29 | done 30 | -------------------------------------------------------------------------------- /tools/mark-shipped.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | dotnet pwsh -NoProfile -ExecutionPolicy RemoteSigned -File "%~dpn0.ps1" 3 | -------------------------------------------------------------------------------- /tools/mark-shipped.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(PositionalBinding=$false)] 2 | param () 3 | 4 | Set-StrictMode -Version 2.0 5 | $ErrorActionPreference = 'Stop' 6 | 7 | function MarkShipped([string]$dir) 8 | { 9 | $shippedFilePath = Join-Path $dir 'PublicAPI.Shipped.txt' 10 | [array]$shipped = Get-Content $shippedFilePath 11 | 12 | $unshippedFilePath = Join-Path $dir 'PublicAPI.Unshipped.txt' 13 | [array]$unshipped = Get-Content $unshippedFilePath | ? { $_ -and $_ -notmatch '^#' } 14 | 15 | $removed = @() 16 | $removedPrefix = '*REMOVED*'; 17 | Write-Verbose "Processing $dir" 18 | 19 | foreach ($item in $unshipped) 20 | { 21 | if ($item.StartsWith($removedPrefix)) 22 | { 23 | $item = $item.Substring($removedPrefix.Length) 24 | $removed += $item 25 | } 26 | else 27 | { 28 | $shipped += $item 29 | } 30 | } 31 | 32 | $shipped | 33 | Sort-Object | 34 | ? { -not $removed.Contains($_) } | 35 | Out-File $shippedFilePath -Encoding Ascii 36 | 37 | '#nullable enable' | Out-File $unshippedFilePath -Encoding Ascii 38 | } 39 | 40 | foreach ($file in Get-ChildItem -re -in 'PublicApi.Shipped.txt') 41 | { 42 | $dir = Split-Path -parent $file 43 | MarkShipped $dir 44 | } 45 | --------------------------------------------------------------------------------