diff options
author | Ahson Khan <ahkha@microsoft.com> | 2017-12-07 21:27:48 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-07 21:27:48 +0300 |
commit | d2193783e6b009295f78e122ccf228e533f3f94c (patch) | |
tree | 1a6c5ec396ecdfa599f4389cdf382c25f6624987 /src/System.Memory/tests | |
parent | 6d57c82817cd58672af8c3b39bf2019247bc78b4 (diff) |
Implement Span LastIndexOf extension method and add tests (#25748)
* Implement Span LastIndexOf and add tests
* Add LastIndexOfSequence tests and fix implementation
* Vectorize LastIndexOf<byte> similar to IndexOf<byte>
* Add LastIndexOf performance tests
* Adding IndexOf and LastIndexOf tests for reference type (string).
* Use abbreviated version of 'default' literal
* Remove unnecessary type specifiers in generic function calls.
* Cleanup and format all files in the solution to follow coding style.
* Cleaning up leftover unused using directives and extra spaces
Diffstat (limited to 'src/System.Memory/tests')
57 files changed, 2518 insertions, 211 deletions
diff --git a/src/System.Memory/tests/AllocationHelper.cs b/src/System.Memory/tests/AllocationHelper.cs index 69311ba0ab..3496465d49 100644 --- a/src/System.Memory/tests/AllocationHelper.cs +++ b/src/System.Memory/tests/AllocationHelper.cs @@ -11,14 +11,14 @@ namespace System.SpanTests /// </summary> static class AllocationHelper { - private static readonly Mutex MemoryLock = new Mutex(); - private static readonly TimeSpan WaitTimeout = TimeSpan.FromSeconds(120); + private static readonly Mutex s_memoryLock = new Mutex(); + private static readonly TimeSpan s_waitTimeout = TimeSpan.FromSeconds(120); public static bool TryAllocNative(IntPtr size, out IntPtr memory) { memory = IntPtr.Zero; - if (!MemoryLock.WaitOne(WaitTimeout)) + if (!s_memoryLock.WaitOne(s_waitTimeout)) return false; try @@ -28,7 +28,7 @@ namespace System.SpanTests catch (OutOfMemoryException) { memory = IntPtr.Zero; - MemoryLock.ReleaseMutex(); + s_memoryLock.ReleaseMutex(); } return memory != IntPtr.Zero; @@ -43,7 +43,7 @@ namespace System.SpanTests } finally { - MemoryLock.ReleaseMutex(); + s_memoryLock.ReleaseMutex(); } } } diff --git a/src/System.Memory/tests/Base64/Base64DecoderUnitTests.cs b/src/System.Memory/tests/Base64/Base64DecoderUnitTests.cs index 4bc0f20063..15a6733060 100644 --- a/src/System.Memory/tests/Base64/Base64DecoderUnitTests.cs +++ b/src/System.Memory/tests/Base64/Base64DecoderUnitTests.cs @@ -24,7 +24,7 @@ namespace System.Buffers.Text.Tests Base64TestHelper.InitalizeDecodableBytes(source, numBytes); Span<byte> decodedBytes = new byte[Base64.GetMaxDecodedFromUtf8Length(source.Length)]; - Assert.Equal(OperationStatus.Done, + Assert.Equal(OperationStatus.Done, Base64.DecodeFromUtf8(source, decodedBytes, out int consumed, out int decodedByteCount)); Assert.Equal(source.Length, consumed); Assert.Equal(decodedBytes.Length, decodedByteCount); @@ -38,7 +38,7 @@ namespace System.Buffers.Text.Tests Span<byte> source = Span<byte>.Empty; Span<byte> decodedBytes = new byte[Base64.GetMaxDecodedFromUtf8Length(source.Length)]; - Assert.Equal(OperationStatus.Done, + Assert.Equal(OperationStatus.Done, Base64.DecodeFromUtf8(source, decodedBytes, out int consumed, out int decodedByteCount)); Assert.Equal(source.Length, consumed); Assert.Equal(decodedBytes.Length, decodedByteCount); @@ -62,7 +62,7 @@ namespace System.Buffers.Text.Tests Span<byte> decodedBytes = new byte[Base64.GetMaxDecodedFromUtf8Length(source.Length)]; int expectedConsumed = source.Length / 4 * 4; // only consume closest multiple of four since isFinalBlock is false - Assert.Equal(OperationStatus.NeedMoreData, + Assert.Equal(OperationStatus.NeedMoreData, Base64.DecodeFromUtf8(source, decodedBytes, out int consumed, out int decodedByteCount, isFinalBlock: false)); Assert.Equal(expectedConsumed, consumed); Assert.Equal(decodedBytes.Length, decodedByteCount); @@ -151,7 +151,7 @@ namespace System.Buffers.Text.Tests // 123-255 byte[] invalidBytes = Base64TestHelper.InvalidBytes; Assert.Equal(byte.MaxValue + 1 - 64, invalidBytes.Length); // 192 - + for (int j = 0; j < 8; j++) { Span<byte> source = new byte[8] { 50, 50, 50, 50, 80, 80, 80, 80 }; // valid input - "2222PPPP" @@ -160,14 +160,15 @@ namespace System.Buffers.Text.Tests for (int i = 0; i < invalidBytes.Length; i++) { // Don't test padding (byte 61 i.e. '='), which is tested in DecodingInvalidBytesPadding - if (invalidBytes[i] == Base64TestHelper.s_encodingPad) continue; + if (invalidBytes[i] == Base64TestHelper.s_encodingPad) + continue; // replace one byte with an invalid input source[j] = invalidBytes[i]; Assert.Equal(OperationStatus.InvalidData, Base64.DecodeFromUtf8(source, decodedBytes, out int consumed, out int decodedByteCount)); - + if (j < 4) { Assert.Equal(0, consumed); @@ -302,7 +303,7 @@ namespace System.Buffers.Text.Tests source[11] = Base64TestHelper.s_encodingPad; Span<byte> decodedBytes = new byte[6]; - Assert.Equal(OperationStatus.DestinationTooSmall, + Assert.Equal(OperationStatus.DestinationTooSmall, Base64.DecodeFromUtf8(source, decodedBytes, out int consumed, out int written)); int expectedConsumed = 8; Assert.Equal(expectedConsumed, consumed); @@ -316,7 +317,7 @@ namespace System.Buffers.Text.Tests source[11] = Base64TestHelper.s_encodingPad; Span<byte> decodedBytes = new byte[7]; - Assert.Equal(OperationStatus.DestinationTooSmall, + Assert.Equal(OperationStatus.DestinationTooSmall, Base64.DecodeFromUtf8(source, decodedBytes, out int consumed, out int written)); int expectedConsumed = 8; Assert.Equal(expectedConsumed, consumed); @@ -335,10 +336,10 @@ namespace System.Buffers.Text.Tests int requiredSize = Base64.GetMaxDecodedFromUtf8Length(source.Length); Span<byte> decodedBytes = new byte[outputSize]; - Assert.Equal(OperationStatus.DestinationTooSmall, + Assert.Equal(OperationStatus.DestinationTooSmall, Base64.DecodeFromUtf8(source, decodedBytes, out int consumed, out int decodedByteCount)); int expectedConsumed = decodedBytes.Length / 3 * 4; - Assert.Equal(expectedConsumed, consumed); + Assert.Equal(expectedConsumed, consumed); Assert.Equal(decodedBytes.Length, decodedByteCount); Assert.True(Base64TestHelper.VerifyDecodingCorrectness(expectedConsumed, decodedBytes.Length, source, decodedBytes)); @@ -380,7 +381,6 @@ namespace System.Buffers.Text.Tests Assert.Throws<ArgumentOutOfRangeException>(() => Base64.GetMaxDecodedFromUtf8Length(int.MinValue)); } - [Fact] public void DecodeInPlace() { @@ -429,7 +429,7 @@ namespace System.Buffers.Text.Tests public void DecodeInPlaceInvalidBytes() { byte[] invalidBytes = Base64TestHelper.InvalidBytes; - + for (int j = 0; j < 8; j++) { for (int i = 0; i < invalidBytes.Length; i++) @@ -437,14 +437,15 @@ namespace System.Buffers.Text.Tests Span<byte> buffer = new byte[8] { 50, 50, 50, 50, 80, 80, 80, 80 }; // valid input - "2222PPPP" // Don't test padding (byte 61 i.e. '='), which is tested in DecodeInPlaceInvalidBytesPadding - if (invalidBytes[i] == Base64TestHelper.s_encodingPad) continue; + if (invalidBytes[i] == Base64TestHelper.s_encodingPad) + continue; // replace one byte with an invalid input buffer[j] = invalidBytes[i]; string sourceString = Encoding.ASCII.GetString(buffer.Slice(0, 4).ToArray()); Assert.Equal(OperationStatus.InvalidData, Base64.DecodeFromUtf8InPlace(buffer, out int bytesWritten)); - + if (j < 4) { Assert.Equal(0, bytesWritten); @@ -523,7 +524,7 @@ namespace System.Buffers.Text.Tests Span<byte> expectedBytes = Convert.FromBase64String(sourceString); Assert.True(expectedBytes.SequenceEqual(buffer.Slice(0, bytesWritten))); } - + { Span<byte> buffer = new byte[] { 50, 50, 50, 50, 80, 80, 80, 80 }; buffer[7] = Base64TestHelper.s_encodingPad; // valid input - "2222PPP=" diff --git a/src/System.Memory/tests/Base64/Base64EncoderUnitTests.cs b/src/System.Memory/tests/Base64/Base64EncoderUnitTests.cs index d2e25a497a..c3f5335106 100644 --- a/src/System.Memory/tests/Base64/Base64EncoderUnitTests.cs +++ b/src/System.Memory/tests/Base64/Base64EncoderUnitTests.cs @@ -64,7 +64,7 @@ namespace System.Buffers.Text.Tests { Span<byte> source = Span<byte>.Empty; Span<byte> encodedBytes = new byte[Base64.GetMaxEncodedToUtf8Length(source.Length)]; - + Assert.Equal(OperationStatus.Done, Base64.EncodeToUtf8(source, encodedBytes, out int consumed, out int encodedBytesCount)); Assert.Equal(source.Length, consumed); Assert.Equal(encodedBytes.Length, encodedBytesCount); @@ -79,7 +79,7 @@ namespace System.Buffers.Text.Tests // CLR default limit of 2 gigabytes (GB). try { - // 1610612734, larger than MaximumEncodeLength, requires output buffer of size 2147483648 (which is > int.MaxValue) + // 1610612734, larger than MaximumEncodeLength, requires output buffer of size 2147483648 (which is > int.MaxValue) Span<byte> source = new byte[(int.MaxValue >> 2) * 3 + 1]; Span<byte> encodedBytes = new byte[2000000000]; Assert.Equal(OperationStatus.DestinationTooSmall, Base64.EncodeToUtf8(source, encodedBytes, out int consumed, out int encodedBytesCount)); @@ -249,7 +249,7 @@ namespace System.Buffers.Text.Tests [Fact] public void EncodeInPlaceOutputTooSmall() { - byte[] testBytes = {1, 2, 3}; + byte[] testBytes = { 1, 2, 3 }; for (int numberOfBytesToTest = 1; numberOfBytesToTest <= testBytes.Length; numberOfBytesToTest++) { @@ -261,7 +261,7 @@ namespace System.Buffers.Text.Tests [Fact] public void EncodeInPlaceDataLengthTooLarge() { - byte[] testBytes = {1, 2, 3}; + byte[] testBytes = { 1, 2, 3 }; Assert.Equal(OperationStatus.DestinationTooSmall, Base64.EncodeToUtf8InPlace(testBytes, testBytes.Length + 1, out int bytesWritten)); Assert.Equal(0, bytesWritten); } diff --git a/src/System.Memory/tests/Base64/Base64TestHelper.cs b/src/System.Memory/tests/Base64/Base64TestHelper.cs index 1026a97683..1aa8271674 100644 --- a/src/System.Memory/tests/Base64/Base64TestHelper.cs +++ b/src/System.Memory/tests/Base64/Base64TestHelper.cs @@ -57,7 +57,7 @@ namespace System.Buffers.Text.Tests // Workaroudn for indices.Cast<byte>().ToArray() since it throws // InvalidCastException: Unable to cast object of type 'System.Int32' to type 'System.Byte' byte[] bytes = new byte[indices.Length]; - for(int i = 0; i < indices.Length; i++) + for (int i = 0; i < indices.Length; i++) { bytes[i] = (byte)indices[i]; } diff --git a/src/System.Memory/tests/Binary/BinaryReaderUnitTests.cs b/src/System.Memory/tests/Binary/BinaryReaderUnitTests.cs index 7bb001f314..7fc1502fbc 100644 --- a/src/System.Memory/tests/Binary/BinaryReaderUnitTests.cs +++ b/src/System.Memory/tests/Binary/BinaryReaderUnitTests.cs @@ -19,7 +19,8 @@ namespace System.Buffers.Binary.Tests ulong value = 0x8877665544332211; // [11 22 33 44 55 66 77 88] Span<byte> span; - unsafe { + unsafe + { span = new Span<byte>(&value, 8); } @@ -87,7 +88,8 @@ namespace System.Buffers.Binary.Tests ulong value = 0x8877665544332211; // [11 22 33 44 55 66 77 88] ReadOnlySpan<byte> span; - unsafe { + unsafe + { span = new ReadOnlySpan<byte>(&value, 8); } @@ -225,18 +227,18 @@ namespace System.Buffers.Binary.Tests Span<byte> spanBE = new byte[Unsafe.SizeOf<TestStruct>()]; - WriteInt16BigEndian(spanBE, testStruct.S0); - WriteInt32BigEndian(spanBE.Slice(2), testStruct.I0); - WriteInt64BigEndian(spanBE.Slice(6), testStruct.L0); - WriteUInt16BigEndian(spanBE.Slice(14), testStruct.US0); - WriteUInt32BigEndian(spanBE.Slice(16), testStruct.UI0); - WriteUInt64BigEndian(spanBE.Slice(20), testStruct.UL0); - WriteInt16BigEndian(spanBE.Slice(28), testStruct.S1); - WriteInt32BigEndian(spanBE.Slice(30), testStruct.I1); - WriteInt64BigEndian(spanBE.Slice(34), testStruct.L1); - WriteUInt16BigEndian(spanBE.Slice(42), testStruct.US1); - WriteUInt32BigEndian(spanBE.Slice(44), testStruct.UI1); - WriteUInt64BigEndian(spanBE.Slice(48), testStruct.UL1); + WriteInt16BigEndian(spanBE, s_testStruct.S0); + WriteInt32BigEndian(spanBE.Slice(2), s_testStruct.I0); + WriteInt64BigEndian(spanBE.Slice(6), s_testStruct.L0); + WriteUInt16BigEndian(spanBE.Slice(14), s_testStruct.US0); + WriteUInt32BigEndian(spanBE.Slice(16), s_testStruct.UI0); + WriteUInt64BigEndian(spanBE.Slice(20), s_testStruct.UL0); + WriteInt16BigEndian(spanBE.Slice(28), s_testStruct.S1); + WriteInt32BigEndian(spanBE.Slice(30), s_testStruct.I1); + WriteInt64BigEndian(spanBE.Slice(34), s_testStruct.L1); + WriteUInt16BigEndian(spanBE.Slice(42), s_testStruct.US1); + WriteUInt32BigEndian(spanBE.Slice(44), s_testStruct.UI1); + WriteUInt64BigEndian(spanBE.Slice(48), s_testStruct.UL1); ReadOnlySpan<byte> readOnlySpanBE = new ReadOnlySpan<byte>(spanBE.ToArray()); @@ -272,8 +274,8 @@ namespace System.Buffers.Binary.Tests UL1 = ReadUInt64BigEndian(readOnlySpanBE.Slice(48)) }; - Assert.Equal(testStruct, readStruct); - Assert.Equal(testStruct, readStructFromReadOnlySpan); + Assert.Equal(s_testStruct, readStruct); + Assert.Equal(s_testStruct, readStructFromReadOnlySpan); } [Fact] @@ -283,18 +285,18 @@ namespace System.Buffers.Binary.Tests Span<byte> spanLE = new byte[Unsafe.SizeOf<TestStruct>()]; - WriteInt16LittleEndian(spanLE, testStruct.S0); - WriteInt32LittleEndian(spanLE.Slice(2), testStruct.I0); - WriteInt64LittleEndian(spanLE.Slice(6), testStruct.L0); - WriteUInt16LittleEndian(spanLE.Slice(14), testStruct.US0); - WriteUInt32LittleEndian(spanLE.Slice(16), testStruct.UI0); - WriteUInt64LittleEndian(spanLE.Slice(20), testStruct.UL0); - WriteInt16LittleEndian(spanLE.Slice(28), testStruct.S1); - WriteInt32LittleEndian(spanLE.Slice(30), testStruct.I1); - WriteInt64LittleEndian(spanLE.Slice(34), testStruct.L1); - WriteUInt16LittleEndian(spanLE.Slice(42), testStruct.US1); - WriteUInt32LittleEndian(spanLE.Slice(44), testStruct.UI1); - WriteUInt64LittleEndian(spanLE.Slice(48), testStruct.UL1); + WriteInt16LittleEndian(spanLE, s_testStruct.S0); + WriteInt32LittleEndian(spanLE.Slice(2), s_testStruct.I0); + WriteInt64LittleEndian(spanLE.Slice(6), s_testStruct.L0); + WriteUInt16LittleEndian(spanLE.Slice(14), s_testStruct.US0); + WriteUInt32LittleEndian(spanLE.Slice(16), s_testStruct.UI0); + WriteUInt64LittleEndian(spanLE.Slice(20), s_testStruct.UL0); + WriteInt16LittleEndian(spanLE.Slice(28), s_testStruct.S1); + WriteInt32LittleEndian(spanLE.Slice(30), s_testStruct.I1); + WriteInt64LittleEndian(spanLE.Slice(34), s_testStruct.L1); + WriteUInt16LittleEndian(spanLE.Slice(42), s_testStruct.US1); + WriteUInt32LittleEndian(spanLE.Slice(44), s_testStruct.UI1); + WriteUInt64LittleEndian(spanLE.Slice(48), s_testStruct.UL1); ReadOnlySpan<byte> readOnlySpanLE = new ReadOnlySpan<byte>(spanLE.ToArray()); @@ -330,8 +332,8 @@ namespace System.Buffers.Binary.Tests UL1 = ReadUInt64LittleEndian(readOnlySpanLE.Slice(48)) }; - Assert.Equal(testStruct, readStruct); - Assert.Equal(testStruct, readStructFromReadOnlySpan); + Assert.Equal(s_testStruct, readStruct); + Assert.Equal(s_testStruct, readStructFromReadOnlySpan); } [Fact] @@ -446,7 +448,7 @@ namespace System.Buffers.Binary.Tests Assert.Equal(testExplicitStruct, readStructFieldByFieldFromReadOnlySpan); } - private static TestStruct testStruct = new TestStruct + private static TestStruct s_testStruct = new TestStruct { S0 = short.MaxValue, I0 = int.MaxValue, diff --git a/src/System.Memory/tests/Binary/BinaryWriterUnitTests.cs b/src/System.Memory/tests/Binary/BinaryWriterUnitTests.cs index 0b9a8f8768..efd6d2be2f 100644 --- a/src/System.Memory/tests/Binary/BinaryWriterUnitTests.cs +++ b/src/System.Memory/tests/Binary/BinaryWriterUnitTests.cs @@ -267,9 +267,9 @@ namespace System.Buffers.Binary.Tests uint uintValue = 1; long longValue = 1; ulong ulongValue = 1; - + Span<byte> span = new byte[1]; - + WriteMachineEndian<byte>(span, ref byteValue); byte read = ReadMachineEndian<byte>(span); Assert.Equal<byte>(byteValue, read); @@ -302,7 +302,7 @@ namespace System.Buffers.Binary.Tests TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => WriteMachineEndian<ulong>(_span, ref ulongValue)); Assert.False(TryWriteMachineEndian<ulong>(span, ref ulongValue)); - var structValue = new TestHelpers.TestValueTypeWithReference{ I = 1, S = "1" }; + var structValue = new TestHelpers.TestValueTypeWithReference { I = 1, S = "1" }; TestHelpers.AssertThrows<ArgumentException, byte>(span, (_span) => WriteMachineEndian<TestHelpers.TestValueTypeWithReference>(_span, ref structValue)); TestHelpers.AssertThrows<ArgumentException, byte>(span, (_span) => TryWriteMachineEndian<TestHelpers.TestValueTypeWithReference>(_span, ref structValue)); } diff --git a/src/System.Memory/tests/Memory/CopyTo.cs b/src/System.Memory/tests/Memory/CopyTo.cs index b5305a32bf..1cb36761e7 100644 --- a/src/System.Memory/tests/Memory/CopyTo.cs +++ b/src/System.Memory/tests/Memory/CopyTo.cs @@ -91,7 +91,7 @@ namespace System.MemoryTests int[] dst = { 99, 100 }; Memory<int> srcMemory = src; - Assert.Throws<ArgumentException>( () => srcMemory.CopyTo(dst) ); + Assert.Throws<ArgumentException>(() => srcMemory.CopyTo(dst)); int[] expected = { 99, 100 }; Assert.Equal<int>(expected, dst); // CopyTo() checks for sufficient space before doing any copying. } @@ -176,7 +176,7 @@ namespace System.MemoryTests int[] src = { 1, 2, 3 }; Memory<int> dst = new int[2] { 99, 100 }; - Assert.Throws<ArgumentException>( () => src.CopyTo(dst) ); + Assert.Throws<ArgumentException>(() => src.CopyTo(dst)); int[] expected = { 99, 100 }; Assert.Equal<int>(expected, dst.ToArray()); // CopyTo() checks for sufficient space before doing any copying. } diff --git a/src/System.Memory/tests/Memory/CustomMemoryForTest.cs b/src/System.Memory/tests/Memory/CustomMemoryForTest.cs index ae23459eac..04f6c2d30d 100644 --- a/src/System.Memory/tests/Memory/CustomMemoryForTest.cs +++ b/src/System.Memory/tests/Memory/CustomMemoryForTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. - using System.Buffers; using System.Runtime.InteropServices; using System.Threading; @@ -68,7 +67,7 @@ namespace System.MemoryTests } _disposed = true; - + } public override void Retain() diff --git a/src/System.Memory/tests/Memory/OwnedMemory.cs b/src/System.Memory/tests/Memory/OwnedMemory.cs index 36d3a15520..42c409fde9 100644 --- a/src/System.Memory/tests/Memory/OwnedMemory.cs +++ b/src/System.Memory/tests/Memory/OwnedMemory.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. - using System.Buffers; using Xunit; @@ -118,6 +117,6 @@ namespace System.MemoryTests Assert.True(owner.IsDisposed); } } - + } diff --git a/src/System.Memory/tests/Memory/ToArray.cs b/src/System.Memory/tests/Memory/ToArray.cs index bac27ed72d..23d70b28c5 100644 --- a/src/System.Memory/tests/Memory/ToArray.cs +++ b/src/System.Memory/tests/Memory/ToArray.cs @@ -24,7 +24,7 @@ namespace System.MemoryTests int[] a = { 91, 92, 93, 94, 95 }; var memory = new Memory<int>(a); int[] copy = memory.Slice(2).ToArray(); - + Assert.Equal<int>(new int[] { 93, 94, 95 }, copy); } diff --git a/src/System.Memory/tests/ParsersAndFormatters/Formatter/FormatterTestData.cs b/src/System.Memory/tests/ParsersAndFormatters/Formatter/FormatterTestData.cs index 99a949f451..1784553b49 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/Formatter/FormatterTestData.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/Formatter/FormatterTestData.cs @@ -33,10 +33,10 @@ namespace System.Buffers.Text.Tests // Take good care of this method: it affects Xunit output and makes a lot of difference in how annoying test investigations are. // - string formatString = (FormatSymbol == default) ? - "default" : - FormatSymbol + ((Precision == StandardFormat.NoPrecision) ? - string.Empty : + string formatString = (FormatSymbol == default) ? + "default" : + FormatSymbol + ((Precision == StandardFormat.NoPrecision) ? + string.Empty : Precision.ToString()); string bufferLengthString; @@ -46,7 +46,7 @@ namespace System.Buffers.Text.Tests } else if (PassedInBufferLength < ExpectedOutput.Length) { - bufferLengthString = $", Buffer Length = {PassedInBufferLength} bytes (too short)"; + bufferLengthString = $", Buffer Length = {PassedInBufferLength} bytes (too short)"; } else { diff --git a/src/System.Memory/tests/ParsersAndFormatters/Formatter/TestData.Formatter.cs b/src/System.Memory/tests/ParsersAndFormatters/Formatter/TestData.Formatter.cs index 48be503c3b..632b12908f 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/Formatter/TestData.Formatter.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/Formatter/TestData.Formatter.cs @@ -40,7 +40,7 @@ namespace System.Buffers.Text.Tests public static IEnumerable<object[]> UInt16FormatterTheoryData => UInt16FormatterTestData.Select(td => new object[] { td }); public static IEnumerable<object[]> Int32FormatterTheoryData => Int32FormatterTestData.Select(td => new object[] { td }); public static IEnumerable<object[]> UInt32FormatterTheoryData => UInt32FormatterTestData.Select(td => new object[] { td }); - public static IEnumerable<object[]> Int64FormatterTheoryData => Int64FormatterTestData.Select(td => new object[] { td }); + public static IEnumerable<object[]> Int64FormatterTheoryData => Int64FormatterTestData.Select(td => new object[] { td }); public static IEnumerable<object[]> UInt64FormatterTheoryData => UInt64FormatterTestData.Select(td => new object[] { td }); public static IEnumerable<object[]> DecimalFormatterTheoryData => DecimalFormatterTestData.Select(td => new object[] { td }); public static IEnumerable<object[]> DoubleFormatterTheoryData => DoubleFormatterTestData.Select(td => new object[] { td }); @@ -79,7 +79,7 @@ namespace System.Buffers.Text.Tests if (format.IsDefault) { string expectedOutput = ComputeExpectedOutput<T>(value, format.Symbol, StandardFormat.NoPrecision); - yield return new FormatterTestData<T>(value, new SupportedFormat(default(char), format.SupportsPrecision), default(byte), expectedOutput); + yield return new FormatterTestData<T>(value, new SupportedFormat(default, format.SupportsPrecision), default, expectedOutput); } if (!format.NoRepresentation) @@ -91,7 +91,7 @@ namespace System.Buffers.Text.Tests } else { - foreach (byte precision in TestData.Precisions) + foreach (byte precision in TestData.s_precisions) { string expectedOutput = ComputeExpectedOutput<T>(value, format.Symbol, precision); yield return new FormatterTestData<T>(value, format, precision, expectedOutput); diff --git a/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTestData.cs b/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTestData.cs index 6bc08df1a3..ba80a7bfce 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTestData.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTestData.cs @@ -29,8 +29,8 @@ namespace System.Buffers.Text.Tests // Take good care of this method: it affects Xunit output and makes a lot of difference in how annoying test investigations are. // - string formatString = (FormatSymbol == default) ? - "default" : + string formatString = (FormatSymbol == default) ? + "default" : FormatSymbol.ToString(); return $"[Parse{typeof(T).Name} '{Text}',{formatString} to {(ExpectedSuccess ? ExpectedValue.DisplayString() : "(should-not-parse)")})]"; diff --git a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Date.cs b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Date.cs index 672e7cb547..336952d20f 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Date.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Date.cs @@ -54,7 +54,7 @@ namespace System.Buffers.Text.Tests // Wrong day of week. yield return new ParserTestData<DateTimeOffset>("Thu, 13 Jan 2017 03:45:32 GMT", default, 'R', expectedSuccess: false); - foreach (ParserTestData<DateTimeOffset> bad in GenerateCorruptedDateTimeText("05/08/2017 10:30:45 +00:00", default(char))) + foreach (ParserTestData<DateTimeOffset> bad in GenerateCorruptedDateTimeText("05/08/2017 10:30:45 +00:00", default)) { yield return bad; } @@ -117,7 +117,7 @@ namespace System.Buffers.Text.Tests } catch (ArgumentOutOfRangeException) { - throw new Exception($"Failed on converting {expectedDto.DateTime} to local time. This is probably a piece of data that fails only in certain time zones. Time zone on this machine is {TimeZoneInfo.Local}"); + throw new Exception($"Failed on converting {expectedDto.DateTime} to local time. This is probably a piece of data that fails only in certain time zones. Time zone on this machine is {TimeZoneInfo.Local}"); } } else @@ -128,7 +128,7 @@ namespace System.Buffers.Text.Tests string text; if ((text = pseudoDateTime.DefaultString) != null) { - yield return new ParserTestData<DateTimeOffset>(text, expectedDto, default(char), pseudoDateTime.ExpectSuccess); + yield return new ParserTestData<DateTimeOffset>(text, expectedDto, default, pseudoDateTime.ExpectSuccess); } if ((text = pseudoDateTime.GFormatString) != null) diff --git a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.DecimalsAndFloats.cs b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.DecimalsAndFloats.cs index 9ac948a79b..5e7b079251 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.DecimalsAndFloats.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.DecimalsAndFloats.cs @@ -21,7 +21,7 @@ namespace System.Buffers.Text.Tests continue; MutableDecimal d = ftd.Value.ToMutableDecimal(); - if (d.High == 0 && d.Mid == 0 && d.Low == 0 && d.IsNegative) + if (d.High == 0 && d.Mid == 0 && d.Low == 0 && d.IsNegative) continue; // -0 is not roundtrippable foreach (ParserTestData<decimal> testData in new FormatterTestData<decimal>[] { ftd }.ToParserTheoryDataCollection()) diff --git a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Integer.cs b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Integer.cs index 900ab39389..8e12d876b3 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Integer.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Integer.cs @@ -200,7 +200,7 @@ namespace System.Buffers.Text.Tests { foreach (string integerNegativeInput in GeneralIntegerNegativeInputs) { - yield return new ParserTestData<T>(integerNegativeInput, default(T), format.Symbol, expectedSuccess: false); + yield return new ParserTestData<T>(integerNegativeInput, default, format.Symbol, expectedSuccess: false); } // The hex format always parses as an unsigned number. That violates the assumptions made by this next set of test data. @@ -223,13 +223,13 @@ namespace System.Buffers.Text.Tests { BigInteger bigValue = maxValue + offset; string text = bigValue.ToString(format.Symbol.ToString()); - yield return new ParserTestData<T>(text, default(T), format.Symbol, expectedSuccess: false); + yield return new ParserTestData<T>(text, default, format.Symbol, expectedSuccess: false); } { BigInteger bigValue = maxValue * 10; string text = bigValue.ToString(format.Symbol.ToString()); - yield return new ParserTestData<T>(text, default(T), format.Symbol, expectedSuccess: false); + yield return new ParserTestData<T>(text, default, format.Symbol, expectedSuccess: false); } if (isSigned) // No such thing as an underflow for unsigned integer parsing... @@ -249,13 +249,13 @@ namespace System.Buffers.Text.Tests { BigInteger bigValue = minValue + offset; string text = bigValue.ToString(format.Symbol.ToString()); - yield return new ParserTestData<T>(text, default(T), format.Symbol, expectedSuccess: false); + yield return new ParserTestData<T>(text, default, format.Symbol, expectedSuccess: false); } { BigInteger bigValue = minValue * 10; string text = bigValue.ToString(format.Symbol.ToString()); - yield return new ParserTestData<T>(text, default(T), format.Symbol, expectedSuccess: false); + yield return new ParserTestData<T>(text, default, format.Symbol, expectedSuccess: false); } } } diff --git a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.TimeSpan.cs b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.TimeSpan.cs index d884395eba..74fb809744 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.TimeSpan.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.TimeSpan.cs @@ -178,30 +178,30 @@ namespace System.Buffers.Text.Tests { get { - yield return "1"; - yield return "1.9999999"; - yield return "4294967295"; - yield return "1:2"; - yield return "1:2.9999999"; - yield return "1:4294967295"; + yield return "1"; + yield return "1.9999999"; + yield return "4294967295"; + yield return "1:2"; + yield return "1:2.9999999"; + yield return "1:4294967295"; yield return "1:2:3"; yield return "1.2:3"; yield return "1.2:3:4"; - yield return "1:2:3.9999999"; - yield return "1:2:3.$$$$$$$"; - yield return "1:2:4294967295"; - yield return "1:2:4294967295.9999999"; - yield return "1:2:3:4"; - yield return "1:2:3:4.9999999"; + yield return "1:2:3.9999999"; + yield return "1:2:3.$$$$$$$"; + yield return "1:2:4294967295"; + yield return "1:2:4294967295.9999999"; + yield return "1:2:3:4"; + yield return "1:2:3:4.9999999"; yield return "1:2:3:4.$$$$$$$"; - yield return "1:2:3:4294967295"; + yield return "1:2:3:4294967295"; yield return "1:2:3:4294967295.9999999"; yield return "1.2:3:4.9999999"; yield return "1.2:3:4.$$$$$$$"; yield return "1.2:3:4294967295"; yield return "1.2:3:4294967295.9999999"; - yield return "1.2:3:4:5"; - yield return "1.2:3:4:5.9999999"; + yield return "1.2:3:4:5"; + yield return "1.2:3:4:5.9999999"; yield return "1.2:3:4.9999999:"; yield return "1.2:3:4.9999999."; diff --git a/src/System.Memory/tests/ParsersAndFormatters/PseudoDateTime.cs b/src/System.Memory/tests/ParsersAndFormatters/PseudoDateTime.cs index f190ef6419..e546f3e809 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/PseudoDateTime.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/PseudoDateTime.cs @@ -75,7 +75,7 @@ namespace System.Buffers.Text.Tests if (OffsetNegative) offset = -offset; DateTimeOffset dto = new DateTimeOffset(year: Year, month: Month, day: Day, hour: Hour, minute: Minute, second: Second, offset: offset); - dayAbbreviation = s_DayAbbreviations[(int)(dto.DayOfWeek)]; + dayAbbreviation = s_dayAbbreviations[(int)(dto.DayOfWeek)]; } else { @@ -86,7 +86,7 @@ namespace System.Buffers.Text.Tests string monthAbbrevation; if (Month >= 1 && Month <= 12) { - monthAbbrevation = s_MonthAbbreviations[Month - 1]; + monthAbbrevation = s_monthAbbreviations[Month - 1]; } else { @@ -115,7 +115,7 @@ namespace System.Buffers.Text.Tests } } - public string OFormatStringZ => (OffsetHours != 0 || OffsetMinutes != 0)? null : OFormatStringNoOffset + "Z"; + public string OFormatStringZ => (OffsetHours != 0 || OffsetMinutes != 0) ? null : OFormatStringNoOffset + "Z"; public string OFormatStringOffset { get @@ -139,7 +139,7 @@ namespace System.Buffers.Text.Tests public int OffsetMinutes { get; } public bool ExpectSuccess { get; } - private static readonly string[] s_DayAbbreviations = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; - private static readonly string[] s_MonthAbbreviations = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + private static readonly string[] s_dayAbbreviations = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + private static readonly string[] s_monthAbbreviations = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; } } diff --git a/src/System.Memory/tests/ParsersAndFormatters/SupportedFormats.cs b/src/System.Memory/tests/ParsersAndFormatters/SupportedFormats.cs index c1afc44358..929e9e2867 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/SupportedFormats.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/SupportedFormats.cs @@ -116,7 +116,7 @@ namespace System.Buffers.Text.Tests get { // The "default" format for DateTimeOffset is weird - it's like "G" but also suffixes an offset so it doesn't exactly match any of the explicit offsets. - yield return new SupportedFormat(default(char), supportsPrecision: false) { IsDefault = true, NoRepresentation = true }; + yield return new SupportedFormat(default, supportsPrecision: false) { IsDefault = true, NoRepresentation = true }; yield return new SupportedFormat('G', supportsPrecision: false); yield return new SupportedFormat('R', supportsPrecision: false); yield return new SupportedFormat('l', supportsPrecision: false); diff --git a/src/System.Memory/tests/ParsersAndFormatters/TestData.cs b/src/System.Memory/tests/ParsersAndFormatters/TestData.cs index 7fec56e3f5..3e6751e66f 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/TestData.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/TestData.cs @@ -12,7 +12,7 @@ namespace System.Buffers.Text.Tests // internal static partial class TestData { - public static readonly IEnumerable<byte> Precisions = new byte[] { StandardFormat.NoPrecision, 0, 1, 3, 10, StandardFormat.MaxPrecision }; + public static readonly IEnumerable<byte> s_precisions = new byte[] { StandardFormat.NoPrecision, 0, 1, 3, 10, StandardFormat.MaxPrecision }; public static IEnumerable<object[]> IntegerTypesTheoryData => IntegerTypes.Select(t => new object[] { t }); diff --git a/src/System.Memory/tests/ParsersAndFormatters/TestUtils.cs b/src/System.Memory/tests/ParsersAndFormatters/TestUtils.cs index cbf23abd9b..f02f6fefdf 100644 --- a/src/System.Memory/tests/ParsersAndFormatters/TestUtils.cs +++ b/src/System.Memory/tests/ParsersAndFormatters/TestUtils.cs @@ -13,7 +13,7 @@ namespace System.Buffers.Text.Tests public static MutableDecimal ToMutableDecimal(this decimal d) { int[] bits = decimal.GetBits(d); - return new MutableDecimal() { High = (uint)bits[0], Low = (uint)bits[1], Mid = (uint)bits[2], Flags = (uint)bits[3] }; + return new MutableDecimal() { High = (uint)bits[0], Low = (uint)bits[1], Mid = (uint)bits[2], Flags = (uint)bits[3] }; } public static decimal ToDecimal(this MutableDecimal md) diff --git a/src/System.Memory/tests/Performance/Perf.Base64EncodeDecode.cs b/src/System.Memory/tests/Performance/Perf.Base64EncodeDecode.cs index 97c5c73a0b..201bd11942 100644 --- a/src/System.Memory/tests/Performance/Perf.Base64EncodeDecode.cs +++ b/src/System.Memory/tests/Performance/Perf.Base64EncodeDecode.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.Xunit.Performance; -using System.Text; using Xunit; namespace System.Buffers.Text.Tests @@ -23,8 +22,10 @@ namespace System.Buffers.Text.Tests Base64TestHelper.InitalizeBytes(source); Span<byte> destination = new byte[Base64.GetMaxEncodedToUtf8Length(numberOfBytes)]; - foreach (var iteration in Benchmark.Iterations) { - using (iteration.StartMeasurement()) { + foreach (var iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { for (int i = 0; i < Benchmark.InnerIterationCount; i++) Base64.EncodeToUtf8(source, destination, out int consumed, out int written); } @@ -46,8 +47,10 @@ namespace System.Buffers.Text.Tests Base64TestHelper.InitalizeBytes(source); Span<byte> destination = new byte[Base64.GetMaxEncodedToUtf8Length(numberOfBytes) - 1]; - foreach (var iteration in Benchmark.Iterations) { - using (iteration.StartMeasurement()) { + foreach (var iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { for (int i = 0; i < Benchmark.InnerIterationCount; i++) Base64.EncodeToUtf8(source, destination, out int consumed, out int written); } @@ -65,8 +68,10 @@ namespace System.Buffers.Text.Tests Base64TestHelper.InitalizeBytes(source.AsSpan()); var destination = new char[Base64.GetMaxEncodedToUtf8Length(numberOfBytes)]; - foreach (var iteration in Benchmark.Iterations) { - using (iteration.StartMeasurement()) { + foreach (var iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { for (int i = 0; i < Benchmark.InnerIterationCount; i++) Convert.ToBase64CharArray(source, 0, source.Length, destination, 0); } @@ -85,8 +90,10 @@ namespace System.Buffers.Text.Tests Span<byte> encoded = new byte[Base64.GetMaxEncodedToUtf8Length(numberOfBytes)]; Base64.EncodeToUtf8(source, encoded, out _, out _); - foreach (var iteration in Benchmark.Iterations) { - using (iteration.StartMeasurement()) { + foreach (var iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { for (int i = 0; i < Benchmark.InnerIterationCount; i++) Base64.DecodeFromUtf8(encoded, source, out int bytesConsumed, out int bytesWritten); } @@ -111,8 +118,10 @@ namespace System.Buffers.Text.Tests source = source.Slice(0, source.Length - 1); - foreach (var iteration in Benchmark.Iterations) { - using (iteration.StartMeasurement()) { + foreach (var iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { for (int i = 0; i < Benchmark.InnerIterationCount; i++) Base64.DecodeFromUtf8(encoded, source, out int bytesConsumed, out int bytesWritten); } @@ -130,8 +139,10 @@ namespace System.Buffers.Text.Tests Base64TestHelper.InitalizeBytes(source); ReadOnlySpan<char> encoded = Convert.ToBase64String(source.ToArray()).ToCharArray(); - foreach (var iteration in Benchmark.Iterations) { - using (iteration.StartMeasurement()) { + foreach (var iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { for (int i = 0; i < Benchmark.InnerIterationCount; i++) Convert.TryFromBase64Chars(encoded, source, out int bytesWritten); } @@ -208,7 +219,7 @@ namespace System.Buffers.Text.Tests int length = Base64.GetMaxEncodedToUtf8Length(numberOfBytes); Span<byte> encodedSpan = new byte[length]; Base64.EncodeToUtf8(source, encodedSpan, out _, out _); - + Span<byte> backupSpan = encodedSpan.ToArray(); int bytesWritten = 0; diff --git a/src/System.Memory/tests/Performance/Perf.MemorySlice.cs b/src/System.Memory/tests/Performance/Perf.MemorySlice.cs index f8f3aa2f3f..0d28fcb7f1 100644 --- a/src/System.Memory/tests/Performance/Perf.MemorySlice.cs +++ b/src/System.Memory/tests/Performance/Perf.MemorySlice.cs @@ -10,7 +10,7 @@ namespace System.Memory.Tests public class MemorySlice { private const int InnerCount = 1000; - volatile static int volatileInt = 0; + volatile static int s_volatileInt = 0; [Benchmark(InnerIterationCount = InnerCount)] [InlineData(1000)] @@ -34,7 +34,7 @@ namespace System.Memory.Tests } } } - volatileInt = localInt; + s_volatileInt = localInt; } } @@ -60,7 +60,7 @@ namespace System.Memory.Tests } } } - volatileInt = localInt; + s_volatileInt = localInt; } } @@ -87,7 +87,7 @@ namespace System.Memory.Tests } } } - volatileInt = localInt; + s_volatileInt = localInt; } } @@ -114,7 +114,7 @@ namespace System.Memory.Tests } } } - volatileInt = localInt; + s_volatileInt = localInt; } } @@ -136,7 +136,7 @@ namespace System.Memory.Tests } } - volatileInt = result.Count; + s_volatileInt = result.Count; } [Benchmark(InnerIterationCount = InnerCount)] @@ -157,7 +157,7 @@ namespace System.Memory.Tests } } - volatileInt = result.Count; + s_volatileInt = result.Count; } } } diff --git a/src/System.Memory/tests/Performance/Perf.Span.BinaryReadAndWrite.cs b/src/System.Memory/tests/Performance/Perf.Span.BinaryReadAndWrite.cs index dbcdc998fb..8c561f961d 100644 --- a/src/System.Memory/tests/Performance/Perf.Span.BinaryReadAndWrite.cs +++ b/src/System.Memory/tests/Performance/Perf.Span.BinaryReadAndWrite.cs @@ -7,7 +7,6 @@ using Xunit; using System.Net; using static System.Buffers.Binary.BinaryPrimitives; -using static System.TestHelpers; namespace System.Buffers.Binary.Tests { @@ -47,7 +46,7 @@ namespace System.Buffers.Binary.Tests } } - Assert.Equal(TestHelpers.testExplicitStruct, readStruct); + Assert.Equal(TestHelpers.s_testExplicitStruct, readStruct); } [Benchmark(InnerIterationCount = InnerCount)] @@ -82,7 +81,7 @@ namespace System.Buffers.Binary.Tests } } - Assert.Equal(TestHelpers.testExplicitStruct, readStruct); + Assert.Equal(TestHelpers.s_testExplicitStruct, readStruct); } [Benchmark(InnerIterationCount = InnerCount)] @@ -116,7 +115,7 @@ namespace System.Buffers.Binary.Tests } } - Assert.Equal(TestHelpers.testExplicitStruct, readStruct); + Assert.Equal(TestHelpers.s_testExplicitStruct, readStruct); } [Benchmark(InnerIterationCount = InnerCount)] @@ -150,7 +149,7 @@ namespace System.Buffers.Binary.Tests } } - Assert.Equal(TestHelpers.testExplicitStruct, readStruct); + Assert.Equal(TestHelpers.s_testExplicitStruct, readStruct); } [Benchmark(InnerIterationCount = InnerCount)] @@ -185,7 +184,7 @@ namespace System.Buffers.Binary.Tests } } - Assert.Equal(TestHelpers.testExplicitStruct, readStruct); + Assert.Equal(TestHelpers.s_testExplicitStruct, readStruct); } [Benchmark(InnerIterationCount = InnerCount)] @@ -235,14 +234,14 @@ namespace System.Buffers.Binary.Tests } } - Assert.Equal(TestHelpers.testExplicitStruct, readStruct); + Assert.Equal(TestHelpers.s_testExplicitStruct, readStruct); } [Benchmark(InnerIterationCount = InnerCount)] private static void MeasureReverseEndianness() { var myArray = new int[1000]; - + foreach (var iteration in Benchmark.Iterations) { using (iteration.StartMeasurement()) diff --git a/src/System.Memory/tests/Performance/Perf.Span.IndexOf.cs b/src/System.Memory/tests/Performance/Perf.Span.IndexOf.cs index 75575338a6..dd678920f4 100644 --- a/src/System.Memory/tests/Performance/Perf.Span.IndexOf.cs +++ b/src/System.Memory/tests/Performance/Perf.Span.IndexOf.cs @@ -19,7 +19,7 @@ namespace System.Memory.Tests public void SpanIndexOfChar(int size) { Span<char> charSpan = new char[size]; - charSpan[size/2] = '5'; + charSpan[size / 2] = '5'; int index = 0; foreach (BenchmarkIteration iteration in Benchmark.Iterations) @@ -32,9 +32,9 @@ namespace System.Memory.Tests } } } - Assert.Equal(size/2, index); + Assert.Equal(size / 2, index); } - + [Benchmark(InnerIterationCount = InnerCount)] [InlineData(1)] [InlineData(10)] @@ -43,7 +43,7 @@ namespace System.Memory.Tests public void SpanIndexOfCharAsBytes(int size) { Span<char> charSpan = new char[size]; - charSpan[size/2] = '5'; + charSpan[size / 2] = '5'; Span<byte> byteSpan = charSpan.AsBytes(); int index = 0; @@ -59,7 +59,7 @@ namespace System.Memory.Tests } Assert.Equal(size > 1 ? size : 0, index); } - + [Benchmark(InnerIterationCount = InnerCount)] [InlineData(1)] [InlineData(10)] @@ -67,10 +67,10 @@ namespace System.Memory.Tests [InlineData(1000)] public void StringIndexOfChar(int size) { - string str = new string('0', size/2) + "5"; + string str = new string('0', size / 2) + "5"; if (size > 1) { - str += new string('0', size/2 - 1); + str += new string('0', size / 2 - 1); } int index = 0; @@ -84,7 +84,83 @@ namespace System.Memory.Tests } } } - Assert.Equal(size/2, index); + Assert.Equal(size / 2, index); + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public void SpanLastIndexOfChar(int size) + { + Span<char> charSpan = new char[size]; + charSpan[size / 2] = '5'; + + int index = 0; + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + index |= charSpan.LastIndexOf('5'); + } + } + } + Assert.Equal(size / 2, index); + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public void SpanLastIndexOfCharAsBytes(int size) + { + Span<char> charSpan = new char[size]; + charSpan[size / 2] = '5'; + Span<byte> byteSpan = charSpan.AsBytes(); + + int index = 0; + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + index |= byteSpan.LastIndexOf<byte>(53); // '5' = 53 + } + } + } + Assert.Equal(size > 1 ? size : 0, index); + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public void StringLastIndexOfChar(int size) + { + string str = new string('0', size / 2) + "5"; + if (size > 1) + { + str += new string('0', size / 2 - 1); + } + + int index = 0; + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + index |= str.LastIndexOf('5'); + } + } + } + Assert.Equal(size / 2, index); } } } diff --git a/src/System.Memory/tests/Performance/Perf.Utf8Parser.cs b/src/System.Memory/tests/Performance/Perf.Utf8Parser.cs index 7794ad752d..7d1294f70d 100644 --- a/src/System.Memory/tests/Performance/Perf.Utf8Parser.cs +++ b/src/System.Memory/tests/Performance/Perf.Utf8Parser.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Text; -using System.Runtime.CompilerServices; using Microsoft.Xunit.Performance; using Xunit; diff --git a/src/System.Memory/tests/ReadOnlyMemory/CopyTo.cs b/src/System.Memory/tests/ReadOnlyMemory/CopyTo.cs index e9f2f5d65b..319840d52c 100644 --- a/src/System.Memory/tests/ReadOnlyMemory/CopyTo.cs +++ b/src/System.Memory/tests/ReadOnlyMemory/CopyTo.cs @@ -91,7 +91,7 @@ namespace System.MemoryTests int[] dst = { 99, 100 }; ReadOnlyMemory<int> srcMemory = src; - Assert.Throws<ArgumentException>( () => srcMemory.CopyTo(dst) ); + Assert.Throws<ArgumentException>(() => srcMemory.CopyTo(dst)); int[] expected = { 99, 100 }; Assert.Equal<int>(expected, dst); // CopyTo() checks for sufficient space before doing any copying. } diff --git a/src/System.Memory/tests/ReadOnlyMemory/ImplicitConversion.cs b/src/System.Memory/tests/ReadOnlyMemory/ImplicitConversion.cs index 205dfd28c3..c3cc2f902a 100644 --- a/src/System.Memory/tests/ReadOnlyMemory/ImplicitConversion.cs +++ b/src/System.Memory/tests/ReadOnlyMemory/ImplicitConversion.cs @@ -45,7 +45,7 @@ namespace System.MemoryTests long[] b = { 1, -3, 7, -15, 31 }; ArraySegment<long> segmentLong = new ArraySegment<long>(b, 1, 3); CastReadOnly<long>(segmentLong, -3, 7, -15); - + object o1 = new object(); object o2 = new object(); object o3 = new object(); @@ -61,7 +61,7 @@ namespace System.MemoryTests int[] empty = Array.Empty<int>(); ArraySegment<int> emptySegment = new ArraySegment<int>(empty); CastReadOnly<int>(emptySegment); - + int[] a = { 19, -17 }; ArraySegment<int> segmentInt = new ArraySegment<int>(a, 1, 0); CastReadOnly<int>(segmentInt); diff --git a/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs b/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs index a964c32808..077459be1c 100644 --- a/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs +++ b/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs @@ -181,8 +181,10 @@ namespace System.SpanTests } finally { - if (allocatedFirst) AllocationHelper.ReleaseNative(ref memBlockFirst); - if (allocatedSecond) AllocationHelper.ReleaseNative(ref memBlockSecond); + if (allocatedFirst) + AllocationHelper.ReleaseNative(ref memBlockFirst); + if (allocatedSecond) + AllocationHelper.ReleaseNative(ref memBlockSecond); } } } diff --git a/src/System.Memory/tests/ReadOnlySpan/CtorPointerInt.cs b/src/System.Memory/tests/ReadOnlySpan/CtorPointerInt.cs index 3cf399b055..8f2d42f6f9 100644 --- a/src/System.Memory/tests/ReadOnlySpan/CtorPointerInt.cs +++ b/src/System.Memory/tests/ReadOnlySpan/CtorPointerInt.cs @@ -17,7 +17,7 @@ namespace System.SpanTests unsafe { int[] a = { 90, 91, 92 }; - fixed (int *pa = a) + fixed (int* pa = a) { ReadOnlySpan<int> span = new ReadOnlySpan<int>(pa, 3); span.Validate(90, 91, 92); diff --git a/src/System.Memory/tests/ReadOnlySpan/IndexOf.T.cs b/src/System.Memory/tests/ReadOnlySpan/IndexOf.T.cs index 3ace67ee0e..2c80369662 100644 --- a/src/System.Memory/tests/ReadOnlySpan/IndexOf.T.cs +++ b/src/System.Memory/tests/ReadOnlySpan/IndexOf.T.cs @@ -27,7 +27,7 @@ namespace System.SpanTests a[i] = 10 * (i + 1); } ReadOnlySpan<int> span = new ReadOnlySpan<int>(a); - + for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target = a[targetIndex]; @@ -116,5 +116,74 @@ namespace System.SpanTests Assert.Equal(-1, idx); } } + + [Fact] + public static void ZeroLengthIndexOf_String() + { + ReadOnlySpan<string> sp = new ReadOnlySpan<string>(Array.Empty<string>()); + int idx = sp.IndexOf("a"); + Assert.Equal(-1, idx); + } + + [Fact] + public static void TestMatchIndexOf_String() + { + for (int length = 0; length < 32; length++) + { + string[] a = new string[length]; + for (int i = 0; i < length; i++) + { + a[i] = (10 * (i + 1)).ToString(); + } + ReadOnlySpan<string> span = new ReadOnlySpan<string>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + string target = a[targetIndex]; + int idx = span.IndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestNoMatchIndexOf_String() + { + var rnd = new Random(42); + for (int length = 0; length <= byte.MaxValue; length++) + { + string[] a = new string[length]; + string target = (rnd.Next(0, 256)).ToString(); + for (int i = 0; i < length; i++) + { + string val = (i + 1).ToString(); + a[i] = val == target ? (target + 1) : val; + } + ReadOnlySpan<string> span = new ReadOnlySpan<string>(a); + + int idx = span.IndexOf(target); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestMultipleMatchIndexOf_String() + { + for (int length = 2; length < 32; length++) + { + string[] a = new string[length]; + for (int i = 0; i < length; i++) + { + a[i] = (10 * (i + 1)).ToString(); + } + + a[length - 1] = "5555"; + a[length - 2] = "5555"; + + ReadOnlySpan<string> span = new ReadOnlySpan<string>(a); + int idx = span.IndexOf("5555"); + Assert.Equal(length - 2, idx); + } + } } } diff --git a/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs b/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs index f37938f941..4f902c7fc8 100644 --- a/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs +++ b/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs @@ -28,7 +28,7 @@ namespace System.SpanTests for (int i = 0; i < length; i++) { - byte target0 = default(byte); + byte target0 = default; int idx = span.IndexOf<byte>(target0); Assert.Equal(0, idx); } @@ -215,7 +215,7 @@ namespace System.SpanTests byte[] a = new byte[length]; ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a); - byte[] targets = { default(byte), 99 }; + byte[] targets = { default, 99 }; for (int i = 0; i < length; i++) { @@ -346,7 +346,7 @@ namespace System.SpanTests byte[] a = new byte[length]; ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a); - byte[] targets = { default(byte), 99, 98 }; + byte[] targets = { default, 99, 98 }; for (int i = 0; i < length; i++) { @@ -486,7 +486,7 @@ namespace System.SpanTests byte[] a = new byte[length]; ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a); - var values = new ReadOnlySpan<byte>(new byte[] { default(byte), 99, 98, 0 }); + var values = new ReadOnlySpan<byte>(new byte[] { default, 99, 98, 0 }); for (int i = 0; i < length; i++) { diff --git a/src/System.Memory/tests/ReadOnlySpan/IndexOf.char.cs b/src/System.Memory/tests/ReadOnlySpan/IndexOf.char.cs index 24ce08b73e..2e71529b10 100644 --- a/src/System.Memory/tests/ReadOnlySpan/IndexOf.char.cs +++ b/src/System.Memory/tests/ReadOnlySpan/IndexOf.char.cs @@ -27,7 +27,7 @@ namespace System.SpanTests a[i] = (char)(i + 1); } ReadOnlySpan<char> span = new ReadOnlySpan<char>(a); - + for (int targetIndex = 0; targetIndex < length; targetIndex++) { char target = a[targetIndex]; diff --git a/src/System.Memory/tests/ReadOnlySpan/IndexOfSequence.T.cs b/src/System.Memory/tests/ReadOnlySpan/IndexOfSequence.T.cs index 49a863acb2..401e7c6aec 100644 --- a/src/System.Memory/tests/ReadOnlySpan/IndexOfSequence.T.cs +++ b/src/System.Memory/tests/ReadOnlySpan/IndexOfSequence.T.cs @@ -119,5 +119,117 @@ namespace System.SpanTests int index = span.IndexOf(value); Assert.Equal(-1, index); } + + [Fact] + public static void IndexOfSequenceMatchAtStart_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "5", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "5", "1", "77" }); + int index = span.IndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void IndexOfSequenceMultipleMatch_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "1", "2", "3", "1", "2", "3", "1", "2", "3" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "2", "3" }); + int index = span.IndexOf(value); + Assert.Equal(1, index); + } + + [Fact] + public static void IndexOfSequenceRestart_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "77", "77", "88" }); + int index = span.IndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void IndexOfSequenceNoMatch_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "77", "77", "88", "99" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void IndexOfSequenceNotEvenAHeadMatch_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "100", "77", "88", "99" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void IndexOfSequenceMatchAtVeryEnd_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "3", "4", "5" }); + int index = span.IndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void IndexOfSequenceJustPastVeryEnd_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "3", "4", "5" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void IndexOfSequenceZeroLengthValue_String() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(Array.Empty<string>()); + int index = span.IndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void IndexOfSequenceZeroLengthSpan_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(Array.Empty<string>()); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "1", "2", "3" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void IndexOfSequenceLengthOneValue_String() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "2" }); + int index = span.IndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void IndexOfSequenceLengthOneValueAtVeryEnd_String() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "5" }); + int index = span.IndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void IndexOfSequenceLengthOneValueJustPasttVeryEnd_String() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "5" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } } } diff --git a/src/System.Memory/tests/ReadOnlySpan/LastIndexOf.T.cs b/src/System.Memory/tests/ReadOnlySpan/LastIndexOf.T.cs new file mode 100644 index 0000000000..9738142626 --- /dev/null +++ b/src/System.Memory/tests/ReadOnlySpan/LastIndexOf.T.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class ReadOnlySpanTests + { + [Fact] + public static void ZeroLengthLastIndexOf() + { + ReadOnlySpan<int> sp = new ReadOnlySpan<int>(Array.Empty<int>()); + int idx = sp.LastIndexOf(0); + Assert.Equal(-1, idx); + } + + [Fact] + public static void TestMatchLastIndexOf() + { + for (int length = 0; length < 32; length++) + { + int[] a = new int[length]; + for (int i = 0; i < length; i++) + { + a[i] = 10 * (i + 1); + } + ReadOnlySpan<int> span = new ReadOnlySpan<int>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + int target = a[targetIndex]; + int idx = span.LastIndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestMultipleMatchLastIndexOf() + { + for (int length = 2; length < 32; length++) + { + int[] a = new int[length]; + for (int i = 0; i < length; i++) + { + a[i] = 10 * (i + 1); + } + + a[length - 1] = 5555; + a[length - 2] = 5555; + + ReadOnlySpan<int> span = new ReadOnlySpan<int>(a); + int idx = span.LastIndexOf(5555); + Assert.Equal(length - 1, idx); + } + } + + [Fact] + public static void OnNoMatchMakeSureEveryElementIsComparedLastIndexOf() + { + for (int length = 0; length < 100; length++) + { + TIntLog log = new TIntLog(); + + TInt[] a = new TInt[length]; + for (int i = 0; i < length; i++) + { + a[i] = new TInt(10 * (i + 1), log); + } + ReadOnlySpan<TInt> span = new ReadOnlySpan<TInt>(a); + int idx = span.LastIndexOf(new TInt(9999, log)); + Assert.Equal(-1, idx); + + // Since we asked for a non-existent value, make sure each element of the array was compared once. + // (Strictly speaking, it would not be illegal for IndexOf to compare an element more than once but + // that would be a non-optimal implementation and a red flag. So we'll stick with the stricter test.) + Assert.Equal(a.Length, log.Count); + foreach (TInt elem in a) + { + int numCompares = log.CountCompares(elem.Value, 9999); + Assert.True(numCompares == 1, $"Expected {numCompares} == 1 for element {elem.Value}."); + } + } + } + + [Fact] + public static void MakeSureNoChecksGoOutOfRangeLastIndexOf() + { + const int GuardValue = 77777; + const int GuardLength = 50; + + Action<int, int> checkForOutOfRangeAccess = + delegate (int x, int y) + { + if (x == GuardValue || y == GuardValue) + throw new Exception("Detected out of range access in IndexOf()"); + }; + + for (int length = 0; length < 100; length++) + { + TInt[] a = new TInt[GuardLength + length + GuardLength]; + for (int i = 0; i < a.Length; i++) + { + a[i] = new TInt(GuardValue, checkForOutOfRangeAccess); + } + + for (int i = 0; i < length; i++) + { + a[GuardLength + i] = new TInt(10 * (i + 1), checkForOutOfRangeAccess); + } + + ReadOnlySpan<TInt> span = new ReadOnlySpan<TInt>(a, GuardLength, length); + int idx = span.LastIndexOf(new TInt(9999, checkForOutOfRangeAccess)); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void ZeroLengthLastIndexOf_String() + { + ReadOnlySpan<string> sp = new ReadOnlySpan<string>(Array.Empty<string>()); + int idx = sp.LastIndexOf("a"); + Assert.Equal(-1, idx); + } + + [Fact] + public static void TestMatchLastIndexOf_String() + { + for (int length = 0; length < 32; length++) + { + string[] a = new string[length]; + for (int i = 0; i < length; i++) + { + a[i] = (10 * (i + 1)).ToString(); + } + ReadOnlySpan<string> span = new ReadOnlySpan<string>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + string target = a[targetIndex]; + int idx = span.LastIndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestNoMatchLastIndexOf_String() + { + var rnd = new Random(42); + for (int length = 0; length <= byte.MaxValue; length++) + { + string[] a = new string[length]; + string target = (rnd.Next(0, 256)).ToString(); + for (int i = 0; i < length; i++) + { + string val = (i + 1).ToString(); + a[i] = val == target ? (target + 1) : val; + } + ReadOnlySpan<string> span = new ReadOnlySpan<string>(a); + + int idx = span.LastIndexOf(target); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestMultipleMatchLastIndexOf_String() + { + for (int length = 2; length < 32; length++) + { + string[] a = new string[length]; + for (int i = 0; i < length; i++) + { + a[i] = (10 * (i + 1)).ToString(); + } + + a[length - 1] = "5555"; + a[length - 2] = "5555"; + + ReadOnlySpan<string> span = new ReadOnlySpan<string>(a); + int idx = span.LastIndexOf("5555"); + Assert.Equal(length - 1, idx); + } + } + } +} diff --git a/src/System.Memory/tests/ReadOnlySpan/LastIndexOf.byte.cs b/src/System.Memory/tests/ReadOnlySpan/LastIndexOf.byte.cs new file mode 100644 index 0000000000..37cecc6c8f --- /dev/null +++ b/src/System.Memory/tests/ReadOnlySpan/LastIndexOf.byte.cs @@ -0,0 +1,149 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Numerics; +using Xunit; + +namespace System.SpanTests +{ + public static partial class ReadOnlySpanTests + { + [Fact] + public static void ZeroLengthLastIndexOf_Byte() + { + ReadOnlySpan<byte> sp = new ReadOnlySpan<byte>(Array.Empty<byte>()); + int idx = sp.LastIndexOf<byte>(0); + Assert.Equal(-1, idx); + } + + [Fact] + public static void DefaultFilledLastIndexOf_Byte() + { + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a); + + for (int i = 0; i < length; i++) + { + byte target0 = default; + int idx = span.LastIndexOf(target0); + Assert.Equal(length - 1, idx); + } + } + } + + [Fact] + public static void TestMatchLastIndexOf_Byte() + { + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + for (int i = 0; i < length; i++) + { + a[i] = (byte)(i + 1); + } + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + byte target = a[targetIndex]; + int idx = span.LastIndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestNoMatchLastIndexOf_Byte() + { + var rnd = new Random(42); + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + byte target = (byte)rnd.Next(0, 256); + for (int i = 0; i < length; i++) + { + byte val = (byte)(i + 1); + a[i] = val == target ? (byte)(target + 1) : val; + } + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a); + + int idx = span.LastIndexOf(target); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestAllignmentNoMatchLastIndexOf_Byte() + { + byte[] array = new byte[4 * Vector<byte>.Count]; + for (var i = 0; i < Vector<byte>.Count; i++) + { + var span = new ReadOnlySpan<byte>(array, i, 3 * Vector<byte>.Count); + int idx = span.LastIndexOf<byte>(5); + Assert.Equal(-1, idx); + + span = new ReadOnlySpan<byte>(array, i, 3 * Vector<byte>.Count - 3); + idx = span.LastIndexOf<byte>(5); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestAllignmentMatchLastIndexOf_Byte() + { + byte[] array = new byte[4 * Vector<byte>.Count]; + for (int i = 0; i < array.Length; i++) + { + array[i] = 5; + } + for (var i = 0; i < Vector<byte>.Count; i++) + { + var span = new ReadOnlySpan<byte>(array, i, 3 * Vector<byte>.Count); + int idx = span.LastIndexOf<byte>(5); + Assert.Equal(span.Length - 1, idx); + + span = new ReadOnlySpan<byte>(array, i, 3 * Vector<byte>.Count - 3); + idx = span.LastIndexOf<byte>(5); + Assert.Equal(span.Length - 1, idx); + } + } + + [Fact] + public static void TestMultipleMatchLastIndexOf_Byte() + { + for (int length = 2; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + for (int i = 0; i < length; i++) + { + byte val = (byte)(i + 1); + a[i] = val == 200 ? (byte)201 : val; + } + + a[length - 1] = 200; + a[length - 2] = 200; + + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a); + int idx = span.LastIndexOf<byte>(200); + Assert.Equal(length - 1, idx); + } + } + + [Fact] + public static void MakeSureNoChecksGoOutOfRangeLastIndexOf_Byte() + { + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length + 2]; + a[0] = 99; + a[length + 1] = 99; + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a, 1, length); + int index = span.LastIndexOf<byte>(99); + Assert.Equal(-1, index); + } + } + } +} diff --git a/src/System.Memory/tests/ReadOnlySpan/LastIndexOf.char.cs b/src/System.Memory/tests/ReadOnlySpan/LastIndexOf.char.cs new file mode 100644 index 0000000000..9a60ea90c9 --- /dev/null +++ b/src/System.Memory/tests/ReadOnlySpan/LastIndexOf.char.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class ReadOnlySpanTests + { + [Fact] + public static void ZeroLengthLastIndexOf_Char() + { + ReadOnlySpan<char> sp = new ReadOnlySpan<char>(Array.Empty<char>()); + int idx = sp.LastIndexOf((char)0); + Assert.Equal(-1, idx); + } + + [Fact] + public static void TestMatchLastIndexOf_Char() + { + for (int length = 0; length < 32; length++) + { + char[] a = new char[length]; + for (int i = 0; i < length; i++) + { + a[i] = (char)(i + 1); + } + ReadOnlySpan<char> span = new ReadOnlySpan<char>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + char target = a[targetIndex]; + int idx = span.LastIndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestMultipleMatchLastIndexOf_Char() + { + for (int length = 2; length < 32; length++) + { + char[] a = new char[length]; + for (int i = 0; i < length; i++) + { + a[i] = (char)(i + 1); + } + + a[length - 1] = (char)200; + a[length - 2] = (char)200; + + ReadOnlySpan<char> span = new ReadOnlySpan<char>(a); + int idx = span.LastIndexOf((char)200); + Assert.Equal(length - 1, idx); + } + } + + [Fact] + public static void MakeSureNoChecksGoOutOfRangeLastIndexOf_Char() + { + for (int length = 0; length < 100; length++) + { + char[] a = new char[length + 2]; + a[0] = '9'; + a[length + 1] = '9'; + ReadOnlySpan<char> span = new ReadOnlySpan<char>(a, 1, length); + int index = span.LastIndexOf('9'); + Assert.Equal(-1, index); + } + } + } +} diff --git a/src/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.T.cs b/src/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.T.cs new file mode 100644 index 0000000000..2dde13b322 --- /dev/null +++ b/src/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.T.cs @@ -0,0 +1,245 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class ReadOnlySpanTests + { + [Fact] + public static void LastIndexOfSequenceMatchAtStart() + { + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 5, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 5, 1, 77 }); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceMultipleMatch() + { + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 1, 2, 3, 1, 2, 3, 1, 2, 3, 1 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 2, 3 }); + int index = span.LastIndexOf(value); + Assert.Equal(7, index); + } + + [Fact] + public static void LastIndexOfSequenceRestart() + { + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 8, 9, 77, 0, 1 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 77, 77, 88 }); + int index = span.LastIndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void LastIndexOfSequenceNoMatch() + { + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 77, 77, 88, 99 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceNotEvenAHeadMatch() + { + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 100, 77, 88, 99 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtVeryEnd() + { + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 2, 3, 4, 5 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 3, 4, 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void LastIndexOfSequenceJustPastVeryEnd() + { + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 2, 3, 4, 5 }, 0, 5); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 3, 4, 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthValue() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(Array.Empty<int>()); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthSpan() + { + ReadOnlySpan<int> span = new ReadOnlySpan<int>(Array.Empty<int>()); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 1, 2, 3 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValue() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 2, 3, 4, 5 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 2 }); + int index = span.LastIndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueAtVeryEnd() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 2, 3, 4, 5 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueMultipleTimes() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 5, 3, 4, 5 }); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<int> span = new ReadOnlySpan<int>(new int[] { 0, 1, 2, 3, 4, 5 }, 0, 5); + ReadOnlySpan<int> value = new ReadOnlySpan<int>(new int[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtStart_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "5", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "5", "1", "77" }); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceMultipleMatch_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "1", "2", "3", "1", "2", "3", "1", "2", "3" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "2", "3" }); + int index = span.LastIndexOf(value); + Assert.Equal(7, index); + } + + [Fact] + public static void LastIndexOfSequenceRestart_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "8", "9", "77", "0", "1" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "77", "77", "88" }); + int index = span.LastIndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void LastIndexOfSequenceNoMatch_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "77", "77", "88", "99" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceNotEvenAHeadMatch_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "100", "77", "88", "99" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtVeryEnd_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "3", "4", "5" }); + int index = span.LastIndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void LastIndexOfSequenceJustPastVeryEnd_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "3", "4", "5" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthValue_String() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(Array.Empty<string>()); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthSpan_String() + { + ReadOnlySpan<string> span = new ReadOnlySpan<string>(Array.Empty<string>()); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "1", "2", "3" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValue_String() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "2" }); + int index = span.LastIndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueAtVeryEnd_String() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "5" }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd_String() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<string> span = new ReadOnlySpan<string>(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); + ReadOnlySpan<string> value = new ReadOnlySpan<string>(new string[] { "5" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + } +} diff --git a/src/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.byte.cs b/src/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.byte.cs new file mode 100644 index 0000000000..293920a2f7 --- /dev/null +++ b/src/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.byte.cs @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class ReadOnlySpanTests + { + [Fact] + public static void LastIndexOfSequenceMatchAtStart_Byte() + { + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 5, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 5, 1, 77 }); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceMultipleMatch_Byte() + { + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 1, 2, 3, 1, 2, 3, 1, 2, 3, 1 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 2, 3 }); + int index = span.LastIndexOf(value); + Assert.Equal(7, index); + } + + [Fact] + public static void LastIndexOfSequenceRestart_Byte() + { + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 8, 9, 77, 0, 1 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 77, 77, 88 }); + int index = span.LastIndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void LastIndexOfSequenceNoMatch_Byte() + { + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 77, 77, 88, 99 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceNotEvenAHeadMatch_Byte() + { + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 100, 77, 88, 99 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtVeryEnd_Byte() + { + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 3, 4, 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void LastIndexOfSequenceJustPastVeryEnd_Byte() + { + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }, 0, 5); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 3, 4, 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthValue_Byte() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(Array.Empty<byte>()); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthSpan_Byte() + { + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(Array.Empty<byte>()); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 1, 2, 3 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValue_Byte() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 2 }); + int index = span.LastIndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueAtVeryEnd_Byte() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueMultipleTimes_Byte() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 5, 3, 4, 5 }); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd_Byte() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }, 0, 5); + ReadOnlySpan<byte> value = new ReadOnlySpan<byte>(new byte[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + } +} diff --git a/src/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.char.cs b/src/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.char.cs new file mode 100644 index 0000000000..63f6635f76 --- /dev/null +++ b/src/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.char.cs @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class ReadOnlySpanTests + { + [Fact] + public static void LastIndexOfSequenceMatchAtStart_Char() + { + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '5', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '8', '9' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '5', '1', '7' }); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceMultipleMatch_Char() + { + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '1', '2', '3', '1', '2', '3', '1', '2', '3', '1' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '2', '3' }); + int index = span.LastIndexOf(value); + Assert.Equal(7, index); + } + + [Fact] + public static void LastIndexOfSequenceRestart_Char() + { + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '5', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '6', '9', '7', '0', '1' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '7', '7', '8' }); + int index = span.LastIndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void LastIndexOfSequenceNoMatch_Char() + { + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '0', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '8', '9' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '7', '7', '8', 'X' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceNotEvenAHeadMatch_Char() + { + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '0', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '8', '9' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { 'X', '7', '8', '9' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtVeryEnd_Char() + { + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '0', '1', '2', '3', '4', '5' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '3', '4', '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void LastIndexOfSequenceJustPastVeryEnd_Char() + { + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '0', '1', '2', '3', '4', '5' }, 0, 5); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '3', '4', '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthValue_Char() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '0', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '8', '9' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(Array.Empty<char>()); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthSpan_Char() + { + ReadOnlySpan<char> span = new ReadOnlySpan<char>(Array.Empty<char>()); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '1', '2', '3' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValue_Char() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '0', '1', '2', '3', '4', '5' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '2' }); + int index = span.LastIndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueAtVeryEnd_Char() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '0', '1', '2', '3', '4', '5' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueMultipleTimes_Char() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '0', '1', '5', '3', '4', '5' }); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd_Char() + { + // A zero-length value is always "found" at the start of the span. + ReadOnlySpan<char> span = new ReadOnlySpan<char>(new char[] { '0', '1', '2', '3', '4', '5' }, 0, 5); + ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + } +} diff --git a/src/System.Memory/tests/ReadOnlySpan/Overflow.cs b/src/System.Memory/tests/ReadOnlySpan/Overflow.cs index dc9ed088e7..54f9fc7a93 100644 --- a/src/System.Memory/tests/ReadOnlySpan/Overflow.cs +++ b/src/System.Memory/tests/ReadOnlySpan/Overflow.cs @@ -36,9 +36,9 @@ namespace System.SpanTests try { ref Guid memory = ref Unsafe.AsRef<Guid>(memBlock.ToPointer()); - var span = new ReadOnlySpan<Guid>(memBlock.ToPointer(), GuidThreeGiBLimit); + var span = new ReadOnlySpan<Guid>(memBlock.ToPointer(), s_guidThreeGiBLimit); - int bigIndex = checked(GuidTwoGiBLimit + 1); + int bigIndex = checked(s_guidTwoGiBLimit + 1); uint byteOffset = checked((uint)bigIndex * (uint)sizeof(Guid)); Assert.True(byteOffset > int.MaxValue); // Make sure byteOffset actually overflows 2Gb, or this test is pointless. Guid expectedGuid = Guid.NewGuid(); @@ -65,8 +65,7 @@ namespace System.SpanTests private const long TwoGiB = 2L * 1024L * 1024L * 1024L; private const long OneGiB = 1L * 1024L * 1024L * 1024L; - private static readonly int GuidThreeGiBLimit = (int)(ThreeGiB / Unsafe.SizeOf<Guid>()); // sizeof(Guid) requires unsafe keyword and I don't want to mark the entire class unsafe. - private static readonly int GuidTwoGiBLimit = (int)(TwoGiB / Unsafe.SizeOf<Guid>()); - private static readonly int GuidOneGiBLimit = (int)(OneGiB / Unsafe.SizeOf<Guid>()); + private static readonly int s_guidThreeGiBLimit = (int)(ThreeGiB / Unsafe.SizeOf<Guid>()); // sizeof(Guid) requires unsafe keyword and I don't want to mark the entire class unsafe. + private static readonly int s_guidTwoGiBLimit = (int)(TwoGiB / Unsafe.SizeOf<Guid>()); } } diff --git a/src/System.Memory/tests/Span/Clear.cs b/src/System.Memory/tests/Span/Clear.cs index ecd0c4a34f..7fbb5cb697 100644 --- a/src/System.Memory/tests/Span/Clear.cs +++ b/src/System.Memory/tests/Span/Clear.cs @@ -131,7 +131,6 @@ namespace System.SpanTests Assert.Equal<IntPtr>(expected, actual); } - [Fact] public static void ClearValueTypeWithoutReferences() { @@ -202,8 +201,8 @@ namespace System.SpanTests [Fact] public static void ClearEnumType() { - TestEnum[] actual = {TestEnum.e0, TestEnum.e1, TestEnum.e2}; - TestEnum[] expected = {default(TestEnum), default(TestEnum), default(TestEnum) }; + TestEnum[] actual = { TestEnum.e0, TestEnum.e1, TestEnum.e2 }; + TestEnum[] expected = { default, default, default }; var span = new Span<TestEnum>(actual); span.Clear(); @@ -218,9 +217,9 @@ namespace System.SpanTests new TestValueTypeWithReference() { I = 2, S = "b" }, new TestValueTypeWithReference() { I = 3, S = "c" } }; TestValueTypeWithReference[] expected = { - default(TestValueTypeWithReference), - default(TestValueTypeWithReference), - default(TestValueTypeWithReference) }; + default, + default, + default }; var span = new Span<TestValueTypeWithReference>(actual); span.Clear(); diff --git a/src/System.Memory/tests/Span/CopyTo.cs b/src/System.Memory/tests/Span/CopyTo.cs index 22ff1d0150..213354214c 100644 --- a/src/System.Memory/tests/Span/CopyTo.cs +++ b/src/System.Memory/tests/Span/CopyTo.cs @@ -250,8 +250,10 @@ namespace System.SpanTests } finally { - if (allocatedFirst) AllocationHelper.ReleaseNative(ref memBlockFirst); - if (allocatedSecond) AllocationHelper.ReleaseNative(ref memBlockSecond); + if (allocatedFirst) + AllocationHelper.ReleaseNative(ref memBlockFirst); + if (allocatedSecond) + AllocationHelper.ReleaseNative(ref memBlockSecond); } } } diff --git a/src/System.Memory/tests/Span/IndexOf.T.cs b/src/System.Memory/tests/Span/IndexOf.T.cs index 8d9736be83..0da12edee9 100644 --- a/src/System.Memory/tests/Span/IndexOf.T.cs +++ b/src/System.Memory/tests/Span/IndexOf.T.cs @@ -27,7 +27,7 @@ namespace System.SpanTests a[i] = 10 * (i + 1); } Span<int> span = new Span<int>(a); - + for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target = a[targetIndex]; @@ -116,5 +116,74 @@ namespace System.SpanTests Assert.Equal(-1, idx); } } + + [Fact] + public static void ZeroLengthIndexOf_String() + { + Span<string> sp = new Span<string>(Array.Empty<string>()); + int idx = sp.IndexOf("a"); + Assert.Equal(-1, idx); + } + + [Fact] + public static void TestMatchIndexOf_String() + { + for (int length = 0; length < 32; length++) + { + string[] a = new string[length]; + for (int i = 0; i < length; i++) + { + a[i] = (10 * (i + 1)).ToString(); + } + Span<string> span = new Span<string>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + string target = a[targetIndex]; + int idx = span.IndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestNoMatchIndexOf_String() + { + var rnd = new Random(42); + for (int length = 0; length <= byte.MaxValue; length++) + { + string[] a = new string[length]; + string target = (rnd.Next(0, 256)).ToString(); + for (int i = 0; i < length; i++) + { + string val = (i + 1).ToString(); + a[i] = val == target ? (target + 1) : val; + } + Span<string> span = new Span<string>(a); + + int idx = span.IndexOf(target); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestMultipleMatchIndexOf_String() + { + for (int length = 2; length < 32; length++) + { + string[] a = new string[length]; + for (int i = 0; i < length; i++) + { + a[i] = (10 * (i + 1)).ToString(); + } + + a[length - 1] = "5555"; + a[length - 2] = "5555"; + + Span<string> span = new Span<string>(a); + int idx = span.IndexOf("5555"); + Assert.Equal(length - 2, idx); + } + } } } diff --git a/src/System.Memory/tests/Span/IndexOf.byte.cs b/src/System.Memory/tests/Span/IndexOf.byte.cs index 71981631b5..e4a535570a 100644 --- a/src/System.Memory/tests/Span/IndexOf.byte.cs +++ b/src/System.Memory/tests/Span/IndexOf.byte.cs @@ -28,7 +28,7 @@ namespace System.SpanTests for (int i = 0; i < length; i++) { - byte target0 = default(byte); + byte target0 = default; int idx = span.IndexOf<byte>(target0); Assert.Equal(0, idx); } @@ -215,7 +215,7 @@ namespace System.SpanTests byte[] a = new byte[length]; Span<byte> span = new Span<byte>(a); - byte[] targets = { default(byte), 99 }; + byte[] targets = { default, 99 }; for (int i = 0; i < length; i++) { @@ -346,7 +346,7 @@ namespace System.SpanTests byte[] a = new byte[length]; Span<byte> span = new Span<byte>(a); - byte[] targets = { default(byte), 99, 98 }; + byte[] targets = { default, 99, 98 }; for (int i = 0; i < length; i++) { @@ -486,7 +486,7 @@ namespace System.SpanTests byte[] a = new byte[length]; Span<byte> span = new Span<byte>(a); - var values = new ReadOnlySpan<byte>(new byte[] { default(byte), 99, 98, 0 }); + var values = new ReadOnlySpan<byte>(new byte[] { default, 99, 98, 0 }); for (int i = 0; i < length; i++) { diff --git a/src/System.Memory/tests/Span/IndexOf.char.cs b/src/System.Memory/tests/Span/IndexOf.char.cs index 51c91ffa0e..b77c3f7d77 100644 --- a/src/System.Memory/tests/Span/IndexOf.char.cs +++ b/src/System.Memory/tests/Span/IndexOf.char.cs @@ -27,7 +27,7 @@ namespace System.SpanTests a[i] = (char)(i + 1); } Span<char> span = new Span<char>(a); - + for (int targetIndex = 0; targetIndex < length; targetIndex++) { char target = a[targetIndex]; diff --git a/src/System.Memory/tests/Span/IndexOfSequence.T.cs b/src/System.Memory/tests/Span/IndexOfSequence.T.cs index 9c2ffc5b91..e8c270c0a2 100644 --- a/src/System.Memory/tests/Span/IndexOfSequence.T.cs +++ b/src/System.Memory/tests/Span/IndexOfSequence.T.cs @@ -119,5 +119,117 @@ namespace System.SpanTests int index = span.IndexOf(value); Assert.Equal(-1, index); } + + [Fact] + public static void IndexOfSequenceMatchAtStart_String() + { + Span<string> span = new Span<string>(new string[] { "5", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + Span<string> value = new Span<string>(new string[] { "5", "1", "77" }); + int index = span.IndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void IndexOfSequenceMultipleMatch_String() + { + Span<string> span = new Span<string>(new string[] { "1", "2", "3", "1", "2", "3", "1", "2", "3" }); + Span<string> value = new Span<string>(new string[] { "2", "3" }); + int index = span.IndexOf(value); + Assert.Equal(1, index); + } + + [Fact] + public static void IndexOfSequenceRestart_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + Span<string> value = new Span<string>(new string[] { "77", "77", "88" }); + int index = span.IndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void IndexOfSequenceNoMatch_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + Span<string> value = new Span<string>(new string[] { "77", "77", "88", "99" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void IndexOfSequenceNotEvenAHeadMatch_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + Span<string> value = new Span<string>(new string[] { "100", "77", "88", "99" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void IndexOfSequenceMatchAtVeryEnd_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + Span<string> value = new Span<string>(new string[] { "3", "4", "5" }); + int index = span.IndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void IndexOfSequenceJustPastVeryEnd_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); + Span<string> value = new Span<string>(new string[] { "3", "4", "5" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void IndexOfSequenceZeroLengthValue_String() + { + // A zero-length value is always "found" at the start of the span. + Span<string> span = new Span<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + Span<string> value = new Span<string>(Array.Empty<string>()); + int index = span.IndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void IndexOfSequenceZeroLengthSpan_String() + { + Span<string> span = new Span<string>(Array.Empty<string>()); + Span<string> value = new Span<string>(new string[] { "1", "2", "3" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void IndexOfSequenceLengthOneValue_String() + { + // A zero-length value is always "found" at the start of the span. + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + Span<string> value = new Span<string>(new string[] { "2" }); + int index = span.IndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void IndexOfSequenceLengthOneValueAtVeryEnd_String() + { + // A zero-length value is always "found" at the start of the span. + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + Span<string> value = new Span<string>(new string[] { "5" }); + int index = span.IndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void IndexOfSequenceLengthOneValueJustPasttVeryEnd_String() + { + // A zero-length value is always "found" at the start of the span. + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); + Span<string> value = new Span<string>(new string[] { "5" }); + int index = span.IndexOf(value); + Assert.Equal(-1, index); + } } } diff --git a/src/System.Memory/tests/Span/LastIndexOf.T.cs b/src/System.Memory/tests/Span/LastIndexOf.T.cs new file mode 100644 index 0000000000..e15858eb3f --- /dev/null +++ b/src/System.Memory/tests/Span/LastIndexOf.T.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class SpanTests + { + [Fact] + public static void ZeroLengthLastIndexOf() + { + Span<int> sp = new Span<int>(Array.Empty<int>()); + int idx = sp.LastIndexOf(0); + Assert.Equal(-1, idx); + } + + [Fact] + public static void TestMatchLastIndexOf() + { + for (int length = 0; length < 32; length++) + { + int[] a = new int[length]; + for (int i = 0; i < length; i++) + { + a[i] = 10 * (i + 1); + } + Span<int> span = new Span<int>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + int target = a[targetIndex]; + int idx = span.LastIndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestMultipleMatchLastIndexOf() + { + for (int length = 2; length < 32; length++) + { + int[] a = new int[length]; + for (int i = 0; i < length; i++) + { + a[i] = 10 * (i + 1); + } + + a[length - 1] = 5555; + a[length - 2] = 5555; + + Span<int> span = new Span<int>(a); + int idx = span.LastIndexOf(5555); + Assert.Equal(length - 1, idx); + } + } + + [Fact] + public static void OnNoMatchMakeSureEveryElementIsComparedLastIndexOf() + { + for (int length = 0; length < 100; length++) + { + TIntLog log = new TIntLog(); + + TInt[] a = new TInt[length]; + for (int i = 0; i < length; i++) + { + a[i] = new TInt(10 * (i + 1), log); + } + Span<TInt> span = new Span<TInt>(a); + int idx = span.LastIndexOf(new TInt(9999, log)); + Assert.Equal(-1, idx); + + // Since we asked for a non-existent value, make sure each element of the array was compared once. + // (Strictly speaking, it would not be illegal for IndexOf to compare an element more than once but + // that would be a non-optimal implementation and a red flag. So we'll stick with the stricter test.) + Assert.Equal(a.Length, log.Count); + foreach (TInt elem in a) + { + int numCompares = log.CountCompares(elem.Value, 9999); + Assert.True(numCompares == 1, $"Expected {numCompares} == 1 for element {elem.Value}."); + } + } + } + + [Fact] + public static void MakeSureNoChecksGoOutOfRangeLastIndexOf() + { + const int GuardValue = 77777; + const int GuardLength = 50; + + Action<int, int> checkForOutOfRangeAccess = + delegate (int x, int y) + { + if (x == GuardValue || y == GuardValue) + throw new Exception("Detected out of range access in IndexOf()"); + }; + + for (int length = 0; length < 100; length++) + { + TInt[] a = new TInt[GuardLength + length + GuardLength]; + for (int i = 0; i < a.Length; i++) + { + a[i] = new TInt(GuardValue, checkForOutOfRangeAccess); + } + + for (int i = 0; i < length; i++) + { + a[GuardLength + i] = new TInt(10 * (i + 1), checkForOutOfRangeAccess); + } + + Span<TInt> span = new Span<TInt>(a, GuardLength, length); + int idx = span.LastIndexOf(new TInt(9999, checkForOutOfRangeAccess)); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void ZeroLengthLastIndexOf_String() + { + Span<string> sp = new Span<string>(Array.Empty<string>()); + int idx = sp.LastIndexOf("a"); + Assert.Equal(-1, idx); + } + + [Fact] + public static void TestMatchLastIndexOf_String() + { + for (int length = 0; length < 32; length++) + { + string[] a = new string[length]; + for (int i = 0; i < length; i++) + { + a[i] = (10 * (i + 1)).ToString(); + } + Span<string> span = new Span<string>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + string target = a[targetIndex]; + int idx = span.LastIndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestNoMatchLastIndexOf_String() + { + var rnd = new Random(42); + for (int length = 0; length <= byte.MaxValue; length++) + { + string[] a = new string[length]; + string target = (rnd.Next(0, 256)).ToString(); + for (int i = 0; i < length; i++) + { + string val = (i + 1).ToString(); + a[i] = val == target ? (target + 1) : val; + } + Span<string> span = new Span<string>(a); + + int idx = span.LastIndexOf(target); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestMultipleMatchLastIndexOf_String() + { + for (int length = 2; length < 32; length++) + { + string[] a = new string[length]; + for (int i = 0; i < length; i++) + { + a[i] = (10 * (i + 1)).ToString(); + } + + a[length - 1] = "5555"; + a[length - 2] = "5555"; + + Span<string> span = new Span<string>(a); + int idx = span.LastIndexOf("5555"); + Assert.Equal(length - 1, idx); + } + } + } +} diff --git a/src/System.Memory/tests/Span/LastIndexOf.byte.cs b/src/System.Memory/tests/Span/LastIndexOf.byte.cs new file mode 100644 index 0000000000..93582c6ed0 --- /dev/null +++ b/src/System.Memory/tests/Span/LastIndexOf.byte.cs @@ -0,0 +1,149 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Numerics; +using Xunit; + +namespace System.SpanTests +{ + public static partial class SpanTests + { + [Fact] + public static void ZeroLengthLastIndexOf_Byte() + { + Span<byte> sp = new Span<byte>(Array.Empty<byte>()); + int idx = sp.LastIndexOf<byte>(0); + Assert.Equal(-1, idx); + } + + [Fact] + public static void DefaultFilledLastIndexOf_Byte() + { + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + Span<byte> span = new Span<byte>(a); + + for (int i = 0; i < length; i++) + { + byte target0 = default; + int idx = span.LastIndexOf(target0); + Assert.Equal(length - 1, idx); + } + } + } + + [Fact] + public static void TestMatchLastIndexOf_Byte() + { + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + for (int i = 0; i < length; i++) + { + a[i] = (byte)(i + 1); + } + Span<byte> span = new Span<byte>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + byte target = a[targetIndex]; + int idx = span.LastIndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestNoMatchLastIndexOf_Byte() + { + var rnd = new Random(42); + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + byte target = (byte)rnd.Next(0, 256); + for (int i = 0; i < length; i++) + { + byte val = (byte)(i + 1); + a[i] = val == target ? (byte)(target + 1) : val; + } + Span<byte> span = new Span<byte>(a); + + int idx = span.LastIndexOf(target); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestAllignmentNoMatchLastIndexOf_Byte() + { + byte[] array = new byte[4 * Vector<byte>.Count]; + for (var i = 0; i < Vector<byte>.Count; i++) + { + var span = new Span<byte>(array, i, 3 * Vector<byte>.Count); + int idx = span.LastIndexOf<byte>(5); + Assert.Equal(-1, idx); + + span = new Span<byte>(array, i, 3 * Vector<byte>.Count - 3); + idx = span.LastIndexOf<byte>(5); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestAllignmentMatchLastIndexOf_Byte() + { + byte[] array = new byte[4 * Vector<byte>.Count]; + for (int i = 0; i < array.Length; i++) + { + array[i] = 5; + } + for (var i = 0; i < Vector<byte>.Count; i++) + { + var span = new Span<byte>(array, i, 3 * Vector<byte>.Count); + int idx = span.LastIndexOf<byte>(5); + Assert.Equal(span.Length - 1, idx); + + span = new Span<byte>(array, i, 3 * Vector<byte>.Count - 3); + idx = span.LastIndexOf<byte>(5); + Assert.Equal(span.Length - 1, idx); + } + } + + [Fact] + public static void TestMultipleMatchLastIndexOf_Byte() + { + for (int length = 2; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + for (int i = 0; i < length; i++) + { + byte val = (byte)(i + 1); + a[i] = val == 200 ? (byte)201 : val; + } + + a[length - 1] = 200; + a[length - 2] = 200; + + Span<byte> span = new Span<byte>(a); + int idx = span.LastIndexOf<byte>(200); + Assert.Equal(length - 1, idx); + } + } + + [Fact] + public static void MakeSureNoChecksGoOutOfRangeLastIndexOf_Byte() + { + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length + 2]; + a[0] = 99; + a[length + 1] = 99; + Span<byte> span = new Span<byte>(a, 1, length); + int index = span.LastIndexOf<byte>(99); + Assert.Equal(-1, index); + } + } + } +} diff --git a/src/System.Memory/tests/Span/LastIndexOf.char.cs b/src/System.Memory/tests/Span/LastIndexOf.char.cs new file mode 100644 index 0000000000..902150a35b --- /dev/null +++ b/src/System.Memory/tests/Span/LastIndexOf.char.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class SpanTests + { + [Fact] + public static void ZeroLengthLastIndexOf_Char() + { + Span<char> sp = new Span<char>(Array.Empty<char>()); + int idx = sp.LastIndexOf((char)0); + Assert.Equal(-1, idx); + } + + [Fact] + public static void TestMatchLastIndexOf_Char() + { + for (int length = 0; length < 32; length++) + { + char[] a = new char[length]; + for (int i = 0; i < length; i++) + { + a[i] = (char)(i + 1); + } + Span<char> span = new Span<char>(a); + + for (int targetIndex = 0; targetIndex < length; targetIndex++) + { + char target = a[targetIndex]; + int idx = span.LastIndexOf(target); + Assert.Equal(targetIndex, idx); + } + } + } + + [Fact] + public static void TestMultipleMatchLastIndexOf_Char() + { + for (int length = 2; length < 32; length++) + { + char[] a = new char[length]; + for (int i = 0; i < length; i++) + { + a[i] = (char)(i + 1); + } + + a[length - 1] = (char)200; + a[length - 2] = (char)200; + + Span<char> span = new Span<char>(a); + int idx = span.LastIndexOf((char)200); + Assert.Equal(length - 1, idx); + } + } + + [Fact] + public static void MakeSureNoChecksGoOutOfRangeLastIndexOf_Char() + { + for (int length = 0; length < 100; length++) + { + char[] a = new char[length + 2]; + a[0] = '9'; + a[length + 1] = '9'; + Span<char> span = new Span<char>(a, 1, length); + int index = span.LastIndexOf('9'); + Assert.Equal(-1, index); + } + } + } +} diff --git a/src/System.Memory/tests/Span/LastIndexOfSequence.T.cs b/src/System.Memory/tests/Span/LastIndexOfSequence.T.cs new file mode 100644 index 0000000000..833d80c200 --- /dev/null +++ b/src/System.Memory/tests/Span/LastIndexOfSequence.T.cs @@ -0,0 +1,245 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class SpanTests + { + [Fact] + public static void LastIndexOfSequenceMatchAtStart() + { + Span<int> span = new Span<int>(new int[] { 5, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + Span<int> value = new Span<int>(new int[] { 5, 1, 77 }); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceMultipleMatch() + { + Span<int> span = new Span<int>(new int[] { 1, 2, 3, 1, 2, 3, 1, 2, 3, 1 }); + Span<int> value = new Span<int>(new int[] { 2, 3 }); + int index = span.LastIndexOf(value); + Assert.Equal(7, index); + } + + [Fact] + public static void LastIndexOfSequenceRestart() + { + Span<int> span = new Span<int>(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 8, 9, 77, 0, 1 }); + Span<int> value = new Span<int>(new int[] { 77, 77, 88 }); + int index = span.LastIndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void LastIndexOfSequenceNoMatch() + { + Span<int> span = new Span<int>(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + Span<int> value = new Span<int>(new int[] { 77, 77, 88, 99 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceNotEvenAHeadMatch() + { + Span<int> span = new Span<int>(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + Span<int> value = new Span<int>(new int[] { 100, 77, 88, 99 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtVeryEnd() + { + Span<int> span = new Span<int>(new int[] { 0, 1, 2, 3, 4, 5 }); + Span<int> value = new Span<int>(new int[] { 3, 4, 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void LastIndexOfSequenceJustPastVeryEnd() + { + Span<int> span = new Span<int>(new int[] { 0, 1, 2, 3, 4, 5 }, 0, 5); + Span<int> value = new Span<int>(new int[] { 3, 4, 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthValue() + { + // A zero-length value is always "found" at the start of the span. + Span<int> span = new Span<int>(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + Span<int> value = new Span<int>(Array.Empty<int>()); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthSpan() + { + Span<int> span = new Span<int>(Array.Empty<int>()); + Span<int> value = new Span<int>(new int[] { 1, 2, 3 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValue() + { + // A zero-length value is always "found" at the start of the span. + Span<int> span = new Span<int>(new int[] { 0, 1, 2, 3, 4, 5 }); + Span<int> value = new Span<int>(new int[] { 2 }); + int index = span.LastIndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueAtVeryEnd() + { + // A zero-length value is always "found" at the start of the span. + Span<int> span = new Span<int>(new int[] { 0, 1, 2, 3, 4, 5 }); + Span<int> value = new Span<int>(new int[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueMultipleTimes() + { + // A zero-length value is always "found" at the start of the span. + Span<int> span = new Span<int>(new int[] { 0, 1, 5, 3, 4, 5 }); + Span<int> value = new Span<int>(new int[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd() + { + // A zero-length value is always "found" at the start of the span. + Span<int> span = new Span<int>(new int[] { 0, 1, 2, 3, 4, 5 }, 0, 5); + Span<int> value = new Span<int>(new int[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtStart_String() + { + Span<string> span = new Span<string>(new string[] { "5", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + Span<string> value = new Span<string>(new string[] { "5", "1", "77" }); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceMultipleMatch_String() + { + Span<string> span = new Span<string>(new string[] { "1", "2", "3", "1", "2", "3", "1", "2", "3" }); + Span<string> value = new Span<string>(new string[] { "2", "3" }); + int index = span.LastIndexOf(value); + Assert.Equal(7, index); + } + + [Fact] + public static void LastIndexOfSequenceRestart_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "8", "9", "77", "0", "1" }); + Span<string> value = new Span<string>(new string[] { "77", "77", "88" }); + int index = span.LastIndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void LastIndexOfSequenceNoMatch_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + Span<string> value = new Span<string>(new string[] { "77", "77", "88", "99" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceNotEvenAHeadMatch_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + Span<string> value = new Span<string>(new string[] { "100", "77", "88", "99" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtVeryEnd_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + Span<string> value = new Span<string>(new string[] { "3", "4", "5" }); + int index = span.LastIndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void LastIndexOfSequenceJustPastVeryEnd_String() + { + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); + Span<string> value = new Span<string>(new string[] { "3", "4", "5" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthValue_String() + { + // A zero-length value is always "found" at the start of the span. + Span<string> span = new Span<string>(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); + Span<string> value = new Span<string>(Array.Empty<string>()); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthSpan_String() + { + Span<string> span = new Span<string>(Array.Empty<string>()); + Span<string> value = new Span<string>(new string[] { "1", "2", "3" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValue_String() + { + // A zero-length value is always "found" at the start of the span. + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + Span<string> value = new Span<string>(new string[] { "2" }); + int index = span.LastIndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueAtVeryEnd_String() + { + // A zero-length value is always "found" at the start of the span. + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }); + Span<string> value = new Span<string>(new string[] { "5" }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd_String() + { + // A zero-length value is always "found" at the start of the span. + Span<string> span = new Span<string>(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); + Span<string> value = new Span<string>(new string[] { "5" }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + } +} diff --git a/src/System.Memory/tests/Span/LastIndexOfSequence.byte.cs b/src/System.Memory/tests/Span/LastIndexOfSequence.byte.cs new file mode 100644 index 0000000000..96b229725e --- /dev/null +++ b/src/System.Memory/tests/Span/LastIndexOfSequence.byte.cs @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class SpanTests + { + [Fact] + public static void LastIndexOfSequenceMatchAtStart_Byte() + { + Span<byte> span = new Span<byte>(new byte[] { 5, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + Span<byte> value = new Span<byte>(new byte[] { 5, 1, 77 }); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceMultipleMatch_Byte() + { + Span<byte> span = new Span<byte>(new byte[] { 1, 2, 3, 1, 2, 3, 1, 2, 3, 1 }); + Span<byte> value = new Span<byte>(new byte[] { 2, 3 }); + int index = span.LastIndexOf(value); + Assert.Equal(7, index); + } + + [Fact] + public static void LastIndexOfSequenceRestart_Byte() + { + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 8, 9, 77, 0, 1 }); + Span<byte> value = new Span<byte>(new byte[] { 77, 77, 88 }); + int index = span.LastIndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void LastIndexOfSequenceNoMatch_Byte() + { + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + Span<byte> value = new Span<byte>(new byte[] { 77, 77, 88, 99 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceNotEvenAHeadMatch_Byte() + { + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + Span<byte> value = new Span<byte>(new byte[] { 100, 77, 88, 99 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtVeryEnd_Byte() + { + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }); + Span<byte> value = new Span<byte>(new byte[] { 3, 4, 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void LastIndexOfSequenceJustPastVeryEnd_Byte() + { + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }, 0, 5); + Span<byte> value = new Span<byte>(new byte[] { 3, 4, 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthValue_Byte() + { + // A zero-length value is always "found" at the start of the span. + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); + Span<byte> value = new Span<byte>(Array.Empty<byte>()); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthSpan_Byte() + { + Span<byte> span = new Span<byte>(Array.Empty<byte>()); + Span<byte> value = new Span<byte>(new byte[] { 1, 2, 3 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValue_Byte() + { + // A zero-length value is always "found" at the start of the span. + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }); + Span<byte> value = new Span<byte>(new byte[] { 2 }); + int index = span.LastIndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueAtVeryEnd_Byte() + { + // A zero-length value is always "found" at the start of the span. + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }); + Span<byte> value = new Span<byte>(new byte[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueMultipleTimes_Byte() + { + // A zero-length value is always "found" at the start of the span. + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 5, 3, 4, 5 }); + Span<byte> value = new Span<byte>(new byte[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd_Byte() + { + // A zero-length value is always "found" at the start of the span. + Span<byte> span = new Span<byte>(new byte[] { 0, 1, 2, 3, 4, 5 }, 0, 5); + Span<byte> value = new Span<byte>(new byte[] { 5 }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + } +} diff --git a/src/System.Memory/tests/Span/LastIndexOfSequence.char.cs b/src/System.Memory/tests/Span/LastIndexOfSequence.char.cs new file mode 100644 index 0000000000..af027cb54a --- /dev/null +++ b/src/System.Memory/tests/Span/LastIndexOfSequence.char.cs @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.SpanTests +{ + public static partial class SpanTests + { + [Fact] + public static void LastIndexOfSequenceMatchAtStart_Char() + { + Span<char> span = new Span<char>(new char[] { '5', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '8', '9' }); + Span<char> value = new Span<char>(new char[] { '5', '1', '7' }); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceMultipleMatch_Char() + { + Span<char> span = new Span<char>(new char[] { '1', '2', '3', '1', '2', '3', '1', '2', '3', '1' }); + Span<char> value = new Span<char>(new char[] { '2', '3' }); + int index = span.LastIndexOf(value); + Assert.Equal(7, index); + } + + [Fact] + public static void LastIndexOfSequenceRestart_Char() + { + Span<char> span = new Span<char>(new char[] { '5', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '6', '9', '7', '0', '1' }); + Span<char> value = new Span<char>(new char[] { '7', '7', '8' }); + int index = span.LastIndexOf(value); + Assert.Equal(10, index); + } + + [Fact] + public static void LastIndexOfSequenceNoMatch_Char() + { + Span<char> span = new Span<char>(new char[] { '0', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '8', '9' }); + Span<char> value = new Span<char>(new char[] { '7', '7', '8', 'X' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceNotEvenAHeadMatch_Char() + { + Span<char> span = new Span<char>(new char[] { '0', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '8', '9' }); + Span<char> value = new Span<char>(new char[] { 'X', '7', '8', '9' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceMatchAtVeryEnd_Char() + { + Span<char> span = new Span<char>(new char[] { '0', '1', '2', '3', '4', '5' }); + Span<char> value = new Span<char>(new char[] { '3', '4', '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(3, index); + } + + [Fact] + public static void LastIndexOfSequenceJustPastVeryEnd_Char() + { + Span<char> span = new Span<char>(new char[] { '0', '1', '2', '3', '4', '5' }, 0, 5); + Span<char> value = new Span<char>(new char[] { '3', '4', '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthValue_Char() + { + // A zero-length value is always "found" at the start of the span. + Span<char> span = new Span<char>(new char[] { '0', '1', '7', '2', '3', '7', '7', '4', '5', '7', '7', '7', '8', '6', '6', '7', '7', '8', '9' }); + Span<char> value = new Span<char>(Array.Empty<char>()); + int index = span.LastIndexOf(value); + Assert.Equal(0, index); + } + + [Fact] + public static void LastIndexOfSequenceZeroLengthSpan_Char() + { + Span<char> span = new Span<char>(Array.Empty<char>()); + Span<char> value = new Span<char>(new char[] { '1', '2', '3' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValue_Char() + { + // A zero-length value is always "found" at the start of the span. + Span<char> span = new Span<char>(new char[] { '0', '1', '2', '3', '4', '5' }); + Span<char> value = new Span<char>(new char[] { '2' }); + int index = span.LastIndexOf(value); + Assert.Equal(2, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueAtVeryEnd_Char() + { + // A zero-length value is always "found" at the start of the span. + Span<char> span = new Span<char>(new char[] { '0', '1', '2', '3', '4', '5' }); + Span<char> value = new Span<char>(new char[] { '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueMultipleTimes_Char() + { + // A zero-length value is always "found" at the start of the span. + Span<char> span = new Span<char>(new char[] { '0', '1', '5', '3', '4', '5' }); + Span<char> value = new Span<char>(new char[] { '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(5, index); + } + + [Fact] + public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd_Char() + { + // A zero-length value is always "found" at the start of the span. + Span<char> span = new Span<char>(new char[] { '0', '1', '2', '3', '4', '5' }, 0, 5); + Span<char> value = new Span<char>(new char[] { '5' }); + int index = span.LastIndexOf(value); + Assert.Equal(-1, index); + } + } +} diff --git a/src/System.Memory/tests/Span/Overflow.cs b/src/System.Memory/tests/Span/Overflow.cs index b9f9070f1b..77d036d3ea 100644 --- a/src/System.Memory/tests/Span/Overflow.cs +++ b/src/System.Memory/tests/Span/Overflow.cs @@ -36,9 +36,9 @@ namespace System.SpanTests try { ref Guid memory = ref Unsafe.AsRef<Guid>(memBlock.ToPointer()); - var span = new Span<Guid>(memBlock.ToPointer(), GuidThreeGiBLimit); + var span = new Span<Guid>(memBlock.ToPointer(), s_guidThreeGiBLimit); - int bigIndex = checked(GuidTwoGiBLimit + 1); + int bigIndex = checked(s_guidTwoGiBLimit + 1); uint byteOffset = checked((uint)bigIndex * (uint)sizeof(Guid)); Assert.True(byteOffset > int.MaxValue); // Make sure byteOffset actually overflows 2Gb, or this test is pointless. ref Guid expected = ref Unsafe.Add<Guid>(ref memory, bigIndex); @@ -63,8 +63,7 @@ namespace System.SpanTests private const long TwoGiB = 2L * 1024L * 1024L * 1024L; private const long OneGiB = 1L * 1024L * 1024L * 1024L; - private static readonly int GuidThreeGiBLimit = (int)(ThreeGiB / Unsafe.SizeOf<Guid>()); // sizeof(Guid) requires unsafe keyword and I don't want to mark the entire class unsafe. - private static readonly int GuidTwoGiBLimit = (int)(TwoGiB / Unsafe.SizeOf<Guid>()); - private static readonly int GuidOneGiBLimit = (int)(OneGiB / Unsafe.SizeOf<Guid>()); + private static readonly int s_guidThreeGiBLimit = (int)(ThreeGiB / Unsafe.SizeOf<Guid>()); // sizeof(Guid) requires unsafe keyword and I don't want to mark the entire class unsafe. + private static readonly int s_guidTwoGiBLimit = (int)(TwoGiB / Unsafe.SizeOf<Guid>()); } } diff --git a/src/System.Memory/tests/System.Memory.Tests.csproj b/src/System.Memory/tests/System.Memory.Tests.csproj index f85ef25828..8a9cb59d7d 100644 --- a/src/System.Memory/tests/System.Memory.Tests.csproj +++ b/src/System.Memory/tests/System.Memory.Tests.csproj @@ -38,6 +38,12 @@ <Compile Include="Span\IndexOfSequence.T.cs" /> <Compile Include="Span\IndexOfSequence.byte.cs" /> <Compile Include="Span\IndexOfSequence.char.cs" /> + <Compile Include="Span\LastIndexOf.T.cs" /> + <Compile Include="Span\LastIndexOf.byte.cs" /> + <Compile Include="Span\LastIndexOf.char.cs" /> + <Compile Include="Span\LastIndexOfSequence.T.cs" /> + <Compile Include="Span\LastIndexOfSequence.byte.cs" /> + <Compile Include="Span\LastIndexOfSequence.char.cs" /> <Compile Include="Span\NonPortableCast.cs" /> <Compile Include="Span\Overflow.cs" /> <Compile Include="Span\SequenceEqual.T.cs" /> @@ -70,6 +76,12 @@ <Compile Include="ReadOnlySpan\IndexOfSequence.T.cs" /> <Compile Include="ReadOnlySpan\IndexOfSequence.byte.cs" /> <Compile Include="ReadOnlySpan\IndexOfSequence.char.cs" /> + <Compile Include="ReadOnlySpan\LastIndexOf.T.cs" /> + <Compile Include="ReadOnlySpan\LastIndexOf.byte.cs" /> + <Compile Include="ReadOnlySpan\LastIndexOf.char.cs" /> + <Compile Include="ReadOnlySpan\LastIndexOfSequence.T.cs" /> + <Compile Include="ReadOnlySpan\LastIndexOfSequence.byte.cs" /> + <Compile Include="ReadOnlySpan\LastIndexOfSequence.char.cs" /> <Compile Include="ReadOnlySpan\NonPortableCast.cs" /> <Compile Include="ReadOnlySpan\Overflow.cs" /> <Compile Include="ReadOnlySpan\Overlaps.cs" /> diff --git a/src/System.Memory/tests/TInt.cs b/src/System.Memory/tests/TInt.cs index e6dba18fe8..2bceaa2c80 100644 --- a/src/System.Memory/tests/TInt.cs +++ b/src/System.Memory/tests/TInt.cs @@ -13,7 +13,7 @@ namespace System internal struct TInt : IEquatable<TInt> { public TInt(int value) - : this(value, (Action<int,int>)null) + : this(value, (Action<int, int>)null) { // This constructor does not report comparisons but is still useful for catching uses of the boxing Equals(). } diff --git a/src/System.Memory/tests/TestHelpers.cs b/src/System.Memory/tests/TestHelpers.cs index 29e5291ca2..c5c2fece68 100644 --- a/src/System.Memory/tests/TestHelpers.cs +++ b/src/System.Memory/tests/TestHelpers.cs @@ -33,7 +33,7 @@ namespace System public delegate void AssertThrowsAction<T>(Span<T> span); // Cannot use standard Assert.Throws() when testing Span - Span and closures don't get along. - public static void AssertThrows<E, T>(Span<T> span, AssertThrowsAction<T> action) where E:Exception + public static void AssertThrows<E, T>(Span<T> span, AssertThrowsAction<T> action) where E : Exception { try { @@ -89,7 +89,7 @@ namespace System public delegate void AssertThrowsActionReadOnly<T>(ReadOnlySpan<T> span); // Cannot use standard Assert.Throws() when testing Span - Span and closures don't get along. - public static void AssertThrows<E, T>(ReadOnlySpan<T> span, AssertThrowsActionReadOnly<T> action) where E:Exception + public static void AssertThrows<E, T>(ReadOnlySpan<T> span, AssertThrowsActionReadOnly<T> action) where E : Exception { try { @@ -163,7 +163,7 @@ namespace System span.Clear(); } - public static TestStructExplicit testExplicitStruct = new TestStructExplicit + public static TestStructExplicit s_testExplicitStruct = new TestStructExplicit { S0 = short.MaxValue, I0 = int.MaxValue, @@ -183,18 +183,18 @@ namespace System { Span<byte> spanBE = new byte[Unsafe.SizeOf<TestStructExplicit>()]; - WriteInt16BigEndian(spanBE, testExplicitStruct.S0); - WriteInt32BigEndian(spanBE.Slice(2), testExplicitStruct.I0); - WriteInt64BigEndian(spanBE.Slice(6), testExplicitStruct.L0); - WriteUInt16BigEndian(spanBE.Slice(14), testExplicitStruct.US0); - WriteUInt32BigEndian(spanBE.Slice(16), testExplicitStruct.UI0); - WriteUInt64BigEndian(spanBE.Slice(20), testExplicitStruct.UL0); - WriteInt16BigEndian(spanBE.Slice(28), testExplicitStruct.S1); - WriteInt32BigEndian(spanBE.Slice(30), testExplicitStruct.I1); - WriteInt64BigEndian(spanBE.Slice(34), testExplicitStruct.L1); - WriteUInt16BigEndian(spanBE.Slice(42), testExplicitStruct.US1); - WriteUInt32BigEndian(spanBE.Slice(44), testExplicitStruct.UI1); - WriteUInt64BigEndian(spanBE.Slice(48), testExplicitStruct.UL1); + WriteInt16BigEndian(spanBE, s_testExplicitStruct.S0); + WriteInt32BigEndian(spanBE.Slice(2), s_testExplicitStruct.I0); + WriteInt64BigEndian(spanBE.Slice(6), s_testExplicitStruct.L0); + WriteUInt16BigEndian(spanBE.Slice(14), s_testExplicitStruct.US0); + WriteUInt32BigEndian(spanBE.Slice(16), s_testExplicitStruct.UI0); + WriteUInt64BigEndian(spanBE.Slice(20), s_testExplicitStruct.UL0); + WriteInt16BigEndian(spanBE.Slice(28), s_testExplicitStruct.S1); + WriteInt32BigEndian(spanBE.Slice(30), s_testExplicitStruct.I1); + WriteInt64BigEndian(spanBE.Slice(34), s_testExplicitStruct.L1); + WriteUInt16BigEndian(spanBE.Slice(42), s_testExplicitStruct.US1); + WriteUInt32BigEndian(spanBE.Slice(44), s_testExplicitStruct.UI1); + WriteUInt64BigEndian(spanBE.Slice(48), s_testExplicitStruct.UL1); Assert.Equal(56, spanBE.Length); return spanBE; @@ -204,23 +204,23 @@ namespace System { Span<byte> spanLE = new byte[Unsafe.SizeOf<TestStructExplicit>()]; - WriteInt16LittleEndian(spanLE, testExplicitStruct.S0); - WriteInt32LittleEndian(spanLE.Slice(2), testExplicitStruct.I0); - WriteInt64LittleEndian( spanLE.Slice(6), testExplicitStruct.L0); - WriteUInt16LittleEndian(spanLE.Slice(14), testExplicitStruct.US0); - WriteUInt32LittleEndian(spanLE.Slice(16), testExplicitStruct.UI0); - WriteUInt64LittleEndian(spanLE.Slice(20), testExplicitStruct.UL0); - WriteInt16LittleEndian(spanLE.Slice(28), testExplicitStruct.S1); - WriteInt32LittleEndian(spanLE.Slice(30), testExplicitStruct.I1); - WriteInt64LittleEndian(spanLE.Slice(34), testExplicitStruct.L1); - WriteUInt16LittleEndian(spanLE.Slice(42), testExplicitStruct.US1); - WriteUInt32LittleEndian(spanLE.Slice(44), testExplicitStruct.UI1); - WriteUInt64LittleEndian(spanLE.Slice(48), testExplicitStruct.UL1); + WriteInt16LittleEndian(spanLE, s_testExplicitStruct.S0); + WriteInt32LittleEndian(spanLE.Slice(2), s_testExplicitStruct.I0); + WriteInt64LittleEndian(spanLE.Slice(6), s_testExplicitStruct.L0); + WriteUInt16LittleEndian(spanLE.Slice(14), s_testExplicitStruct.US0); + WriteUInt32LittleEndian(spanLE.Slice(16), s_testExplicitStruct.UI0); + WriteUInt64LittleEndian(spanLE.Slice(20), s_testExplicitStruct.UL0); + WriteInt16LittleEndian(spanLE.Slice(28), s_testExplicitStruct.S1); + WriteInt32LittleEndian(spanLE.Slice(30), s_testExplicitStruct.I1); + WriteInt64LittleEndian(spanLE.Slice(34), s_testExplicitStruct.L1); + WriteUInt16LittleEndian(spanLE.Slice(42), s_testExplicitStruct.US1); + WriteUInt32LittleEndian(spanLE.Slice(44), s_testExplicitStruct.UI1); + WriteUInt64LittleEndian(spanLE.Slice(48), s_testExplicitStruct.UL1); Assert.Equal(56, spanLE.Length); return spanLE; } - + [StructLayout(LayoutKind.Explicit)] public struct TestStructExplicit { |