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
32 changes: 28 additions & 4 deletions src/Polyfill/EnumerablePolyfill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,52 @@ public static IEnumerable<T> InfiniteSequence<T>(T start, T step)
public static IEnumerable<T> Sequence<T>(T start, T endInclusive, T step)
where T : INumber<T>
{
if (T.IsPositive(step))
if (T.IsNaN(start))
{
throw new ArgumentOutOfRangeException(nameof(start));
}

if (T.IsNaN(endInclusive))
{
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}

if (T.IsNaN(step))
{
throw new ArgumentOutOfRangeException(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)
{
throw new ArgumentOutOfRangeException("endInclusive < start");
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}

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)
{
throw new ArgumentOutOfRangeException("endInclusive > start");
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}

return DecrementingIterator(start, endInclusive, step);
}

// step == 0. The sequence can only terminate when there is a single value to yield.
if (start != endInclusive)
{
throw new ArgumentOutOfRangeException(nameof(step));
}

return Enumerable.Repeat(start, 1);

static IEnumerable<T> IncrementingIterator(T current, T endInclusive, T step)
{
yield return current;
Expand Down
25 changes: 21 additions & 4 deletions src/Split/net7.0/EnumerablePolyfill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,39 @@ public static IEnumerable<T> InfiniteSequence<T>(T start, T step)
public static IEnumerable<T> Sequence<T>(T start, T endInclusive, T step)
where T : INumber<T>
{
if (T.IsPositive(step))
if (T.IsNaN(start))
{
throw new ArgumentOutOfRangeException(nameof(start));
}
if (T.IsNaN(endInclusive))
{
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}
if (T.IsNaN(step))
{
throw new ArgumentOutOfRangeException(nameof(step));
}
if (step > T.Zero)
{
if (endInclusive < start)
{
throw new ArgumentOutOfRangeException("endInclusive < start");
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}
return IncrementingIterator(start, endInclusive, step);
}
else
if (step < T.Zero)
{
if (endInclusive > start)
{
throw new ArgumentOutOfRangeException("endInclusive > start");
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}
return DecrementingIterator(start, endInclusive, step);
}
if (start != endInclusive)
{
throw new ArgumentOutOfRangeException(nameof(step));
}
return Enumerable.Repeat(start, 1);
static IEnumerable<T> IncrementingIterator(T current, T endInclusive, T step)
{
yield return current;
Expand Down
25 changes: 21 additions & 4 deletions src/Split/net8.0/EnumerablePolyfill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,39 @@ public static IEnumerable<T> InfiniteSequence<T>(T start, T step)
public static IEnumerable<T> Sequence<T>(T start, T endInclusive, T step)
where T : INumber<T>
{
if (T.IsPositive(step))
if (T.IsNaN(start))
{
throw new ArgumentOutOfRangeException(nameof(start));
}
if (T.IsNaN(endInclusive))
{
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}
if (T.IsNaN(step))
{
throw new ArgumentOutOfRangeException(nameof(step));
}
if (step > T.Zero)
{
if (endInclusive < start)
{
throw new ArgumentOutOfRangeException("endInclusive < start");
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}
return IncrementingIterator(start, endInclusive, step);
}
else
if (step < T.Zero)
{
if (endInclusive > start)
{
throw new ArgumentOutOfRangeException("endInclusive > start");
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}
return DecrementingIterator(start, endInclusive, step);
}
if (start != endInclusive)
{
throw new ArgumentOutOfRangeException(nameof(step));
}
return Enumerable.Repeat(start, 1);
static IEnumerable<T> IncrementingIterator(T current, T endInclusive, T step)
{
yield return current;
Expand Down
25 changes: 21 additions & 4 deletions src/Split/net9.0/EnumerablePolyfill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,39 @@ public static IEnumerable<T> InfiniteSequence<T>(T start, T step)
public static IEnumerable<T> Sequence<T>(T start, T endInclusive, T step)
where T : INumber<T>
{
if (T.IsPositive(step))
if (T.IsNaN(start))
{
throw new ArgumentOutOfRangeException(nameof(start));
}
if (T.IsNaN(endInclusive))
{
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}
if (T.IsNaN(step))
{
throw new ArgumentOutOfRangeException(nameof(step));
}
if (step > T.Zero)
{
if (endInclusive < start)
{
throw new ArgumentOutOfRangeException("endInclusive < start");
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}
return IncrementingIterator(start, endInclusive, step);
}
else
if (step < T.Zero)
{
if (endInclusive > start)
{
throw new ArgumentOutOfRangeException("endInclusive > start");
throw new ArgumentOutOfRangeException(nameof(endInclusive));
}
return DecrementingIterator(start, endInclusive, step);
}
if (start != endInclusive)
{
throw new ArgumentOutOfRangeException(nameof(step));
}
return Enumerable.Repeat(start, 1);
static IEnumerable<T> IncrementingIterator(T current, T endInclusive, T step)
{
yield return current;
Expand Down
49 changes: 49 additions & 0 deletions src/Tests/PolyfillTests_IEnumerable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,55 @@ public async Task Sequence_Throws_WhenStepPositiveAndEndLessThanStart() =>
public async Task Sequence_Throws_WhenStepNegativeAndEndGreaterThanStart() =>
await Assert.That(() => Enumerable.Sequence(1, 5, -1).ToList()).Throws<ArgumentOutOfRangeException>();

// The argument checks are not deferred, so no enumeration is needed (or wanted: a NaN used to give an endless sequence)
[Test]
public async Task Sequence_Throws_WhenStartIsNaN()
{
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => Enumerable.Sequence(double.NaN, 1d, 1d));
await Assert.That(exception.ParamName).IsEqualTo("start");
}

[Test]
public async Task Sequence_Throws_WhenEndIsNaN()
{
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => Enumerable.Sequence(0d, double.NaN, 1d));
await Assert.That(exception.ParamName).IsEqualTo("endInclusive");
}

[Test]
public async Task Sequence_Throws_WhenStepIsNaN()
{
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => Enumerable.Sequence(0d, 1d, double.NaN));
await Assert.That(exception.ParamName).IsEqualTo("step");
}

[Test]
public async Task Sequence_Throws_WhenStepIsZeroAndStartNotEqualToEnd()
{
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => Enumerable.Sequence(1, 5, 0));
await Assert.That(exception.ParamName).IsEqualTo("step");

exception = Assert.Throws<ArgumentOutOfRangeException>(() => Enumerable.Sequence(1d, 5d, -0d));
await Assert.That(exception.ParamName).IsEqualTo("step");
}

[Test]
public async Task Sequence_SingleValue_WhenStepIsZeroAndStartEqualsEnd()
{
var result = Enumerable.Sequence(3, 3, 0).ToList();
await Assert.That(result.SequenceEqual(new[] {3})).IsTrue();
}

[Test]
public async Task Sequence_Throws_WithParamName_WhenEndOnWrongSideOfStart()
{
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => Enumerable.Sequence(5, 1, 1));
await Assert.That(exception.ParamName).IsEqualTo("endInclusive");

exception = Assert.Throws<ArgumentOutOfRangeException>(() => Enumerable.Sequence(1, 5, -1));
await Assert.That(exception.ParamName).IsEqualTo("endInclusive");
}

#endif

[Test]
Expand Down
Loading