diff --git a/src/libraries/Common/tests/System/IO/VirtualDriveHelper.Windows.cs b/src/libraries/Common/tests/System/IO/VirtualDriveHelper.Windows.cs index 9a221a2488c7c1..66198579eb52b0 100644 --- a/src/libraries/Common/tests/System/IO/VirtualDriveHelper.Windows.cs +++ b/src/libraries/Common/tests/System/IO/VirtualDriveHelper.Windows.cs @@ -87,7 +87,7 @@ char GetNextAvailableDriveLetter() List existingDrives = DriveInfo.GetDrives().Select(x => x.Name[0]).ToList(); // A,B are reserved, C is usually reserved - IEnumerable range = Enumerable.Range('D', 'Z' - 'D'); + IEnumerable range = Enumerable.Range('D', 'Z' - 'D'); IEnumerable castRange = range.Select(x => Convert.ToChar(x)); IEnumerable allDrivesLetters = castRange.Except(existingDrives); @@ -145,4 +145,4 @@ private static string SubstPath } } } -} \ No newline at end of file +} diff --git a/src/libraries/System.Linq.AsyncEnumerable/ref/System.Linq.AsyncEnumerable.csproj b/src/libraries/System.Linq.AsyncEnumerable/ref/System.Linq.AsyncEnumerable.csproj index b8f3303989b913..b2939090a3c05e 100644 --- a/src/libraries/System.Linq.AsyncEnumerable/ref/System.Linq.AsyncEnumerable.csproj +++ b/src/libraries/System.Linq.AsyncEnumerable/ref/System.Linq.AsyncEnumerable.csproj @@ -7,6 +7,10 @@ + + + + diff --git a/src/libraries/System.Linq.AsyncEnumerable/ref/System.Linq.AsyncEnumerable.netcore.cs b/src/libraries/System.Linq.AsyncEnumerable/ref/System.Linq.AsyncEnumerable.netcore.cs new file mode 100644 index 00000000000000..8bf512e0f51d1f --- /dev/null +++ b/src/libraries/System.Linq.AsyncEnumerable/ref/System.Linq.AsyncEnumerable.netcore.cs @@ -0,0 +1,13 @@ +// 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 Range(T start, int count) where T : System.Numerics.IBinaryInteger { throw null; } + } +} diff --git a/src/libraries/System.Linq.AsyncEnumerable/src/System.Linq.AsyncEnumerable.csproj b/src/libraries/System.Linq.AsyncEnumerable/src/System.Linq.AsyncEnumerable.csproj index 65d7a694bb6a54..c35ec7bdd450a4 100644 --- a/src/libraries/System.Linq.AsyncEnumerable/src/System.Linq.AsyncEnumerable.csproj +++ b/src/libraries/System.Linq.AsyncEnumerable/src/System.Linq.AsyncEnumerable.csproj @@ -76,6 +76,10 @@ + + + + diff --git a/src/libraries/System.Linq.AsyncEnumerable/src/System/Linq/Range.netcore.cs b/src/libraries/System.Linq.AsyncEnumerable/src/System/Linq/Range.netcore.cs new file mode 100644 index 00000000000000..14eb7248248674 --- /dev/null +++ b/src/libraries/System.Linq.AsyncEnumerable/src/System/Linq/Range.netcore.cs @@ -0,0 +1,55 @@ +// 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.Numerics; + +namespace System.Linq +{ + public static partial class AsyncEnumerable + { + /// Generates a sequence of integral numbers within a specified range. + /// The type of the elements in the sequence. + /// The value of the first in the sequence. + /// The number of sequential to generate. + /// An that contains a range of sequential integral numbers. + /// is less than 0 + /// + -1 is larger than . + public static IAsyncEnumerable Range(T start, int count) where T : IBinaryInteger + { + if (count == 0) + { + return Empty(); + } + + if (count < 0) + { + ThrowHelper.ThrowArgumentOutOfRangeException(nameof(count)); + } + + T max = start + T.CreateTruncating(count - 1); + if (start > max || StartMaxCount(start, max) + 1 != count) + { + ThrowHelper.ThrowArgumentOutOfRangeException(nameof(count)); + } + + return Impl(start, count); + + static async IAsyncEnumerable Impl(T start, int count) + { + for (int i = 0; i < count; i++, start++) + { + yield return start; + } + } + + static int StartMaxCount(T start, T max) + { + int count = int.CreateTruncating(max - start); + if (count < 0) + count = int.CreateTruncating(max) - int.CreateTruncating(start); + return count; + } + } + } +} diff --git a/src/libraries/System.Linq.AsyncEnumerable/tests/RangeTests.cs b/src/libraries/System.Linq.AsyncEnumerable/tests/RangeTests.cs index 75413ef13fc7c4..5e2e5fdfda9368 100644 --- a/src/libraries/System.Linq.AsyncEnumerable/tests/RangeTests.cs +++ b/src/libraries/System.Linq.AsyncEnumerable/tests/RangeTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Numerics; using System.Threading.Tasks; using Xunit; @@ -12,14 +13,30 @@ public class RangeTests : AsyncEnumerableTests public void InvalidInputs_Throws() { AssertExtensions.Throws("count", () => AsyncEnumerable.Range(-1, -1)); - AssertExtensions.Throws("count", () => AsyncEnumerable.Range(-1, -1)); + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(2, int.MaxValue)); AssertExtensions.Throws("count", () => AsyncEnumerable.Range(int.MaxValue - 1, 3)); + +#if NET + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(-1, -1)); + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(2, int.MaxValue)); + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(int.MaxValue - 1, 3)); + + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(255, -1)); + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(2, byte.MaxValue)); + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(byte.MaxValue - 1, 3)); + + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(-1, -1)); + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(long.MaxValue - int.MaxValue + 2, int.MaxValue)); + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(long.MaxValue - 1, 3)); + + AssertExtensions.Throws("count", () => AsyncEnumerable.Range(-1, -1)); +#endif } [Fact] public async Task VariousValues_MatchesEnumerable() { - foreach (int start in new[] { int.MinValue, -1, 0, 1, 1_000_000 }) + foreach (int start in new[] { int.MinValue, -1, 0, 1, int.MaxValue - 9 }) { foreach (int count in new[] { 0, 1, 3, 10 }) { @@ -28,6 +45,53 @@ await AssertEqual( AsyncEnumerable.Range(start, count)); } } + +#if NET + foreach (int start in new[] { int.MinValue, -1, 0, 1, int.MaxValue - 9 }) + { + foreach (int count in new[] { 0, 1, 3, 10 }) + { + await AssertEqual( + Enumerable.Range(start, count), + AsyncEnumerable.Range(start, count)); + } + } + + foreach (byte start in new[] { byte.MinValue, 1, byte.MaxValue - 9 }) + { + foreach (int count in new[] { 0, 1, 3, 10 }) + { + await AssertEqual( + Enumerable.Range(start, count), + AsyncEnumerable.Range(start, count)); + } + } + + foreach (long start in new[] { long.MinValue, -1, 0, 1, long.MaxValue - 9 }) + { + foreach (int count in new[] { 0, 1, 3, 10 }) + { + await AssertEqual( + Enumerable.Range(start, count), + AsyncEnumerable.Range(start, count)); + } + } + + foreach (BigInteger start in new[] { -BigInteger.Pow(2, 1024), -1, 0, 1, BigInteger.Pow(2, 1024) }) + { + foreach (int count in new[] { 0, 1, 3, 10 }) + { + await AssertEqual( + Enumerable.Range(start, count), + AsyncEnumerable.Range(start, count)); + } + + await AssertEqual( + Enumerable.Range(start, int.MaxValue).Skip(10).Take(10), + AsyncEnumerable.Range(start, int.MaxValue).Skip(10).Take(10)); + } + +#endif } } } diff --git a/src/libraries/System.Linq/ref/System.Linq.cs b/src/libraries/System.Linq/ref/System.Linq.cs index 20682db0deb76f..2c1e2f97d5190f 100644 --- a/src/libraries/System.Linq/ref/System.Linq.cs +++ b/src/libraries/System.Linq/ref/System.Linq.cs @@ -159,6 +159,7 @@ public static System.Collections.Generic.IEnumerable< public static System.Linq.IOrderedEnumerable Order(this System.Collections.Generic.IEnumerable source, System.Collections.Generic.IComparer? comparer) { throw null; } public static System.Collections.Generic.IEnumerable Prepend(this System.Collections.Generic.IEnumerable source, TSource element) { throw null; } public static System.Collections.Generic.IEnumerable Range(int start, int count) { throw null; } + public static System.Collections.Generic.IEnumerable Range(T start, int count) where T : System.Numerics.IBinaryInteger { throw null; } public static System.Collections.Generic.IEnumerable Repeat(TResult element, int count) { throw null; } public static System.Collections.Generic.IEnumerable Reverse(this System.Collections.Generic.IEnumerable source) { throw null; } public static System.Collections.Generic.IEnumerable Reverse(this TSource[] source) { throw null; } diff --git a/src/libraries/System.Linq/src/System/Linq/Range.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/Range.SpeedOpt.cs index 41d1336018bd33..cee9d9d3d8622c 100644 --- a/src/libraries/System.Linq/src/System/Linq/Range.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/Range.SpeedOpt.cs @@ -2,113 +2,115 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; namespace System.Linq { public static partial class Enumerable { - private sealed partial class RangeIterator : IList, IReadOnlyList + private sealed partial class RangeIterator : IList, IReadOnlyList { - public override IEnumerable Select(Func selector) + public override IEnumerable Select(Func selector) { - return new RangeSelectIterator(_start, _end, selector); + return new RangeSelectIterator(_start, _end, selector); } - public override int[] ToArray() + public override T[] ToArray() { - int start = _start; - int[] array = new int[_end - start]; + T start = _start; + T[] array = new T[Count]; FillIncrementing(array, start); return array; } - public override List ToList() + public override List ToList() { - (int start, int end) = (_start, _end); - List list = new List(end - start); - FillIncrementing(SetCountAndGetSpan(list, end - start), start); + int count = Count; + List list = new List(count); + FillIncrementing(SetCountAndGetSpan(list, count), _start); return list; } - public void CopyTo(int[] array, int arrayIndex) => - FillIncrementing(array.AsSpan(arrayIndex, _end - _start), _start); + public void CopyTo(T[] array, int arrayIndex) => + FillIncrementing(array.AsSpan(arrayIndex, Count), _start); - public override int GetCount(bool onlyIfCheap) => _end - _start; + public override int GetCount(bool onlyIfCheap) => Count; - public int Count => _end - _start; + public int Count => _count; - public override Iterator? Skip(int count) + public override Iterator? Skip(int count) { - if (count >= _end - _start) + Debug.Assert(count > 0); + if (count >= Count) { return null; } - return new RangeIterator(_start + count, _end - _start - count); + return new RangeIterator(_start + T.CreateTruncating(count), Count - count); } - public override Iterator Take(int count) + public override Iterator? Take(int count) { - int curCount = _end - _start; - if (count >= curCount) + Debug.Assert(count > 0); + if (count >= Count) { return this; } - return new RangeIterator(_start, count); + return new RangeIterator(_start, count); } - public override int TryGetElementAt(int index, out bool found) + public override T TryGetElementAt(int index, out bool found) { - if ((uint)index < (uint)(_end - _start)) + if ((uint)index < (uint)Count) { found = true; - return _start + index; + return _start + T.CreateTruncating(index); } found = false; - return 0; + return T.Zero; } - public override int TryGetFirst(out bool found) + public override T TryGetFirst(out bool found) { found = true; return _start; } - public override int TryGetLast(out bool found) + public override T TryGetLast(out bool found) { found = true; - return _end - 1; + return _end - T.One; } - public bool Contains(int item) => - (uint)(item - _start) < (uint)(_end - _start); + public bool Contains(T item) => + _start <= item && item <= _end - T.One; // _start can be equal to _end - public int IndexOf(int item) => - Contains(item) ? item - _start : -1; + public int IndexOf(T item) => + Contains(item) ? StartMaxCount(_start, item) : -1; - public int this[int index] + public T this[int index] { get { - if ((uint)index >= (uint)(_end - _start)) + if ((uint)index >= (uint)Count) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index); } - return _start + index; + return _start + T.CreateTruncating(index); } set => ThrowHelper.ThrowNotSupportedException(); } public bool IsReadOnly => true; - void ICollection.Add(int item) => ThrowHelper.ThrowNotSupportedException(); - void ICollection.Clear() => ThrowHelper.ThrowNotSupportedException(); - void IList.Insert(int index, int item) => ThrowHelper.ThrowNotSupportedException(); - bool ICollection.Remove(int item) => ThrowHelper.ThrowNotSupportedException_Boolean(); - void IList.RemoveAt(int index) => ThrowHelper.ThrowNotSupportedException(); + void ICollection.Add(T item) => ThrowHelper.ThrowNotSupportedException(); + void ICollection.Clear() => ThrowHelper.ThrowNotSupportedException(); + void IList.Insert(int index, T item) => ThrowHelper.ThrowNotSupportedException(); + bool ICollection.Remove(T item) => ThrowHelper.ThrowNotSupportedException_Boolean(); + void IList.RemoveAt(int index) => ThrowHelper.ThrowNotSupportedException(); } } } diff --git a/src/libraries/System.Linq/src/System/Linq/Range.cs b/src/libraries/System.Linq/src/System/Linq/Range.cs index 1bf57b0e520d01..f998967ce834ce 100644 --- a/src/libraries/System.Linq/src/System/Linq/Range.cs +++ b/src/libraries/System.Linq/src/System/Linq/Range.cs @@ -24,35 +24,70 @@ public static IEnumerable Range(int start, int count) return []; } - return new RangeIterator(start, count); + return new RangeIterator(start, count); + } + + /// Generates a sequence of integral numbers within a specified range. + /// The type of the elements in the sequence. + /// The value of the first in the sequence. + /// The number of sequential to generate. + /// An that contains a range of sequential integral numbers. + /// is less than 0 + /// + -1 is larger than . + public static IEnumerable Range(T start, int count) where T : IBinaryInteger + { + if (count < 0) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count); + } + + if (count == 0) + { + return []; + } + + T max = start + T.CreateTruncating(count - 1); + if (start > max || RangeIterator.StartMaxCount(start, max) + 1 != count) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count); + } + + return new RangeIterator(start, count); } /// /// An iterator that yields a range of consecutive integers. /// [DebuggerDisplay("Count = {CountForDebugger}")] - private sealed partial class RangeIterator : Iterator + private sealed partial class RangeIterator : Iterator where T : IBinaryInteger { - private readonly int _start; - private readonly int _end; + // _start can be equal to _end + // _start <= _end - T.One + private readonly T _start; + private readonly T _end; + private readonly int _count; - public RangeIterator(int start, int count) + public RangeIterator(T start, int count) { Debug.Assert(count > 0); + Debug.Assert(start <= start + T.CreateTruncating(count - 1)); + Debug.Assert(StartMaxCount(start, start + T.CreateTruncating(count - 1)) + 1 == count); + _start = start; - _end = start + count; + _end = start + T.CreateTruncating(count); + _count = count; } - private int CountForDebugger => _end - _start; + private int CountForDebugger => _count; // Count(_start, _end - T.One) + 1; - private protected override Iterator Clone() => new RangeIterator(_start, _end - _start); + private protected override Iterator Clone() => new RangeIterator(_start, _count); public override bool MoveNext() { switch (_state) { case 1: - Debug.Assert(_start != _end); + Debug.Assert(_start <= _end - T.One); // _start can be equal to _end _current = _start; _state = 2; return true; @@ -73,27 +108,33 @@ public override void Dispose() { _state = -1; // Don't reset current } + + internal static int StartMaxCount(T start, T max) + { + int count = int.CreateTruncating(max - start); + if (count < 0) + count = int.CreateTruncating(max) - int.CreateTruncating(start); + return count; + } } /// Fills the with incrementing numbers, starting from . - private static void FillIncrementing(Span destination, int value) + private static void FillIncrementing(Span destination, T value) where T : IBinaryInteger { - ref int pos = ref MemoryMarshal.GetReference(destination); - ref int end = ref Unsafe.Add(ref pos, destination.Length); + ref T pos = ref MemoryMarshal.GetReference(destination); + ref T end = ref Unsafe.Add(ref pos, destination.Length); - if (Vector.IsHardwareAccelerated && - destination.Length >= Vector.Count) + if (Vector.IsHardwareAccelerated && Vector.IsSupported && destination.Length >= Vector.Count) { - Vector init = Vector.Indices; - Vector current = new Vector(value) + init; - Vector increment = new Vector(Vector.Count); + Vector current = new Vector(value) + Vector.Indices; + Vector increment = new Vector(T.CreateTruncating(Vector.Count)); - ref int oneVectorFromEnd = ref Unsafe.Subtract(ref end, Vector.Count); + ref T oneVectorFromEnd = ref Unsafe.Subtract(ref end, Vector.Count); do { current.StoreUnsafe(ref pos); current += increment; - pos = ref Unsafe.Add(ref pos, Vector.Count); + pos = ref Unsafe.Add(ref pos, Vector.Count); } while (!Unsafe.IsAddressGreaterThan(ref pos, ref oneVectorFromEnd)); diff --git a/src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs index 91e936adc6c7e5..8f3d031deaeb47 100644 --- a/src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.CompilerServices; +using System.Numerics; using System.Runtime.InteropServices; using static System.Linq.Utilities; @@ -233,46 +233,50 @@ public override TResult TryGetLast(out bool found) } } - private sealed partial class RangeSelectIterator : Iterator + private sealed partial class RangeSelectIterator : Iterator where T : IBinaryInteger { - private readonly int _start; - private readonly int _end; - private readonly Func _selector; + // _start can be equal to _end + // _start <= _end - T.One + private readonly T _start; + private readonly T _end; + private readonly int _count; + private readonly Func _selector; - public RangeSelectIterator(int start, int end, Func selector) + public RangeSelectIterator(T start, T end, Func selector) { - Debug.Assert(start < end); - Debug.Assert((uint)(end - start) <= (uint)int.MaxValue); + Debug.Assert(start <= end - T.One); // _start can be equal to _end + Debug.Assert((uint)RangeIterator.StartMaxCount(start, end - T.One) + 1 <= (uint)int.MaxValue); Debug.Assert(selector is not null); _start = start; _end = end; + _count = RangeIterator.StartMaxCount(start, end - T.One) + 1; _selector = selector; } private protected override Iterator Clone() => - new RangeSelectIterator(_start, _end, _selector); + new RangeSelectIterator(_start, _end, _selector); public override bool MoveNext() { - if (_state < 1 || _state == (_end - _start + 1)) + if (_state < 1 || _state == _count + 1) { Dispose(); return false; } int index = _state++ - 1; - Debug.Assert(_start < _end - index); - _current = _selector(_start + index); + Debug.Assert(index < _count); + _current = _selector(_start + T.CreateTruncating(index)); return true; } public override IEnumerable Select(Func selector) => - new RangeSelectIterator(_start, _end, CombineSelectors(_selector, selector)); + new RangeSelectIterator(_start, _end, CombineSelectors(_selector, selector)); public override TResult[] ToArray() { - var results = new TResult[_end - _start]; + var results = new TResult[_count]; Fill(results, _start, _selector); return results; @@ -280,13 +284,13 @@ public override TResult[] ToArray() public override List ToList() { - var results = new List(_end - _start); - Fill(SetCountAndGetSpan(results, _end - _start), _start, _selector); + var results = new List(_count); + Fill(SetCountAndGetSpan(results, _count), _start, _selector); return results; } - private static void Fill(Span results, int start, Func func) + private static void Fill(Span results, T start, Func func) { for (int i = 0; i < results.Length; i++, start++) { @@ -300,45 +304,47 @@ public override int GetCount(bool onlyIfCheap) // run it provided `onlyIfCheap` is false. if (!onlyIfCheap) { - for (int i = _start; i != _end; i++) + T i = _start; // for (T i = _start; i != _end; i++) can not be used because _start can be equal to _end + do { _selector(i); } + while (++i != _end); } - return _end - _start; + return _count; } public override Iterator? Skip(int count) { Debug.Assert(count > 0); - if (count >= (_end - _start)) + if (count >= _count) { return null; } - return new RangeSelectIterator(_start + count, _end, _selector); + return new RangeSelectIterator(_start + T.CreateTruncating(count), _end, _selector); } public override Iterator Take(int count) { Debug.Assert(count > 0); - if (count >= (_end - _start)) + if (count >= _count) { return this; } - return new RangeSelectIterator(_start, _start + count, _selector); + return new RangeSelectIterator(_start, _start + T.CreateTruncating(count), _selector); } public override TResult? TryGetElementAt(int index, out bool found) { - if ((uint)index < (uint)(_end - _start)) + if ((uint)index < (uint)(_count)) { found = true; - return _selector(_start + index); + return _selector(_start + T.CreateTruncating(index)); } found = false; @@ -347,16 +353,16 @@ public override Iterator Take(int count) public override TResult TryGetFirst(out bool found) { - Debug.Assert(_end > _start); + Debug.Assert(_end - T.One >= _start); // _start can be equal to _end found = true; return _selector(_start); } public override TResult TryGetLast(out bool found) { - Debug.Assert(_end > _start); + Debug.Assert(_end - T.One >= _start); // _start can be equal to _end found = true; - return _selector(_end - 1); + return _selector(_end - T.One); } } diff --git a/src/libraries/System.Linq/tests/RangeIBinaryIntegerTests.cs b/src/libraries/System.Linq/tests/RangeIBinaryIntegerTests.cs new file mode 100644 index 00000000000000..ed52b0d838f7f7 --- /dev/null +++ b/src/libraries/System.Linq/tests/RangeIBinaryIntegerTests.cs @@ -0,0 +1,1089 @@ +// 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.Numerics; +using Xunit; + +namespace System.Linq.Tests +{ + public abstract class RangeIBinaryIntegerTests : EnumerableTests where T : IBinaryInteger + { +#pragma warning disable xUnit1015 + + //public static TheoryData StartCountCorrectData; + //public static TheoryData StartCountIncorrectData; + + [Theory] + [MemberData("StartCountCorrectData")] + public void Range_ProduceCorrectSequence(T start, int count) + { + var range = Enumerable.Range(start, count); + + TestCorrectRangeResult(range, start, count); + + Assert.Equal(range, Enumerable.Range(start, count)); + + // Not enumerate after the end + using (var enumerator = range.GetEnumerator()) + { + for (var i = 0; i < count; i++) + Assert.True(enumerator.MoveNext()); + for (var i = 0; i < 100; i++) + Assert.False(enumerator.MoveNext()); + } + } + + [Theory] + [MemberData("StartCountIncorrectData")] + public void Range_IncorrectStartCount(T start, int count) + { + Assert.Throws("count", () => Enumerable.Range(start, count)); + TestCorrectRangeResult(Enumerable.Range(start, 0), start, 0); + TestCorrectRangeResult(Enumerable.Range(start, 1), start, 1); + } + + [Theory] + [MemberData("StartCountCorrectData")] + public void Range_GetEnumeratorSame(T start, int count) + { + var range = Enumerable.Range(start, count); + if (count <= 0) + { + Assert.IsType(range); + return; + } + + using (var enumerator = range.GetEnumerator()) + { + Assert.Same(range, enumerator); + } + } + + [Theory] + [MemberData("StartCountCorrectData")] + public void Range_GetEnumeratorUnique(T start, int count) + { + var range = Enumerable.Range(start, count); + if (count <= 0) + { + Assert.IsType(range); + return; + } + + using (var enum1 = range.GetEnumerator()) + using (var enum2 = range.GetEnumerator()) + { + Assert.NotSame(enum1, enum2); + } + } + + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsSpeedOptimized))] + [MemberData("StartCountCorrectData")] + public void Range_SpeedOpt(T start, int count) + { + var range = Enumerable.Range(start, count); + TestCorrectSpeedOptRange(range, start, count); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsSpeedOptimized))] + [MemberData("StartCountCorrectData")] + public void Range_Skip(T start, int count) + { + var range = Enumerable.Range(start, count).Skip(count / 2); + start += T.CreateTruncating(count / 2); + count -= count / 2; + TestCorrectSpeedOptRange(range, start, count); + + if (count > 1) + { + TestCorrectSpeedOptRange(range.Skip(count - 1), start + T.CreateTruncating(count - 1), 1); + TestCorrectSpeedOptRange(range.Take(1), start, 1); + } + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsSpeedOptimized))] + [MemberData("StartCountCorrectData")] + public void Range_Take(T start, int count) + { + var range = Enumerable.Range(start, count).Take(count / 2); + count = count / 2; + TestCorrectSpeedOptRange(range, start, count); + + if (count > 1) + { + TestCorrectSpeedOptRange(range.Skip(count - 1), start + T.CreateTruncating(count - 1), 1); + TestCorrectSpeedOptRange(range.Take(1), start, 1); + } + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsSpeedOptimized))] + [MemberData("StartCountCorrectData")] + public void Range_IListImplementationIsValid(T start, int count) + { + var range = Enumerable.Range(start, count); + if (count <= 0) + { + Assert.IsType(range); + return; + + } + + var expected = range.ToArray(); + IList list = Assert.IsAssignableFrom>(range); + IReadOnlyList roList = Assert.IsAssignableFrom>(range); + + Assert.Throws(() => list.Add(default)); + Assert.Throws(() => list.Insert(0, default)); + Assert.Throws(list.Clear); + Assert.Throws(() => list.Remove(default)); + Assert.Throws(() => list.RemoveAt(0)); + Assert.Throws(() => list[0] = default); + AssertExtensions.Throws("index", () => list[-1]); + AssertExtensions.Throws("index", () => list[expected.Length]); + AssertExtensions.Throws("index", () => roList[-1]); + AssertExtensions.Throws("index", () => roList[expected.Length]); + + Assert.True(list.IsReadOnly); + Assert.Equal(expected.Length, list.Count); + Assert.Equal(expected.Length, roList.Count); + + if (expected.Length > 0) + { + if (expected[0] - T.One < expected[0]) + { + Assert.False(list.Contains(expected[0] - T.One)); + Assert.False(roList.Contains(expected[0] - T.One)); + + Assert.Equal(-1, list.IndexOf(expected[0] - T.One)); + //Assert.Equal(-1, roList.IndexOf(expected[0] - T.One)); + } + + if (expected[^1] + T.One > expected[^1]) + { + Assert.False(list.Contains(expected[^1] + T.One)); + Assert.False(roList.Contains(expected[^1] + T.One)); + + Assert.Equal(-1, list.IndexOf(expected[^1] + T.One)); + //Assert.Equal(-1, roList.IndexOf(expected[^1] + T.One)); + } + } + else + { + Assert.False(list.Contains(default)); + Assert.False(roList.Contains(default)); + + Assert.Equal(-1, list.IndexOf(default)); + //Assert.Equal(-1, roList.IndexOf(default)); + } + + Assert.All(expected, item => Assert.True(list.Contains(item))); + Assert.All(expected, item => Assert.True(roList.Contains(item))); + + Assert.All(expected, item => Assert.Equal(Array.IndexOf(expected, item), list.IndexOf(item))); + //Assert.All(expected, item => Assert.Equal(Array.IndexOf(expected, item), roList.IndexOf(item))); + + for (int i = 0; i < expected.Length; i++) + { + Assert.Equal(expected[i], list[i]); + Assert.Equal(expected[i], roList[i]); + } + + T[] actual = new T[expected.Length + 2]; + list.CopyTo(actual, 1); + Assert.Equal(default, actual[0]); + Assert.Equal(default, actual[^1]); + Assert.Equal(expected, actual.AsSpan(1, expected.Length)); + } + + private void TestCorrectRangeResult(IEnumerable rangeResult, T expectedStart, int expectedCount) + { + T expected = expectedStart; + int count = 0; + foreach (var val in rangeResult) + { + Assert.Equal(expected, val); + expected++; + count++; + } + Assert.Equal(expectedCount, count); + Assert.Equal(expectedCount, rangeResult.Count()); + } + + private void TestCorrectSpeedOptRange(IEnumerable range, T expectedStart, int expectedCount) + { + TestCorrectRangeResult(range, expectedStart, expectedCount); + + { + var select1 = range.Select(item => item - expectedStart); + // Should be first after creating + if (expectedCount <= 0) + { + Assert.IsType(select1); + } + else + { + using (var enum1 = select1.GetEnumerator()) + using (var enum2 = select1.GetEnumerator()) + { + Assert.Same(select1, enum1); + Assert.NotSame(enum1, enum2); + } + } + + TestCorrectRangeSelect(select1, T.Zero, expectedCount); + + var select2 = select1.Select(item => item - expectedStart); + // Should be first after creating + if (expectedCount <= 0) + { + Assert.IsType(select2); + } + else + { + using (var enum1 = select2.GetEnumerator()) + using (var enum2 = select2.GetEnumerator()) + { + Assert.Same(select2, enum1); + Assert.NotSame(enum1, enum2); + } + } + + TestCorrectRangeSelect(select2, T.Zero - expectedStart, expectedCount); + + TestCorrectRangeSelect(select2.Skip(expectedCount / 2), T.Zero - expectedStart + T.CreateTruncating(expectedCount / 2), expectedCount - expectedCount / 2); + TestCorrectRangeSelect(select2.Take(expectedCount / 2), T.Zero - expectedStart, expectedCount / 2); + + if (expectedCount > 1) + { + TestCorrectRangeSelect(select2.Skip(expectedCount - 1), T.Zero - expectedStart + T.CreateTruncating(expectedCount - 1), 1); + TestCorrectRangeSelect(select2.Take(1), T.Zero - expectedStart, 1); + } + } + + TestCorrectRangeResult(range.ToArray(), expectedStart, expectedCount); + TestCorrectRangeResult(range.ToList(), expectedStart, expectedCount); + + if (expectedCount == 0) + { + Assert.Empty(range); + + Assert.Equal(default, range.FirstOrDefault()); + Assert.Equal(default, range.LastOrDefault()); + Assert.Equal(expectedStart - T.One, range.FirstOrDefault(expectedStart - T.One)); + Assert.Equal(expectedStart - T.One, range.LastOrDefault(expectedStart - T.One)); + } + else + { + if (expectedCount == 1) + Assert.Single(range); + + Assert.Contains(expectedStart, range); + Assert.Contains(expectedStart + T.CreateTruncating(expectedCount / 2), range); + Assert.Contains(expectedStart + T.CreateTruncating(expectedCount - 1), range); + + Assert.Equal(expectedStart, range.ElementAt(0)); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount / 2), range.ElementAt(expectedCount / 2)); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), range.ElementAt(expectedCount - 1)); + + Assert.Equal(expectedStart, range.ElementAtOrDefault(0)); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount / 2), range.ElementAtOrDefault(expectedCount / 2)); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), range.ElementAtOrDefault(expectedCount - 1)); + + Assert.Equal(expectedStart, range.First()); + Assert.Equal(expectedStart, range.FirstOrDefault()); + Assert.Equal(expectedStart, range.FirstOrDefault(expectedStart - T.One)); + + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), range.Last()); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), range.LastOrDefault()); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), range.LastOrDefault(expectedStart - T.One)); + } + + Assert.Same(range, range.Skip(0)); + Assert.Same(range, range.Skip(-1)); + Assert.Same(range, range.Skip(int.MinValue)); + Assert.Empty(range.Skip(expectedCount)); + Assert.Empty(range.Skip(expectedCount + 1)); + Assert.Empty(range.Skip(int.MaxValue)); + + Assert.Same(range, range.Take(expectedCount)); + Assert.Same(range, range.Take(expectedCount + 1)); + Assert.Same(range, range.Take(int.MaxValue)); + Assert.Empty(range.Take(0)); + Assert.Empty(range.Take(-1)); + Assert.Empty(range.Take(int.MinValue)); + + if (expectedStart - T.One < expectedStart) + Assert.DoesNotContain(expectedStart - T.One, range); + if (expectedStart + T.CreateTruncating(expectedCount) > expectedStart) + Assert.DoesNotContain(expectedStart + T.CreateTruncating(expectedCount), range); + + Assert.Equal(default, range.ElementAtOrDefault(-1)); + Assert.Equal(default, range.ElementAtOrDefault(int.MinValue)); + Assert.Equal(default, range.ElementAtOrDefault(expectedCount)); + Assert.Equal(default, range.ElementAtOrDefault(int.MaxValue)); + + AssertExtensions.Throws("index", () => range.ElementAt(-1)); + AssertExtensions.Throws("index", () => range.ElementAt(int.MinValue)); + AssertExtensions.Throws("index", () => range.ElementAt(expectedCount)); + AssertExtensions.Throws("index", () => range.ElementAt(int.MaxValue)); + } + + private void TestCorrectRangeSelect(IEnumerable select, T expectedStart, int expectedCount) + { + TestCorrectRangeResult(select, expectedStart, expectedCount); + TestCorrectRangeResult(select.ToArray(), expectedStart, expectedCount); + TestCorrectRangeResult(select.ToList(), expectedStart, expectedCount); + + if (expectedCount == 0) + { + Assert.Empty(select); + + Assert.Equal(default, select.FirstOrDefault()); + Assert.Equal(default, select.LastOrDefault()); + Assert.Equal(expectedStart - T.One, select.FirstOrDefault(expectedStart - T.One)); + Assert.Equal(expectedStart - T.One, select.LastOrDefault(expectedStart - T.One)); + } + else + { + if (expectedCount == 1) + Assert.Single(select); + + Assert.Equal(expectedStart, select.ElementAt(0)); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount / 2), select.ElementAt(expectedCount / 2)); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), select.ElementAt(expectedCount - 1)); + + Assert.Equal(expectedStart, select.ElementAtOrDefault(0)); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount / 2), select.ElementAtOrDefault(expectedCount / 2)); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), select.ElementAtOrDefault(expectedCount - 1)); + + Assert.Equal(expectedStart, select.First()); + Assert.Equal(expectedStart, select.FirstOrDefault()); + Assert.Equal(expectedStart, select.FirstOrDefault(expectedStart - T.One)); + + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), select.Last()); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), select.LastOrDefault()); + Assert.Equal(expectedStart + T.CreateTruncating(expectedCount - 1), select.LastOrDefault(expectedStart - T.One)); + } + + Assert.Same(select, select.Skip(0)); + Assert.Same(select, select.Skip(-1)); + Assert.Same(select, select.Skip(int.MinValue)); + Assert.Empty(select.Skip(expectedCount)); + Assert.Empty(select.Skip(expectedCount + 1)); + Assert.Empty(select.Skip(int.MaxValue)); + + Assert.Same(select, select.Take(expectedCount)); + Assert.Same(select, select.Take(expectedCount + 1)); + Assert.Same(select, select.Take(int.MaxValue)); + Assert.Empty(select.Take(0)); + Assert.Empty(select.Take(-1)); + Assert.Empty(select.Take(int.MinValue)); + + Assert.Equal(default, select.ElementAtOrDefault(-1)); + Assert.Equal(default, select.ElementAtOrDefault(int.MinValue)); + Assert.Equal(default, select.ElementAtOrDefault(expectedCount)); + Assert.Equal(default, select.ElementAtOrDefault(int.MaxValue)); + + AssertExtensions.Throws("index", () => select.ElementAt(-1)); + AssertExtensions.Throws("index", () => select.ElementAt(int.MinValue)); + AssertExtensions.Throws("index", () => select.ElementAt(expectedCount)); + AssertExtensions.Throws("index", () => select.ElementAt(int.MaxValue)); + + } + +#pragma warning restore xUnit1015 + } + + public class RangeByteTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { 0, 256 }, + { 0, 15 }, + { 0, 1 }, + { 0, 0 }, + + { 63, 256 - 63 }, + { 63, 15 }, + { 63, 1 }, + { 63, 0 }, + + { 128, 128 }, + { 128, 15 }, + { 128, 1 }, + { 128, 0 }, + + { 255 - 14, 15 }, + { 255, 1 }, + { 255, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { 0, byte.MaxValue + 2 }, + { 0, byte.MaxValue + 64 }, + { 0, byte.MaxValue + 128 }, + { 0, byte.MaxValue + 172 }, + { 0, byte.MaxValue + byte.MaxValue }, + { 0, int.MaxValue }, + { 0, -1 }, + { 0, int.MinValue }, + + { 1, byte.MaxValue + 1 }, + { 1, byte.MaxValue + 64 }, + { 1, byte.MaxValue + 128 }, + { 1, byte.MaxValue + 172 }, + { 1, byte.MaxValue + byte.MaxValue }, + { 1, int.MaxValue }, + { 1, -1 }, + { 1, int.MinValue }, + + { 127, 130 }, + { 127, byte.MaxValue + 64 }, + { 127, byte.MaxValue + 128 }, + { 127, byte.MaxValue + 172 }, + { 127, byte.MaxValue + byte.MaxValue }, + { 127, int.MaxValue }, + { 127, -1 }, + { 127, int.MinValue }, + + { 128, 129 }, + { 128, byte.MaxValue + 64 }, + { 128, byte.MaxValue + 128 }, + { 128, byte.MaxValue + 172 }, + { 128, byte.MaxValue + byte.MaxValue }, + { 128, int.MaxValue }, + { 128, -1 }, + { 128, int.MinValue }, + + { 129, 128 }, + { 129, byte.MaxValue + 64 }, + { 129, byte.MaxValue + 128 }, + { 129, byte.MaxValue + 172 }, + { 129, byte.MaxValue + byte.MaxValue }, + { 129, int.MaxValue }, + { 129, -1 }, + { 129, int.MinValue }, + + { 254, 3 }, + { 254, byte.MaxValue + 64 }, + { 254, byte.MaxValue + 128 }, + { 254, byte.MaxValue + 172 }, + { 254, byte.MaxValue + byte.MaxValue }, + { 254, int.MaxValue }, + { 254, -1 }, + { 254, int.MinValue }, + + { 255, 2 }, + { 255, byte.MaxValue + 64 }, + { 255, byte.MaxValue + 128 }, + { 255, byte.MaxValue + 172 }, + { 255, byte.MaxValue + byte.MaxValue }, + { 255, int.MaxValue }, + { 255, -1 }, + { 255, int.MinValue }, + }; + } + + public class RangeSByteTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { sbyte.MinValue, 256 }, + { sbyte.MinValue, 15 }, + { sbyte.MinValue, 1 }, + { sbyte.MinValue, 0 }, + + { sbyte.MinValue / 2, 128 - sbyte.MinValue / 2 }, + { sbyte.MinValue / 2, 15 }, + { sbyte.MinValue / 2, 1 }, + { sbyte.MinValue / 2, 0 }, + + { -1, 129 }, + { -1, 15 }, + { -1, 1 }, + { -1, 0 }, + + { sbyte.MaxValue - 14, 15 }, + { sbyte.MaxValue, 1 }, + { sbyte.MaxValue, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { -128, byte.MaxValue + 2 }, + { -128, byte.MaxValue + 64 }, + { -128, byte.MaxValue + 128 }, + { -128, byte.MaxValue + 172 }, + { -128, byte.MaxValue + byte.MaxValue }, + { -128, int.MaxValue }, + { -128, -1 }, + { -128, int.MinValue }, + + { -127, byte.MaxValue + 1}, + { -127, byte.MaxValue + 64 }, + { -127, byte.MaxValue + 128 }, + { -127, byte.MaxValue + 172 }, + { -127, byte.MaxValue + byte.MaxValue }, + { -127, int.MaxValue }, + { -127, -1 }, + { -127, int.MinValue }, + + { -1, byte.MaxValue + 3 }, + { -1, byte.MaxValue + 64 }, + { -1, byte.MaxValue + 128 }, + { -1, byte.MaxValue + 172 }, + { -1, byte.MaxValue + byte.MaxValue }, + { -1, int.MaxValue }, + { -1, -1 }, + { -1, int.MinValue }, + + { 0, byte.MaxValue + 2 }, + { 0, byte.MaxValue + 64 }, + { 0, byte.MaxValue + 128 }, + { 0, byte.MaxValue + 172 }, + { 0, byte.MaxValue + byte.MaxValue }, + { 0, int.MaxValue }, + { 0, -1 }, + { 0, int.MinValue }, + + { 1, byte.MaxValue + 1 }, + { 1, byte.MaxValue + 64 }, + { 1, byte.MaxValue + 128 }, + { 1, byte.MaxValue + 172 }, + { 1, byte.MaxValue + byte.MaxValue }, + { 1, int.MaxValue }, + { 1, -1 }, + { 1, int.MinValue }, + + { 126, 3 }, + { 126, byte.MaxValue + 64 }, + { 126, byte.MaxValue + 128 }, + { 126, byte.MaxValue + 172 }, + { 126, byte.MaxValue + byte.MaxValue }, + { 126, int.MaxValue }, + { 126, -1 }, + { 126, int.MinValue }, + + { 127, 2 }, + { 127, byte.MaxValue + 64 }, + { 127, byte.MaxValue + 128 }, + { 127, byte.MaxValue + 172 }, + { 127, byte.MaxValue + byte.MaxValue }, + { 127, int.MaxValue }, + { 127, -1 }, + { 127, int.MinValue }, + }; + } + + public class RangeUshortTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { 0, 15 }, + { 0, 1 }, + { 0, 0 }, + + { ushort.MaxValue / 2, 15 }, + { ushort.MaxValue / 2, 1 }, + { ushort.MaxValue / 2, 0 }, + + { ushort.MaxValue - 14, 15 }, + { ushort.MaxValue, 1 }, + { ushort.MaxValue, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { 0, ushort.MaxValue + 2 }, + { 0, ushort.MaxValue + ushort.MaxValue / 4 }, + { 0, ushort.MaxValue + ushort.MaxValue / 4 }, + { 0, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { 0, ushort.MaxValue + ushort.MaxValue }, + { 0, int.MaxValue }, + { 0, -1 }, + { 0, int.MinValue }, + + { 1, ushort.MaxValue + 1}, + { 1, ushort.MaxValue + ushort.MaxValue / 4 }, + { 1, ushort.MaxValue + ushort.MaxValue / 4 }, + { 1, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { 1, ushort.MaxValue + ushort.MaxValue }, + { 1, int.MaxValue }, + { 1, -1 }, + { 1, int.MinValue }, + + { ushort.MaxValue / 2, ushort.MaxValue - ushort.MaxValue / 2 + 2 }, + { ushort.MaxValue / 2, ushort.MaxValue + ushort.MaxValue / 4 }, + { ushort.MaxValue / 2, ushort.MaxValue + ushort.MaxValue / 2 }, + { ushort.MaxValue / 2, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { ushort.MaxValue / 2, ushort.MaxValue + ushort.MaxValue }, + { ushort.MaxValue / 2, int.MaxValue }, + { ushort.MaxValue / 2, -1 }, + { ushort.MaxValue / 2, int.MinValue }, + + { ushort.MaxValue / 2 + 1, ushort.MaxValue - ushort.MaxValue / 2 + 1 }, + { ushort.MaxValue / 2 + 1, ushort.MaxValue + ushort.MaxValue / 4 }, + { ushort.MaxValue / 2 + 1, ushort.MaxValue + ushort.MaxValue / 2 }, + { ushort.MaxValue / 2 + 1, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { ushort.MaxValue / 2 + 1, ushort.MaxValue + ushort.MaxValue }, + { ushort.MaxValue / 2 + 1, int.MaxValue }, + { ushort.MaxValue / 2 + 1, -1 }, + { ushort.MaxValue / 2 + 1, int.MinValue }, + + { ushort.MaxValue / 2 + 2, ushort.MaxValue - ushort.MaxValue / 2 }, + { ushort.MaxValue / 2 + 2, ushort.MaxValue + ushort.MaxValue / 4 }, + { ushort.MaxValue / 2 + 2, ushort.MaxValue + ushort.MaxValue / 2 }, + { ushort.MaxValue / 2 + 2, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { ushort.MaxValue / 2 + 2, ushort.MaxValue + ushort.MaxValue }, + { ushort.MaxValue / 2 + 2, int.MaxValue }, + { ushort.MaxValue / 2 + 2, -1 }, + { ushort.MaxValue / 2 + 2, int.MinValue }, + + { ushort.MaxValue - 1, 3 }, + { ushort.MaxValue - 1, ushort.MaxValue + ushort.MaxValue / 4 }, + { ushort.MaxValue - 1, ushort.MaxValue + ushort.MaxValue / 2 }, + { ushort.MaxValue - 1, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { ushort.MaxValue - 1, ushort.MaxValue + ushort.MaxValue }, + { ushort.MaxValue - 1, int.MaxValue }, + { ushort.MaxValue - 1, -1 }, + { ushort.MaxValue - 1, int.MinValue }, + + { ushort.MaxValue, 2 }, + { ushort.MaxValue, ushort.MaxValue + ushort.MaxValue / 4 }, + { ushort.MaxValue, ushort.MaxValue + ushort.MaxValue / 2 }, + { ushort.MaxValue, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { ushort.MaxValue, ushort.MaxValue + ushort.MaxValue }, + { ushort.MaxValue, int.MaxValue }, + { ushort.MaxValue, -1 }, + { ushort.MaxValue, int.MinValue }, + }; + } + + public class RangeShortTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { short.MinValue, 15 }, + { short.MinValue, 1 }, + { short.MinValue, 0 }, + + + { -1, 15 }, + { -1, 1 }, + { -1, 0 }, + + { short.MaxValue - 14, 15 }, + { short.MaxValue, 1 }, + { short.MaxValue, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { short.MinValue, ushort.MaxValue + 2 }, + { short.MinValue, ushort.MaxValue + 64 }, + { short.MinValue, ushort.MaxValue + 128 }, + { short.MinValue, ushort.MaxValue + 172 }, + { short.MinValue, ushort.MaxValue + short.MaxValue }, + { short.MinValue, int.MaxValue }, + { short.MinValue, -1 }, + { short.MinValue, int.MinValue }, + + { short.MinValue + 1, ushort.MaxValue + 1}, + { short.MinValue + 1, ushort.MaxValue + 64 }, + { short.MinValue + 1, ushort.MaxValue + 128 }, + { short.MinValue + 1, ushort.MaxValue + 172 }, + { short.MinValue + 1, ushort.MaxValue + ushort.MaxValue }, + { short.MinValue + 1, int.MaxValue }, + { short.MinValue + 1, -1 }, + { short.MinValue + 1, int.MinValue }, + + { -1, short.MaxValue + 3 }, + { -1, ushort.MaxValue + 64 }, + { -1, ushort.MaxValue + 128 }, + { -1, ushort.MaxValue + 172 }, + { -1, ushort.MaxValue + ushort.MaxValue }, + { -1, int.MaxValue }, + { -1, -1 }, + { -1, int.MinValue }, + + { 0, short.MaxValue + 2 }, + { 0, ushort.MaxValue + 64 }, + { 0, ushort.MaxValue + 128 }, + { 0, ushort.MaxValue + 172 }, + { 0, ushort.MaxValue + ushort.MaxValue }, + { 0, int.MaxValue }, + { 0, -1 }, + { 0, int.MinValue }, + + { 1, short.MaxValue + 1 }, + { 1, ushort.MaxValue + 64 }, + { 1, ushort.MaxValue + 128 }, + { 1, ushort.MaxValue + 172 }, + { 1, ushort.MaxValue + ushort.MaxValue }, + { 1, int.MaxValue }, + { 1, -1 }, + { 1, int.MinValue }, + + { short.MaxValue - 1, 3 }, + { short.MaxValue - 1, ushort.MaxValue + 64 }, + { short.MaxValue - 1, ushort.MaxValue + 128 }, + { short.MaxValue - 1, ushort.MaxValue + 172 }, + { short.MaxValue - 1, ushort.MaxValue + ushort.MaxValue }, + { short.MaxValue - 1, int.MaxValue }, + { short.MaxValue - 1, -1 }, + { short.MaxValue - 1, int.MinValue }, + + { short.MaxValue, 2 }, + { short.MaxValue, ushort.MaxValue + 64 }, + { short.MaxValue, ushort.MaxValue + 128 }, + { short.MaxValue, ushort.MaxValue + 172 }, + { short.MaxValue, ushort.MaxValue + ushort.MaxValue }, + { short.MaxValue, int.MaxValue }, + { short.MaxValue, -1 }, + { short.MaxValue, int.MinValue }, + }; + } + + public class RangeCharTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { (char)0, 15 }, + { (char)0, 1 }, + { (char)0, 0 }, + + { (char)(ushort.MaxValue / 2), 15 }, + { (char)(ushort.MaxValue / 2), 1 }, + { (char)(ushort.MaxValue / 2), 0 }, + + { (char)(ushort.MaxValue - 14), 15 }, + { (char)ushort.MaxValue, 1 }, + { (char)ushort.MaxValue, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { (char)0, ushort.MaxValue + 2 }, + { (char)0, ushort.MaxValue + ushort.MaxValue / 4 }, + { (char)0, ushort.MaxValue + ushort.MaxValue / 4 }, + { (char)0, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { (char)0, ushort.MaxValue + ushort.MaxValue }, + { (char)0, int.MaxValue }, + { (char)0, -1 }, + { (char)0, int.MinValue }, + + { (char)1, ushort.MaxValue + 1}, + { (char)1, ushort.MaxValue + ushort.MaxValue / 4 }, + { (char)1, ushort.MaxValue + ushort.MaxValue / 4 }, + { (char)1, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { (char)1, ushort.MaxValue + ushort.MaxValue }, + { (char)1, int.MaxValue }, + { (char)1, -1 }, + { (char)1, int.MinValue }, + + { (char)(ushort.MaxValue / 2), ushort.MaxValue - ushort.MaxValue / 2 + 2 }, + { (char)(ushort.MaxValue / 2), ushort.MaxValue + ushort.MaxValue / 4 }, + { (char)(ushort.MaxValue / 2), ushort.MaxValue + ushort.MaxValue / 2 }, + { (char)(ushort.MaxValue / 2), ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { (char)(ushort.MaxValue / 2), ushort.MaxValue + ushort.MaxValue }, + { (char)(ushort.MaxValue / 2), int.MaxValue }, + { (char)(ushort.MaxValue / 2), -1 }, + { (char)(ushort.MaxValue / 2), int.MinValue }, + + { (char)(ushort.MaxValue / 2 + 1), ushort.MaxValue - ushort.MaxValue / 2 + 1 }, + { (char)(ushort.MaxValue / 2 + 1), ushort.MaxValue + ushort.MaxValue / 4 }, + { (char)(ushort.MaxValue / 2 + 1), ushort.MaxValue + ushort.MaxValue / 2 }, + { (char)(ushort.MaxValue / 2 + 1), ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { (char)(ushort.MaxValue / 2 + 1), ushort.MaxValue + ushort.MaxValue }, + { (char)(ushort.MaxValue / 2 + 1), int.MaxValue }, + { (char)(ushort.MaxValue / 2 + 1), -1 }, + { (char)(ushort.MaxValue / 2 + 1), int.MinValue }, + + { (char)(ushort.MaxValue / 2 + 2), ushort.MaxValue - ushort.MaxValue / 2 }, + { (char)(ushort.MaxValue / 2 + 2), ushort.MaxValue + ushort.MaxValue / 4 }, + { (char)(ushort.MaxValue / 2 + 2), ushort.MaxValue + ushort.MaxValue / 2 }, + { (char)(ushort.MaxValue / 2 + 2), ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { (char)(ushort.MaxValue / 2 + 2), ushort.MaxValue + ushort.MaxValue }, + { (char)(ushort.MaxValue / 2 + 2), int.MaxValue }, + { (char)(ushort.MaxValue / 2 + 2), -1 }, + { (char)(ushort.MaxValue / 2 + 2), int.MinValue }, + + { (char)(ushort.MaxValue - 1), 3 }, + { (char)(ushort.MaxValue - 1), ushort.MaxValue + ushort.MaxValue / 4 }, + { (char)(ushort.MaxValue - 1), ushort.MaxValue + ushort.MaxValue / 2 }, + { (char)(ushort.MaxValue - 1), ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { (char)(ushort.MaxValue - 1), ushort.MaxValue + ushort.MaxValue }, + { (char)(ushort.MaxValue - 1), int.MaxValue }, + { (char)(ushort.MaxValue - 1), -1 }, + { (char)(ushort.MaxValue - 1), int.MinValue }, + + { (char)ushort.MaxValue, 2 }, + { (char)ushort.MaxValue, ushort.MaxValue + ushort.MaxValue / 4 }, + { (char)ushort.MaxValue, ushort.MaxValue + ushort.MaxValue / 2 }, + { (char)ushort.MaxValue, ushort.MaxValue + ushort.MaxValue * 3 / 4 }, + { (char)ushort.MaxValue, ushort.MaxValue + ushort.MaxValue }, + { (char)ushort.MaxValue, int.MaxValue }, + { (char)ushort.MaxValue, -1 }, + { (char)ushort.MaxValue, int.MinValue }, + }; + } + + public class RangeUintTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { 0, 15 }, + { 0, 1 }, + { 0, 0 }, + + { uint.MaxValue / 2, 15 }, + { uint.MaxValue / 2, 1 }, + { uint.MaxValue / 2, 0 }, + + { uint.MaxValue - 14, 15 }, + { uint.MaxValue, 1 }, + { uint.MaxValue, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { 0, -1 }, + { 0, int.MinValue }, + + { 1, -1 }, + { 1, int.MinValue }, + + { uint.MaxValue / 2, -1 }, + { uint.MaxValue / 2, int.MinValue }, + + { uint.MaxValue - int.MaxValue + 2, int.MaxValue }, + { uint.MaxValue - int.MaxValue + 2, -1 }, + { uint.MaxValue - int.MaxValue + 2, int.MinValue }, + + { uint.MaxValue - int.MaxValue / 2, int.MaxValue / 2 + 2 }, + { uint.MaxValue - int.MaxValue / 2, int.MaxValue }, + { uint.MaxValue - int.MaxValue / 2, -1 }, + { uint.MaxValue - int.MaxValue / 2, int.MinValue }, + + { uint.MaxValue - 1, 3 }, + { uint.MaxValue - 1, int.MaxValue / 4 }, + { uint.MaxValue - 1, int.MaxValue / 2 }, + { uint.MaxValue - 1, int.MaxValue }, + { uint.MaxValue - 1, -1 }, + { uint.MaxValue - 1, int.MinValue }, + + { uint.MaxValue, 2 }, + { uint.MaxValue, int.MaxValue / 4 }, + { uint.MaxValue, int.MaxValue / 2 }, + { uint.MaxValue, int.MaxValue }, + { uint.MaxValue, -1 }, + { uint.MaxValue, int.MinValue }, + }; + } + + public class RangeIntTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { int.MinValue, 15 }, + { int.MinValue, 1 }, + { int.MinValue, 0 }, + + + { -1, 15 }, + { -1, 1 }, + { -1, 0 }, + + { int.MaxValue - 14, 15 }, + { int.MaxValue, 1 }, + { int.MaxValue, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { int.MinValue, -1 }, + { int.MinValue, int.MinValue }, + + { int.MinValue + 1, -1 }, + { int.MinValue + 1, int.MinValue }, + + { int.MinValue / 2, -1 }, + { int.MinValue / 2, int.MinValue }, + + { 0, -1 }, + { 0, int.MinValue }, + + { 2, int.MaxValue }, + { 2, -1 }, + { 2, int.MinValue }, + + { int.MaxValue / 2, int.MaxValue - int.MaxValue / 2 + 2}, + { int.MaxValue / 2, int.MaxValue}, + { int.MaxValue / 2, -1 }, + { int.MaxValue / 2, int.MinValue }, + + { int.MaxValue - 1, 3 }, + { int.MaxValue - 1, int.MaxValue }, + { int.MaxValue - 1, -1 }, + { int.MaxValue - 1, int.MinValue }, + + { int.MaxValue, 2 }, + { int.MaxValue, int.MaxValue }, + { int.MaxValue, -1 }, + { int.MaxValue, int.MinValue }, + }; + } + + public class RangeUlongTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { 0, 15 }, + { 0, 1 }, + { 0, 0 }, + + { ulong.MaxValue / 2, 15 }, + { ulong.MaxValue / 2, 1 }, + { ulong.MaxValue / 2, 0 }, + + { ulong.MaxValue - 14, 15 }, + { ulong.MaxValue, 1 }, + { ulong.MaxValue, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { 0, -1 }, + { 0, int.MinValue }, + + { 1, -1 }, + { 1, int.MinValue }, + + { ulong.MaxValue / 2, -1 }, + { ulong.MaxValue / 2, int.MinValue }, + + { ulong.MaxValue - int.MaxValue + 2, int.MaxValue }, + { ulong.MaxValue - int.MaxValue + 2, -1 }, + { ulong.MaxValue - int.MaxValue + 2, int.MinValue }, + + { ulong.MaxValue - int.MaxValue / 2, int.MaxValue / 2 + 2 }, + { ulong.MaxValue - int.MaxValue / 2, int.MaxValue }, + { ulong.MaxValue - int.MaxValue / 2, -1 }, + { ulong.MaxValue - int.MaxValue / 2, int.MinValue }, + + { ulong.MaxValue - 1, 3 }, + { ulong.MaxValue - 1, int.MaxValue / 4 }, + { ulong.MaxValue - 1, int.MaxValue / 2 }, + { ulong.MaxValue - 1, int.MaxValue }, + { ulong.MaxValue - 1, -1 }, + { ulong.MaxValue - 1, int.MinValue }, + + { ulong.MaxValue, 2 }, + { ulong.MaxValue, int.MaxValue / 4 }, + { ulong.MaxValue, int.MaxValue / 2 }, + { ulong.MaxValue, int.MaxValue }, + { ulong.MaxValue, -1 }, + { ulong.MaxValue, int.MinValue }, + }; + } + + public class RangeLongTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { long.MinValue, 15 }, + { long.MinValue, 1 }, + { long.MinValue, 0 }, + + + { -1, 15 }, + { -1, 1 }, + { -1, 0 }, + + { long.MaxValue - 14, 15 }, + { long.MaxValue, 1 }, + { long.MaxValue, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { long.MinValue, -1 }, + { long.MinValue, int.MinValue }, + + { long.MinValue + 1, -1 }, + { long.MinValue + 1, int.MinValue }, + + { long.MinValue / 2, -1 }, + { long.MinValue / 2, int.MinValue }, + + { 0, -1 }, + { 0, int.MinValue }, + + { 2, -1 }, + { 2, int.MinValue }, + + { long.MaxValue / 2, -1 }, + { long.MaxValue / 2, int.MinValue }, + + { long.MaxValue - int.MaxValue + 2, int.MaxValue }, + { long.MaxValue - int.MaxValue + 2, -1 }, + { long.MaxValue - int.MaxValue + 2, int.MinValue }, + + { long.MaxValue - int.MaxValue / 2, int.MaxValue / 2 + 2 }, + { long.MaxValue - int.MaxValue / 2, int.MaxValue }, + { long.MaxValue - int.MaxValue / 2, -1 }, + { long.MaxValue - int.MaxValue / 2, int.MinValue }, + + { long.MaxValue - 1, 3 }, + { long.MaxValue - 1, int.MaxValue }, + { long.MaxValue - 1, -1 }, + { long.MaxValue - 1, int.MinValue }, + + { long.MaxValue, 2 }, + { long.MaxValue, int.MaxValue }, + { long.MaxValue, -1 }, + { long.MaxValue, int.MinValue }, + }; + } + + public class RangeBigIntegerTests : RangeIBinaryIntegerTests + { + public static TheoryData StartCountCorrectData { get; } = new TheoryData() + { + { -new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, 15 }, + { -new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, 1 }, + { -new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, 0 }, + + + { -1, 15 }, + { -1, 1 }, + { -1, 0 }, + + { new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, 15 }, + { new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, 1 }, + { new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, 0 }, + }; + + public static TheoryData StartCountIncorrectData { get; } = new TheoryData() + { + { -new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, -1 }, + { -new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, int.MinValue }, + + { -1, -1 }, + { -1, int.MinValue }, + + { 0, -1 }, + { 0, int.MinValue }, + + { 1, -1 }, + { 1, int.MinValue }, + + { new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, -1 }, + { new BigInteger(long.MaxValue) * long.MaxValue * long.MaxValue * long.MaxValue, int.MinValue }, + }; + } + +} diff --git a/src/libraries/System.Linq/tests/System.Linq.Tests.csproj b/src/libraries/System.Linq/tests/System.Linq.Tests.csproj index 2e1ad5368b276b..a403cba3b40561 100644 --- a/src/libraries/System.Linq/tests/System.Linq.Tests.csproj +++ b/src/libraries/System.Linq/tests/System.Linq.Tests.csproj @@ -50,6 +50,7 @@ + @@ -79,10 +80,8 @@ - - + + diff --git a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs index 431fc42d430619..dd863e224a5405 100644 --- a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs +++ b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs @@ -17,7 +17,7 @@ internal class StringTestSequenceFactory : ReadOnlySequenceFactory { public override ReadOnlySequence CreateOfSize(int size) { - IEnumerable ascii = Enumerable.Range(' ', (char)0x7f - ' '); + IEnumerable ascii = Enumerable.Range(' ', (char)0x7f - ' '); IEnumerable items = ascii; for (int i = (size + 20) / ascii.Count(); i > 0; i--) items = items.Concat(ascii); diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs index c0d7398b039c12..d4081b079c13a0 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs @@ -567,13 +567,13 @@ public void Array_ByValueOut() ushort start = 65; NativeExportsNE.Arrays.FillChars(testArray, testArray.Length, start); - Assert.Equal(Enumerable.Range(start, testArray.Length), testArray.Select(c => (int)c)); + Assert.Equal(Enumerable.Range(start, testArray.Length), testArray.Select(c => (int)c)); // Any items not populated by the invoke target should be initialized to default testArray = new char[10]; int lengthToFill = testArray.Length / 2; NativeExportsNE.Arrays.FillChars(testArray, lengthToFill, start); - Assert.Equal(Enumerable.Range(start, lengthToFill), testArray[..lengthToFill].Select(c => (int)c)); + Assert.Equal(Enumerable.Range(start, lengthToFill), testArray[..lengthToFill].Select(c => (int)c)); Assert.All(testArray[lengthToFill..], c => Assert.Equal(0, c)); } } @@ -600,13 +600,13 @@ public void Array_ByValueOut_This() ushort start = 65; testArray.FillChars(testArray.Length, start); - Assert.Equal(Enumerable.Range(start, testArray.Length), testArray.Select(c => (int)c)); + Assert.Equal(Enumerable.Range(start, testArray.Length), testArray.Select(c => (int)c)); // Any items not populated by the invoke target should be initialized to default testArray = new char[10]; int lengthToFill = testArray.Length / 2; testArray.FillChars(lengthToFill, start); - Assert.Equal(Enumerable.Range(start, lengthToFill), testArray[..lengthToFill].Select(c => (int)c)); + Assert.Equal(Enumerable.Range(start, lengthToFill), testArray[..lengthToFill].Select(c => (int)c)); Assert.All(testArray[lengthToFill..], c => Assert.Equal(0, c)); } }