Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
<Compile Include="System.Linq.AsyncEnumerable.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
<Compile Include="SystemLinq.AsyncEnumerable.netcore.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'">
<ProjectReference Include="$(LibrariesProjectRoot)System.Linq/ref/System.Linq.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Runtime/ref/System.Runtime.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// ------------------------------------------------------------------------------
// Changes to this file must follow the https://aka.ms/api-review process.
// ------------------------------------------------------------------------------

namespace System.Linq
{
public static partial class AsyncEnumerable
{
public static System.Collections.Generic.IAsyncEnumerable<T> InfiniteSequence<T>(T start, T step) where T : System.Numerics.IAdditionOperators<T, T, T> { throw null; }
public static System.Collections.Generic.IAsyncEnumerable<T> Sequence<T>(T start, T endInclusive, T step) where T : System.Numerics.INumber<T> { throw null; }
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
Expand All @@ -18,71 +18,76 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="System\Linq\Shuffle.cs" />
<Compile Include="System\Linq\SkipLast.cs" />
<Compile Include="System\Linq\SkipWhile.cs" />
<Compile Include="System\Linq\Append.cs" />
<Compile Include="System\Linq\Empty.cs" />
<Compile Include="System\Linq\MaxByAsync.cs" />
<Compile Include="System\Linq\MinAsync.cs" />
<Compile Include="System\Linq\Cast.cs" />
<Compile Include="System\Linq\AsyncEnumerable.cs" />
<Compile Include="System\Linq\TakeLast.cs" />
<Compile Include="System\Linq\TakeWhile.cs" />
<Compile Include="System\Linq\UnionBy.cs" />
<Compile Include="System\Linq\AggregateAsync.cs" />
<Compile Include="System\Linq\AnyAsync.cs" />
<Compile Include="System\Linq\AggregateBy.cs" />
<Compile Include="System\Linq\AllAsync.cs" />
<Compile Include="System\Linq\Prepend.cs" />
<Compile Include="System\Linq\AnyAsync.cs" />
<Compile Include="System\Linq\Append.cs" />
<Compile Include="System\Linq\AsyncEnumerable.cs" />
<Compile Include="System\Linq\AverageAsync.cs" />
<Compile Include="System\Linq\Cast.cs" />
<Compile Include="System\Linq\Chunk.cs" />
<Compile Include="System\Linq\Concat.cs" />
<Compile Include="System\Linq\ContainsAsync.cs" />
<Compile Include="System\Linq\AggregateBy.cs" />
<Compile Include="System\Linq\CountBy.cs" />
<Compile Include="System\Linq\CountAsync.cs" />
<Compile Include="System\Linq\CountBy.cs" />
<Compile Include="System\Linq\DefaultIfEmpty.cs" />
<Compile Include="System\Linq\DistinctBy.cs" />
<Compile Include="System\Linq\Distinct.cs" />
<Compile Include="System\Linq\DistinctBy.cs" />
<Compile Include="System\Linq\ElementAtAsync.cs" />
<Compile Include="System\Linq\ToAsyncEnumerable.cs" />
<Compile Include="System\Linq\ExceptBy.cs" />
<Compile Include="System\Linq\Empty.cs" />
<Compile Include="System\Linq\Except.cs" />
<Compile Include="System\Linq\ExceptBy.cs" />
<Compile Include="System\Linq\FirstAsync.cs" />
<Compile Include="System\Linq\GroupBy.cs" />
<Compile Include="System\Linq\GroupJoin.cs" />
<Compile Include="System\Linq\Index.cs" />
<Compile Include="System\Linq\IntersectBy.cs" />
<Compile Include="System\Linq\Intersect.cs" />
<Compile Include="System\Linq\IntersectBy.cs" />
<Compile Include="System\Linq\Join.cs" />
<Compile Include="System\Linq\LastAsync.cs" />
<Compile Include="System\Linq\LeftJoin.cs" />
<Compile Include="System\Linq\ToArrayAsync.cs" />
<Compile Include="System\Linq\ToDictionaryAsync.cs" />
<Compile Include="System\Linq\ToListAsync.cs" />
<Compile Include="System\Linq\ToLookupAsync.cs" />
<Compile Include="System\Linq\MaxAsync.cs" />
<Compile Include="System\Linq\MaxByAsync.cs" />
<Compile Include="System\Linq\MinAsync.cs" />
<Compile Include="System\Linq\MinByAsync.cs" />
<Compile Include="System\Linq\OfType.cs" />
<Compile Include="System\Linq\OrderBy.cs" />
<Compile Include="System\Linq\Prepend.cs" />
<Compile Include="System\Linq\Range.cs" />
<Compile Include="System\Linq\Repeat.cs" />
<Compile Include="System\Linq\Reverse.cs" />
<Compile Include="System\Linq\RightJoin.cs" />
<Compile Include="System\Linq\Select.cs" />
<Compile Include="System\Linq\SelectMany.cs" />
<Compile Include="System\Linq\SequenceEqualAsync.cs" />
<Compile Include="System\Linq\Shuffle.cs" />
<Compile Include="System\Linq\SingleAsync.cs" />
<Compile Include="System\Linq\Skip.cs" />
<Compile Include="System\Linq\SkipLast.cs" />
<Compile Include="System\Linq\SkipWhile.cs" />
<Compile Include="System\Linq\SumAsync.cs" />
<Compile Include="System\Linq\Take.cs" />
<Compile Include="System\Linq\TakeLast.cs" />
<Compile Include="System\Linq\TakeWhile.cs" />
<Compile Include="System\Linq\ThrowHelper.cs" />
<Compile Include="System\Linq\ToArrayAsync.cs" />
<Compile Include="System\Linq\ToAsyncEnumerable.cs" />
<Compile Include="System\Linq\ToDictionaryAsync.cs" />
<Compile Include="System\Linq\ToHashSetAsync.cs" />
<Compile Include="System\Linq\ToListAsync.cs" />
<Compile Include="System\Linq\ToLookupAsync.cs" />
<Compile Include="System\Linq\Union.cs" />
<Compile Include="System\Linq\UnionBy.cs" />
<Compile Include="System\Linq\Where.cs" />
<Compile Include="System\Linq\Zip.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
<Compile Include="System\Linq\InfiniteSequence.cs" />
<Compile Include="System\Linq\Sequence.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'">
<Reference Include="System.Collections" />
<Reference Include="System.Linq" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Linq
{
public static partial class AsyncEnumerable
{
/// <summary>Generates an infinite sequence that begins with <paramref name="start"/> and yields additional values each incremented by <paramref name="step"/>.</summary>
/// <typeparam name="T">The type of the value to be yielded in the result sequence.</typeparam>
/// <param name="start">The starting value.</param>
/// <param name="step">The amount by which the next yielded value should be incremented from the previous yielded value.</param>
/// <returns>An <see cref="IAsyncEnumerable{T}"/> that contains the sequence.</returns>
public static IAsyncEnumerable<T> InfiniteSequence<T>(T start, T step) where T : IAdditionOperators<T, T, T>
{
if (start is null)
{
ThrowHelper.ThrowArgumentNullException(nameof(start));
}

if (step is null)
{
ThrowHelper.ThrowArgumentNullException(nameof(step));
}

return Iterator(start, step);

static async IAsyncEnumerable<T> Iterator(T start, T step)
{
while (true)
{
yield return start;
start += step;
}
}
}
}
}
130 changes: 130 additions & 0 deletions src/libraries/System.Linq.AsyncEnumerable/src/System/Linq/Sequence.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Linq
{
public static partial class AsyncEnumerable
{
/// <summary>Generates a sequence that begins with <paramref name="start"/> and yields additional values each incremented by <paramref name="step"/> until <paramref name="endInclusive"/> is reached.</summary>
/// <typeparam name="T">The type of the value to be yielded in the result sequence.</typeparam>
/// <param name="start">The starting value. This value will always be included in the resulting sequence.</param>
/// <param name="endInclusive">The ending bound beyond which values will not be included in the sequence.</param>
/// <param name="step">The amount by which the next value in the sequence should be incremented from the previous value.</param>
/// <returns>An <see cref="IAsyncEnumerable{T}"/> that contains the sequence.</returns>
/// <exception cref="ArgumentNullException"><paramref name="start"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="step"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="endInclusive"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="step"/> is greater than zero but <paramref name="endInclusive"/> is less than <paramref name="start"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="step"/> is less than zero but <paramref name="endInclusive"/> is greater than <paramref name="start"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="step"/> is zero and <paramref name="endInclusive"/> does not equal <paramref name="start"/>.</exception>
public static IAsyncEnumerable<T> Sequence<T>(T start, T endInclusive, T step) where T : INumber<T>
{
if (start is null)
{
ThrowHelper.ThrowArgumentNullException(nameof(start));
}

if (endInclusive is null)
{
ThrowHelper.ThrowArgumentNullException(nameof(endInclusive));
}

if (step is null)
{
ThrowHelper.ThrowArgumentNullException(nameof(step));
}

if (step > T.Zero)
{
// Presumed to be the most common case, step > 0. Validate that endInclusive >= start, as otherwise we can't easily
// guarantee that the sequence will terminate.
if (endInclusive < start)
{
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(endInclusive));
}

// Otherwise, just produce an incrementing sequence.
return IncrementingIterator(start, endInclusive, step);
}
else if (step < T.Zero)
{
// step < 0. Validate that endInclusive <= start, as otherwise we can't easily guarantee that the sequence will terminate.
if (endInclusive > start)
{
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(endInclusive));
}

// Then produce the decrementing sequence.
return DecrementingIterator(start, endInclusive, step);
}
else
{
// step == 0. If start != endInclusive, then the sequence would be infinite. As such, we validate
// that they're equal, and if they are, we return a sequence that yields the start/endInclusive value once.
if (start != endInclusive)
{
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(step));
}

return Repeat(start, 1);
}

static async IAsyncEnumerable<T> IncrementingIterator(T start, T endInclusive, T step)
{
Debug.Assert(step > T.Zero);

yield return start;

while (true)
{
T next = start + step;

if (next >= endInclusive || next <= start)
{
if (next == endInclusive && start != next)
{
yield return next;
}

yield break;
}

yield return next;
start = next;
}
}


static async IAsyncEnumerable<T> DecrementingIterator(T start, T endInclusive, T step)
{
Debug.Assert(step < T.Zero);

yield return start;

while (true)
{
T next = start + step;

if (next <= endInclusive || next >= start)
{
if (next == endInclusive && start != next)
{
yield return next;
}

yield break;
}

yield return next;
start = next;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ internal static void ThrowIfNegativeOrZero(int value, [CallerArgumentExpression(
}
}

[DoesNotReturn]
internal static void ThrowArgumentNullException(string paramName) => throw new ArgumentNullException(paramName);

[DoesNotReturn]
internal static void ThrowArgumentOutOfRangeException(string paramName) => throw new ArgumentOutOfRangeException(paramName);

Expand Down
Loading
Loading