// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace System.Linq
{
public static partial class AsyncEnumerable
{
///
/// Generates an async-enumerable sequence of integral numbers within a specified range.
///
/// The value of the first integer in the sequence.
/// The number of sequential integers to generate.
/// An async-enumerable sequence that contains a range of sequential integral numbers.
/// is less than zero. -or- + - 1 is larger than .
public static IAsyncEnumerable Range(int start, int count)
{
if (count < 0)
throw Error.ArgumentOutOfRange(nameof(count));
var end = (long)start + count - 1L;
if (end > int.MaxValue)
throw Error.ArgumentOutOfRange(nameof(count));
if (count == 0)
return Empty();
return new RangeAsyncIterator(start, count);
}
private sealed class RangeAsyncIterator : AsyncIterator, IAsyncPartition
{
private readonly int _start;
private readonly int _end;
public RangeAsyncIterator(int start, int count)
{
Debug.Assert(count > 0);
_start = start;
_end = start + count;
}
public override AsyncIteratorBase Clone() => new RangeAsyncIterator(_start, _end - _start);
public ValueTask GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken) => new ValueTask(_end - _start);
public IAsyncPartition Skip(int count)
{
var n = _end - _start;
if (count >= n)
{
return EmptyAsyncIterator.Instance;
}
return new RangeAsyncIterator(_start + count, n - count);
}
public IAsyncPartition Take(int count)
{
var n = _end - _start;
if (count >= n)
{
return this;
}
return new RangeAsyncIterator(_start, count);
}
public ValueTask ToArrayAsync(CancellationToken cancellationToken)
{
var res = new int[_end - _start];
var value = _start;
for (var i = 0; i < res.Length; i++)
{
res[i] = value++;
}
return new ValueTask(res);
}
public ValueTask> ToListAsync(CancellationToken cancellationToken)
{
var res = new List(_end - _start);
for (var value = _start; value < _end; value++)
{
res.Add(value);
}
return new ValueTask>(res);
}
public ValueTask> TryGetElementAtAsync(int index, CancellationToken cancellationToken)
{
if ((uint)index < (uint)(_end - _start))
{
return new ValueTask>(new Maybe(_start + index));
}
return new ValueTask>(new Maybe());
}
public ValueTask> TryGetFirstAsync(CancellationToken cancellationToken) => new ValueTask>(new Maybe(_start));
public ValueTask> TryGetLastAsync(CancellationToken cancellationToken) => new ValueTask>(new Maybe(_end - 1));
protected override ValueTask MoveNextCore()
{
switch (_state)
{
case AsyncIteratorState.Allocated:
_current = _start;
_state = AsyncIteratorState.Iterating;
return new ValueTask(true);
case AsyncIteratorState.Iterating:
_current++;
if (_current != _end)
{
return new ValueTask(true);
}
break;
}
return Core();
async ValueTask Core()
{
await DisposeAsync().ConfigureAwait(false);
return false;
}
}
}
}
}