From da014016bba4fca1f38253ffc596bafe39b7cf1f Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 26 Nov 2024 13:35:52 -0500 Subject: [PATCH] Add MemoryExtensions overloads with comparer --- .../src/System/Diagnostics/TraceUtils.cs | 12 +- .../System.Linq/src/System/Linq/Contains.cs | 42 +- .../System.Memory/ref/System.Memory.cs | 35 + .../tests/ReadOnlySpan/Comparers.cs | 42 + .../tests/ReadOnlySpan/Contains.T.cs | 38 +- .../tests/ReadOnlySpan/Count.T.cs | 85 +- .../tests/ReadOnlySpan/EndsWith.T.cs | 35 +- .../tests/ReadOnlySpan/IndexOf.T.cs | 50 +- .../tests/ReadOnlySpan/IndexOfAny.T.cs | 420 ++-- .../tests/ReadOnlySpan/IndexOfSequence.T.cs | 238 ++- .../tests/ReadOnlySpan/LastIndexOf.T.cs | 50 +- .../tests/ReadOnlySpan/LastIndexOfAny.T.cs | 424 +++-- .../ReadOnlySpan/LastIndexOfSequence.T.cs | 249 +-- .../tests/ReadOnlySpan/SequenceCompareTo.T.cs | 78 +- .../tests/ReadOnlySpan/StartsWith.T.cs | 42 +- .../tests/System.Memory.Tests.csproj | 1 + .../src/System/MemoryExtensions.cs | 1684 ++++++++++++++++- 17 files changed, 2658 insertions(+), 867 deletions(-) create mode 100644 src/libraries/System.Memory/tests/ReadOnlySpan/Comparers.cs diff --git a/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/TraceUtils.cs b/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/TraceUtils.cs index 709075d9c77d66..da3af52b7a7bd1 100644 --- a/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/TraceUtils.cs +++ b/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/TraceUtils.cs @@ -19,17 +19,7 @@ internal static void VerifyAttributes(StringDictionary? attributes, string[]? su foreach (string key in attributes.Keys) { - bool found = false; - if (supportedAttributes != null) - { - for (int i = 0; i < supportedAttributes.Length; i++) - { - if (supportedAttributes[i] == key) - found = true; - } - } - - if (!found) + if (supportedAttributes is null || !supportedAttributes.Contains(key)) { throw new ArgumentException(SR.Format(SR.AttributeNotSupported, key, parent.GetType().FullName)); } diff --git a/src/libraries/System.Linq/src/System/Linq/Contains.cs b/src/libraries/System.Linq/src/System/Linq/Contains.cs index f4dbd43ae00e39..0f56c219d29372 100644 --- a/src/libraries/System.Linq/src/System/Linq/Contains.cs +++ b/src/libraries/System.Linq/src/System/Linq/Contains.cs @@ -18,43 +18,37 @@ public static bool Contains(this IEnumerable source, TSource v ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } + if (source.TryGetSpan(out ReadOnlySpan span)) + { + return span.Contains(value, comparer); + } + if (comparer is null) { // While it's tempting, this must not delegate to ICollection.Contains, as the historical semantics // of a null comparer with this method are to use EqualityComparer.Default, and that might differ // from the semantics encoded in ICollection.Contains. - // We don't bother special-casing spans here as explicitly providing a null comparer with a known collection type - // is relatively rare. If you don't care about the comparer, you use the other overload, and while it will delegate - // to this overload with a null comparer, it'll only do so for collections from which we can't extract a span. - // And if you do care about the comparer, you're generally passing in a non-null one. - - foreach (TSource element in source) - { - if (EqualityComparer.Default.Equals(element, value)) - { - return true; - } - } - } - else if (source.TryGetSpan(out ReadOnlySpan span)) - { - foreach (TSource element in span) + if (typeof(TSource).IsValueType) { - if (comparer.Equals(element, value)) + foreach (TSource element in source) { - return true; + if (EqualityComparer.Default.Equals(element, value)) + { + return true; + } } + + return false; } + + comparer = EqualityComparer.Default; } - else + foreach (TSource element in source) { - foreach (TSource element in source) + if (comparer.Equals(element, value)) { - if (comparer.Equals(element, value)) - { - return true; - } + return true; } } diff --git a/src/libraries/System.Memory/ref/System.Memory.cs b/src/libraries/System.Memory/ref/System.Memory.cs index 53d3da5e0441c2..c90f8fb4b2b979 100644 --- a/src/libraries/System.Memory/ref/System.Memory.cs +++ b/src/libraries/System.Memory/ref/System.Memory.cs @@ -239,6 +239,7 @@ public static partial class MemoryExtensions public static int CompareTo(this System.ReadOnlySpan span, System.ReadOnlySpan other, System.StringComparison comparisonType) { throw null; } public static bool Contains(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.StringComparison comparisonType) { throw null; } public static bool Contains(this System.ReadOnlySpan span, T value) where T : System.IEquatable? { throw null; } + public static bool Contains(this System.ReadOnlySpan span, T value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static bool Contains(this System.Span span, T value) where T : System.IEquatable? { throw null; } public static bool ContainsAny(this System.ReadOnlySpan span, System.Buffers.SearchValues values) { throw null; } @@ -246,8 +247,11 @@ public static partial class MemoryExtensions public static bool ContainsAny(this System.Span span, System.Buffers.SearchValues values) { throw null; } public static bool ContainsAny(this System.ReadOnlySpan span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } public static bool ContainsAny(this System.ReadOnlySpan span, System.ReadOnlySpan values) where T : System.IEquatable? { throw null; } + public static bool ContainsAny(this System.ReadOnlySpan span, System.ReadOnlySpan values, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static bool ContainsAny(this System.ReadOnlySpan span, T value0, T value1) where T : System.IEquatable? { throw null; } + public static bool ContainsAny(this System.ReadOnlySpan span, T value0, T value1, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static bool ContainsAny(this System.ReadOnlySpan span, T value0, T value1, T value2) where T : System.IEquatable? { throw null; } + public static bool ContainsAny(this System.ReadOnlySpan span, T value0, T value1, T value2, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static bool ContainsAny(this System.Span span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] @@ -258,9 +262,13 @@ public static partial class MemoryExtensions public static bool ContainsAny(this System.Span span, T value0, T value1, T value2) where T : System.IEquatable? { throw null; } public static bool ContainsAnyExcept(this System.ReadOnlySpan span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } public static bool ContainsAnyExcept(this System.ReadOnlySpan span, System.ReadOnlySpan values) where T : System.IEquatable? { throw null; } + public static bool ContainsAnyExcept(this System.ReadOnlySpan span, System.ReadOnlySpan values, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static bool ContainsAnyExcept(this System.ReadOnlySpan span, T value) where T : System.IEquatable? { throw null; } + public static bool ContainsAnyExcept(this System.ReadOnlySpan span, T value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static bool ContainsAnyExcept(this System.ReadOnlySpan span, T value0, T value1) where T : System.IEquatable? { throw null; } + public static bool ContainsAnyExcept(this System.ReadOnlySpan span, T value0, T value1, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static bool ContainsAnyExcept(this System.ReadOnlySpan span, T value0, T value1, T value2) where T : System.IEquatable? { throw null; } + public static bool ContainsAnyExcept(this System.ReadOnlySpan span, T value0, T value1, T value2, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static bool ContainsAnyExcept(this System.Span span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] @@ -282,14 +290,18 @@ public static void CopyTo(this T[]? source, System.Span destination) { } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int Count(this System.Span span, T value) where T : System.IEquatable? { throw null; } public static int Count(this System.ReadOnlySpan span, T value) where T : System.IEquatable? { throw null; } + public static int Count(this System.ReadOnlySpan span, T value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int Count(this System.Span span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } public static int Count(this System.ReadOnlySpan span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } + public static int Count(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static bool EndsWith(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.StringComparison comparisonType) { throw null; } public static bool EndsWith(this System.ReadOnlySpan span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } + public static bool EndsWith(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static bool EndsWith(this System.Span span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } public static bool EndsWith(this System.ReadOnlySpan span, T value) where T : System.IEquatable? { throw null; } + public static bool EndsWith(this System.ReadOnlySpan span, T value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static System.Text.SpanLineEnumerator EnumerateLines(this System.ReadOnlySpan span) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static System.Text.SpanLineEnumerator EnumerateLines(this System.Span span) { throw null; } @@ -303,8 +315,11 @@ public static void CopyTo(this T[]? source, System.Span destination) { } public static int IndexOfAny(this System.Span span, System.Buffers.SearchValues values) { throw null; } public static int IndexOfAny(this System.ReadOnlySpan span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } public static int IndexOfAny(this System.ReadOnlySpan span, System.ReadOnlySpan values) where T : System.IEquatable? { throw null; } + public static int IndexOfAny(this System.ReadOnlySpan span, System.ReadOnlySpan values, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int IndexOfAny(this System.ReadOnlySpan span, T value0, T value1) where T : System.IEquatable? { throw null; } + public static int IndexOfAny(this System.ReadOnlySpan span, T value0, T value1, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int IndexOfAny(this System.ReadOnlySpan span, T value0, T value1, T value2) where T : System.IEquatable? { throw null; } + public static int IndexOfAny(this System.ReadOnlySpan span, T value0, T value1, T value2, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int IndexOfAny(this System.Span span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] @@ -324,15 +339,21 @@ public static void CopyTo(this T[]? source, System.Span destination) { } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int IndexOfAnyExcept(this System.Span span, System.ReadOnlySpan values) where T : System.IEquatable? { throw null; } public static int IndexOfAnyExcept(this System.ReadOnlySpan span, T value) where T : System.IEquatable? { throw null; } + public static int IndexOfAnyExcept(this System.ReadOnlySpan span, T value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int IndexOfAnyExcept(this System.ReadOnlySpan span, T value0, T value1) where T : System.IEquatable? { throw null; } + public static int IndexOfAnyExcept(this System.ReadOnlySpan span, T value0, T value1, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int IndexOfAnyExcept(this System.ReadOnlySpan span, T value0, T value1, T value2) where T : System.IEquatable? { throw null; } + public static int IndexOfAnyExcept(this System.ReadOnlySpan span, T value0, T value1, T value2, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int IndexOfAnyExcept(this System.ReadOnlySpan span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } public static int IndexOfAnyExcept(this System.ReadOnlySpan span, System.ReadOnlySpan values) where T : System.IEquatable? { throw null; } + public static int IndexOfAnyExcept(this System.ReadOnlySpan span, System.ReadOnlySpan values, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int IndexOfAnyExceptInRange(this System.ReadOnlySpan span, T lowInclusive, T highInclusive) where T : System.IComparable { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int IndexOfAnyExceptInRange(this System.Span span, T lowInclusive, T highInclusive) where T : System.IComparable { throw null; } public static int IndexOf(this System.ReadOnlySpan span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } + public static int IndexOf(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int IndexOf(this System.ReadOnlySpan span, T value) where T : System.IEquatable? { throw null; } + public static int IndexOf(this System.ReadOnlySpan span, T value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int IndexOf(this System.Span span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] @@ -344,8 +365,11 @@ public static void CopyTo(this T[]? source, System.Span destination) { } public static int LastIndexOf(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.StringComparison comparisonType) { throw null; } public static int LastIndexOfAny(this System.ReadOnlySpan span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } public static int LastIndexOfAny(this System.ReadOnlySpan span, System.ReadOnlySpan values) where T : System.IEquatable? { throw null; } + public static int LastIndexOfAny(this System.ReadOnlySpan span, System.ReadOnlySpan values, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int LastIndexOfAny(this System.ReadOnlySpan span, T value0, T value1) where T : System.IEquatable? { throw null; } + public static int LastIndexOfAny(this System.ReadOnlySpan span, T value0, T value1, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int LastIndexOfAny(this System.ReadOnlySpan span, T value0, T value1, T value2) where T : System.IEquatable? { throw null; } + public static int LastIndexOfAny(this System.ReadOnlySpan span, T value0, T value1, T value2, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int LastIndexOfAny(this System.Span span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] @@ -365,15 +389,21 @@ public static void CopyTo(this T[]? source, System.Span destination) { } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int LastIndexOfAnyExcept(this System.Span span, System.ReadOnlySpan values) where T : System.IEquatable? { throw null; } public static int LastIndexOfAnyExcept(this System.ReadOnlySpan span, T value) where T : System.IEquatable? { throw null; } + public static int LastIndexOfAnyExcept(this System.ReadOnlySpan span, T value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int LastIndexOfAnyExcept(this System.ReadOnlySpan span, T value0, T value1) where T : System.IEquatable? { throw null; } + public static int LastIndexOfAnyExcept(this System.ReadOnlySpan span, T value0, T value1, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int LastIndexOfAnyExcept(this System.ReadOnlySpan span, T value0, T value1, T value2) where T : System.IEquatable? { throw null; } + public static int LastIndexOfAnyExcept(this System.ReadOnlySpan span, T value0, T value1, T value2, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int LastIndexOfAnyExcept(this System.ReadOnlySpan span, System.Buffers.SearchValues values) where T : System.IEquatable? { throw null; } public static int LastIndexOfAnyExcept(this System.ReadOnlySpan span, System.ReadOnlySpan values) where T : System.IEquatable? { throw null; } + public static int LastIndexOfAnyExcept(this System.ReadOnlySpan span, System.ReadOnlySpan values, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int LastIndexOfAnyExceptInRange(this System.ReadOnlySpan span, T lowInclusive, T highInclusive) where T : System.IComparable { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int LastIndexOfAnyExceptInRange(this System.Span span, T lowInclusive, T highInclusive) where T : System.IComparable { throw null; } public static int LastIndexOf(this System.ReadOnlySpan span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } + public static int LastIndexOf(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int LastIndexOf(this System.ReadOnlySpan span, T value) where T : System.IEquatable? { throw null; } + public static int LastIndexOf(this System.ReadOnlySpan span, T value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int LastIndexOf(this System.Span span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] @@ -388,9 +418,12 @@ public static void CopyTo(this T[]? source, System.Span destination) { } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static bool Overlaps(this System.Span span, System.ReadOnlySpan other, out int elementOffset) { throw null; } public static void Replace(this System.Span span, T oldValue, T newValue) where T : System.IEquatable? { } + public static void Replace(this System.Span span, T oldValue, T newValue, System.Collections.Generic.IEqualityComparer? comparer = null) { } public static void Replace(this System.ReadOnlySpan source, System.Span destination, T oldValue, T newValue) where T : System.IEquatable? { } + public static void Replace(this System.ReadOnlySpan source, System.Span destination, T oldValue, T newValue, System.Collections.Generic.IEqualityComparer? comparer = null) { } public static void Reverse(this System.Span span) { } public static int SequenceCompareTo(this System.ReadOnlySpan span, System.ReadOnlySpan other) where T : System.IComparable? { throw null; } + public static int SequenceCompareTo(this System.ReadOnlySpan span, System.ReadOnlySpan other, System.Collections.Generic.IComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static int SequenceCompareTo(this System.Span span, System.ReadOnlySpan other) where T : System.IComparable? { throw null; } public static bool SequenceEqual(this System.ReadOnlySpan span, System.ReadOnlySpan other) where T : System.IEquatable? { throw null; } @@ -415,9 +448,11 @@ public static void Sort(this System.Span keys, Sy public static int SplitAny(this System.ReadOnlySpan source, System.Span destination, System.ReadOnlySpan separators, System.StringSplitOptions options = System.StringSplitOptions.None) { throw null; } public static bool StartsWith(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.StringComparison comparisonType) { throw null; } public static bool StartsWith(this System.ReadOnlySpan span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } + public static bool StartsWith(this System.ReadOnlySpan span, System.ReadOnlySpan value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)] public static bool StartsWith(this System.Span span, System.ReadOnlySpan value) where T : System.IEquatable? { throw null; } public static bool StartsWith(this System.ReadOnlySpan span, T value) where T : System.IEquatable? { throw null; } + public static bool StartsWith(this System.ReadOnlySpan span, T value, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static int ToLower(this System.ReadOnlySpan source, System.Span destination, System.Globalization.CultureInfo? culture) { throw null; } public static int ToLowerInvariant(this System.ReadOnlySpan source, System.Span destination) { throw null; } public static int ToUpper(this System.ReadOnlySpan source, System.Span destination, System.Globalization.CultureInfo? culture) { throw null; } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/Comparers.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/Comparers.cs new file mode 100644 index 00000000000000..233bd81192f6fe --- /dev/null +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/Comparers.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using Xunit; + +namespace System.SpanTests +{ + public static partial class ReadOnlySpanTests + { + private static IEnumerable?> GetDefaultEqualityComparers() + { + yield return null; + + yield return EqualityComparer.Default; + + yield return EqualityComparer.Create((i, j) => EqualityComparer.Default.Equals(i, j)); + + if (typeof(T) == typeof(string)) + { + yield return (IEqualityComparer)(object)StringComparer.Ordinal; + } + } + + private static IEnumerable?> GetDefaultComparers() + { + yield return null; + + yield return Comparer.Default; + + yield return Comparer.Create((i, j) => Comparer.Default.Compare(i, j)); + + if (typeof(T) == typeof(string)) + { + yield return (IComparer)(object)StringComparer.Ordinal; + } + } + + private static IEqualityComparer GetFalseEqualityComparer() => + EqualityComparer.Create((i, j) => false); + } +} diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/Contains.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/Contains.T.cs index 0aede51284e51b..8692f419d4a21a 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/Contains.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/Contains.T.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using Xunit; namespace System.SpanTests @@ -27,13 +28,13 @@ public static void TestContains() { a[i] = 10 * (i + 1); } - ReadOnlySpan span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target = a[targetIndex]; - bool found = span.Contains(target); - Assert.True(found); + Assert.True(new ReadOnlySpan(a).Contains(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a).Contains(target, comparer))); + Assert.False(new ReadOnlySpan(a).Contains(target, GetFalseEqualityComparer())); } } } @@ -52,9 +53,9 @@ public static void TestMultipleContains() a[length - 1] = 5555; a[length - 2] = 5555; - ReadOnlySpan span = new ReadOnlySpan(a); - bool found = span.Contains(5555); - Assert.True(found); + Assert.True(new ReadOnlySpan(a).Contains(5555)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a).Contains(5555, comparer))); + Assert.False(new ReadOnlySpan(a).Contains(5555, GetFalseEqualityComparer())); } } @@ -71,8 +72,7 @@ public static void OnNoMatchForContainsMakeSureEveryElementIsCompared() a[i] = new TInt(10 * (i + 1), log); } ReadOnlySpan span = new ReadOnlySpan(a); - bool found = span.Contains(new TInt(9999, log)); - Assert.False(found); + Assert.False(span.Contains(new TInt(9999, log))); // 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 @@ -112,8 +112,7 @@ void checkForOutOfRangeAccess(int x, int y) } ReadOnlySpan span = new ReadOnlySpan(a, GuardLength, length); - bool found = span.Contains(new TInt(9999, checkForOutOfRangeAccess)); - Assert.False(found); + Assert.False(span.Contains(new TInt(9999, checkForOutOfRangeAccess))); } } @@ -121,8 +120,11 @@ void checkForOutOfRangeAccess(int x, int y) public static void ZeroLengthContains_String() { ReadOnlySpan span = new ReadOnlySpan(Array.Empty()); - bool found = span.Contains("a"); - Assert.False(found); + Assert.False(span.Contains("a")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.False(new ReadOnlySpan(Array.Empty()).Contains("a", comparer))); + Assert.False(span.Contains("a", null)); + Assert.False(span.Contains("a", EqualityComparer.Default)); + Assert.False(span.Contains("a", EqualityComparer.Create((i, j) => i == j))); } [Fact] @@ -140,8 +142,9 @@ public static void TestMatchContains_String() for (int targetIndex = 0; targetIndex < length; targetIndex++) { string target = a[targetIndex]; - bool found = span.Contains(target); - Assert.True(found); + Assert.True(span.Contains(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a).Contains(target, comparer))); + Assert.False(span.Contains(target, GetFalseEqualityComparer())); } } } @@ -161,8 +164,7 @@ public static void TestNoMatchContains_String() } ReadOnlySpan span = new ReadOnlySpan(a); - bool found = span.Contains(target); - Assert.False(found); + Assert.False(span.Contains(target)); } } @@ -181,8 +183,7 @@ public static void TestMultipleMatchContains_String() a[length - 2] = "5555"; ReadOnlySpan span = new ReadOnlySpan(a); - bool found = span.Contains("5555"); - Assert.True(found); + Assert.True(span.Contains("5555")); } } @@ -192,6 +193,7 @@ public static void ContainsNull_String(string[] spanInput, bool expected) { ReadOnlySpan theStrings = spanInput; Assert.Equal(expected, theStrings.Contains(null)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(spanInput).Contains(null, comparer))); } } } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/Count.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/Count.T.cs index 6cc1ff7e353826..75c6c41c74e315 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/Count.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/Count.T.cs @@ -11,6 +11,7 @@ public static partial class ReadOnlySpanTests public static void ZeroLengthCount_Int() { Assert.Equal(0, ReadOnlySpan.Empty.Count(0)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, ReadOnlySpan.Empty.Count(0, comparer))); } [Fact] @@ -19,15 +20,17 @@ public static void ZeroLengthCount_RosInt() for (int i = 0; i <= 2; i++) { Assert.Equal(0, ReadOnlySpan.Empty.Count(new int[i])); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, ReadOnlySpan.Empty.Count(new int[i], comparer))); } } [Fact] public static void ZeroLengthNeedleCount_RosInt() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 5, 5, 5, 5, 5 }); + int[] arr = [5, 5, 5, 5, 5]; - Assert.Equal(0, span.Count(ReadOnlySpan.Empty)); + Assert.Equal(0, new ReadOnlySpan(arr).Count(ReadOnlySpan.Empty)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(arr).Count(ReadOnlySpan.Empty, comparer))); } [Fact] @@ -40,11 +43,12 @@ public static void TestCount_Int() { a[i] = 10 * (i + 1); } - ReadOnlySpan span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { - Assert.Equal(1, span.Count(a[targetIndex])); + Assert.Equal(1, new ReadOnlySpan(a).Count(a[targetIndex])); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(1, new ReadOnlySpan(a).Count(a[targetIndex], comparer))); + Assert.Equal(0, new ReadOnlySpan(a).Count(a[targetIndex], GetFalseEqualityComparer())); } } } @@ -59,11 +63,12 @@ public static void TestCount_RosInt() { a[i] = 10 * (i + 1); } - ReadOnlySpan span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length - 1; targetIndex++) { - Assert.Equal(1, span.Count(new int[] { a[targetIndex], a[targetIndex + 1] })); + Assert.Equal(1, new ReadOnlySpan(a).Count(new int[] { a[targetIndex], a[targetIndex + 1] })); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(1, new ReadOnlySpan(a).Count(new int[] { a[targetIndex], a[targetIndex + 1] }, comparer))); + Assert.Equal(0, new ReadOnlySpan(a).Count(new int[] { a[targetIndex], a[targetIndex + 1] }, GetFalseEqualityComparer())); } } } @@ -81,8 +86,9 @@ public static void TestMultipleCount_Int() a[^1] = a[^2] = 5555; - ReadOnlySpan span = new ReadOnlySpan(a); - Assert.Equal(2, span.Count(5555)); + Assert.Equal(2, new ReadOnlySpan(a).Count(5555)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(2, new ReadOnlySpan(a).Count(5555, comparer))); + Assert.Equal(0, new ReadOnlySpan(a).Count(5555, GetFalseEqualityComparer())); } } @@ -98,8 +104,9 @@ public static void TestMultipleCount_RosInt() } a[0] = a[1] = a[^1] = a[^2] = 5555; - ReadOnlySpan span = new ReadOnlySpan(a); - Assert.Equal(2, span.Count(new int[] { 5555, 5555 })); + Assert.Equal(2, new ReadOnlySpan(a).Count(new int[] { 5555, 5555 })); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(2, new ReadOnlySpan(a).Count(new int[] { 5555, 5555 }, comparer))); + Assert.Equal(0, new ReadOnlySpan(a).Count(new int[] { 5555, 5555 }, GetFalseEqualityComparer())); } } @@ -222,12 +229,14 @@ void CheckForOutOfRangeAccess(int x, int y) => public static void ZeroLengthCount_String() { Assert.Equal(0, ReadOnlySpan.Empty.Count("a")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, ReadOnlySpan.Empty.Count("a", comparer))); } - + [Fact] public static void ZeroLengthCount_RosString() { Assert.Equal(0, ReadOnlySpan.Empty.Count(new[] { "a", "b" })); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, ReadOnlySpan.Empty.Count(new[] { "a", "b" }, comparer))); } [Fact] @@ -240,11 +249,12 @@ public static void TestMatchCount_String() { a[i] = (10 * (i + 1)).ToString(); } - ReadOnlySpan span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { - Assert.Equal(1, span.Count(a[targetIndex])); + Assert.Equal(1, new ReadOnlySpan(a).Count(a[targetIndex])); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(1, new ReadOnlySpan(a).Count(a[targetIndex], comparer))); + Assert.Equal(0, new ReadOnlySpan(a).Count(a[targetIndex], GetFalseEqualityComparer())); } } } @@ -259,11 +269,12 @@ public static void TestMatchCount_RosString() { a[i] = (10 * (i + 1)).ToString(); } - ReadOnlySpan span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length - 1; targetIndex++) { - Assert.Equal(1, span.Count(new string[] { a[targetIndex], a[targetIndex + 1] })); + Assert.Equal(1, new ReadOnlySpan(a).Count(new string[] { a[targetIndex], a[targetIndex + 1] })); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(1, new ReadOnlySpan(a).Count(new string[] { a[targetIndex], a[targetIndex + 1] }, comparer))); + Assert.Equal(0, new ReadOnlySpan(a).Count(new string[] { a[targetIndex], a[targetIndex + 1] }, GetFalseEqualityComparer())); } } } @@ -282,8 +293,8 @@ public static void TestNoMatchCount_String() a[i] = val == target ? (target + 1) : val; } - ReadOnlySpan span = new ReadOnlySpan(a); - Assert.Equal(0, span.Count(target)); + Assert.Equal(0, new ReadOnlySpan(a).Count(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a).Count(target, comparer))); } } @@ -294,15 +305,15 @@ public static void TestNoMatchCount_RosString() for (int length = 0; length <= byte.MaxValue; length++) { string[] a = new string[length]; - ReadOnlySpan target = new string[] { rnd.Next(0, 256).ToString(), "0" }; + var target = new string[] { rnd.Next(0, 256).ToString(), "0" }; for (int i = 0; i < length; i++) { string val = (i + 1).ToString(); a[i] = val == target[0] ? (target[0] + 1) : val; } - ReadOnlySpan span = new ReadOnlySpan(a); - Assert.Equal(0, span.Count(target)); + Assert.Equal(0, new ReadOnlySpan(a).Count(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a).Count(target, comparer))); } } @@ -319,8 +330,9 @@ public static void TestMultipleMatchCount_String() a[^1] = a[^2] = "5555"; - ReadOnlySpan span = new ReadOnlySpan(a); - Assert.Equal(2, span.Count("5555")); + Assert.Equal(2, new ReadOnlySpan(a).Count("5555")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(2, new ReadOnlySpan(a).Count("5555", comparer))); + Assert.Equal(0, new ReadOnlySpan(a).Count("5555", GetFalseEqualityComparer())); } } @@ -337,23 +349,28 @@ public static void TestMultipleMatchCount_RosString() a[0] = a[1] = a[^1] = a[^2] = "5555"; - ReadOnlySpan span = new ReadOnlySpan(a); - Assert.Equal(2, span.Count(new string[] { "5555", "5555" })); + Assert.Equal(2, new ReadOnlySpan(a).Count(new string[] { "5555", "5555" })); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(2, new ReadOnlySpan(a).Count(new string[] { "5555", "5555" }, comparer))); + Assert.Equal(0, new ReadOnlySpan(a).Count(new string[] { "5555", "5555" }, GetFalseEqualityComparer())); } } [Fact] public static void TestOrdinalStringCount_String() { - ReadOnlySpan span = new string[] { "ii", "II", "μμ", "ii" }; - Assert.Equal(2, span.Count("ii")); + var arr = new string[] { "ii", "II", "μμ", "ii" }; + Assert.Equal(2, new ReadOnlySpan(arr).Count("ii")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(2, new ReadOnlySpan(arr).Count("ii", comparer))); + Assert.Equal(0, new ReadOnlySpan(arr).Count("ii", GetFalseEqualityComparer())); } [Fact] public static void TestOrdinalStringCount_RosString() { - ReadOnlySpan span = new string[] { "ii", "II", "μμ", "ii", "μμ" }; - Assert.Equal(1, span.Count(new string[] { "ii", "II" })); + var arr = new string[] { "ii", "II", "μμ", "ii", "μμ" }; + Assert.Equal(1, new ReadOnlySpan(arr).Count(new string[] { "ii", "II" })); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(1, new ReadOnlySpan(arr).Count(new string[] { "ii", "II" }, comparer))); + Assert.Equal(0, new ReadOnlySpan(arr).Count(new string[] { "ii", "II" }, GetFalseEqualityComparer())); } [Fact] @@ -367,17 +384,19 @@ public static void TestOverlapDoNotCount_RosChar() [MemberData(nameof(TestHelpers.CountNullData), MemberType = typeof(TestHelpers))] public static void CountNull_String(string[] spanInput, int expected) { - ReadOnlySpan theStrings = spanInput; - Assert.Equal(expected, theStrings.Count((string)null)); + Assert.Equal(expected, new ReadOnlySpan(spanInput).Count((string)null)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(spanInput).Count((string)null, comparer))); + Assert.Equal(0, new ReadOnlySpan(spanInput).Count((string)null, GetFalseEqualityComparer())); } [Theory] [MemberData(nameof(TestHelpers.CountNullRosData), MemberType = typeof(TestHelpers))] public static void CountNull_RosString(string[] spanInput, int expected) { - ReadOnlySpan theStrings = spanInput; - ReadOnlySpan target = new string[] { null, "9" }; - Assert.Equal(expected, theStrings.Count(target)); + var target = new string[] { null, "9" }; + Assert.Equal(expected, new ReadOnlySpan(spanInput).Count(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(spanInput).Count(target, comparer))); + Assert.Equal(0, new ReadOnlySpan(spanInput).Count(target, GetFalseEqualityComparer())); } } } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/EndsWith.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/EndsWith.T.cs index 471e2613dd14a4..8813842745d4ba 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/EndsWith.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/EndsWith.T.cs @@ -12,39 +12,34 @@ public static void ZeroLengthEndsWith() { int[] a = new int[3]; - ReadOnlySpan first = new ReadOnlySpan(a, 1, 0); - ReadOnlySpan second = new ReadOnlySpan(a, 2, 0); - bool b = first.EndsWith(second); - Assert.True(b); + Assert.True(new ReadOnlySpan(a, 1, 0).EndsWith(new ReadOnlySpan(a, 2, 0))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a, 1, 0).EndsWith(new ReadOnlySpan(a, 2, 0), comparer))); } [Fact] public static void SameSpanEndsWith() { int[] a = { 4, 5, 6 }; - ReadOnlySpan span = new ReadOnlySpan(a); - bool b = span.EndsWith(span); - Assert.True(b); + Assert.True(new ReadOnlySpan(a).EndsWith(new ReadOnlySpan(a))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a).EndsWith(new ReadOnlySpan(a), comparer))); + Assert.False(new ReadOnlySpan(a).EndsWith(new ReadOnlySpan(a), GetFalseEqualityComparer())); } [Fact] public static void LengthMismatchEndsWith() { int[] a = { 4, 5, 6 }; - ReadOnlySpan first = new ReadOnlySpan(a, 0, 2); - ReadOnlySpan second = new ReadOnlySpan(a, 0, 3); - bool b = first.EndsWith(second); - Assert.False(b); + Assert.False(new ReadOnlySpan(a, 0, 2).EndsWith(new ReadOnlySpan(a, 0, 3))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.False(new ReadOnlySpan(a, 0, 2).EndsWith(new ReadOnlySpan(a, 0, 3), comparer))); } [Fact] public static void EndsWithMatch() { int[] a = { 4, 5, 6 }; - ReadOnlySpan span = new ReadOnlySpan(a, 0, 3); - ReadOnlySpan slice = new ReadOnlySpan(a, 1, 2); - bool b = span.EndsWith(slice); - Assert.True(b); + Assert.True(new ReadOnlySpan(a, 0, 3).EndsWith(new ReadOnlySpan(a, 1, 2))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a, 0, 3).EndsWith(new ReadOnlySpan(a, 1, 2), comparer))); + Assert.False(new ReadOnlySpan(a, 0, 3).EndsWith(new ReadOnlySpan(a, 1, 2), GetFalseEqualityComparer())); } [Fact] @@ -52,10 +47,9 @@ public static void EndsWithMatchDifferentSpans() { int[] a = { 4, 5, 6 }; int[] b = { 4, 5, 6 }; - ReadOnlySpan span = new ReadOnlySpan(a, 0, 3); - ReadOnlySpan slice = new ReadOnlySpan(b, 0, 3); - bool c = span.EndsWith(slice); - Assert.True(c); + Assert.True(new ReadOnlySpan(a, 0, 3).EndsWith(new ReadOnlySpan(b, 0, 3))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a, 0, 3).EndsWith(new ReadOnlySpan(b, 0, 3), comparer))); + Assert.False(new ReadOnlySpan(a, 0, 3).EndsWith(new ReadOnlySpan(b, 0, 3), GetFalseEqualityComparer())); } [Fact] @@ -74,8 +68,7 @@ public static void OnEndsWithOfEqualSpansMakeSureEveryElementIsCompared() ReadOnlySpan firstSpan = new ReadOnlySpan(first); ReadOnlySpan secondSpan = new ReadOnlySpan(second); - bool b = firstSpan.EndsWith(secondSpan); - Assert.True(b); + Assert.True(firstSpan.EndsWith(secondSpan)); // Make sure each element of the array was compared once. (Strictly speaking, it would not be illegal for // EndsWith to compare an element more than once but that would be a non-optimal implementation and diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOf.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOf.T.cs index 42111dbd2808e3..933d98671f95b7 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOf.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOf.T.cs @@ -10,9 +10,8 @@ public static partial class ReadOnlySpanTests [Fact] public static void ZeroLengthIndexOf() { - ReadOnlySpan sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.IndexOf(0); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOf(0)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOf(0, comparer))); } [Fact] @@ -25,13 +24,13 @@ public static void TestMatch() { a[i] = 10 * (i + 1); } - ReadOnlySpan span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target = a[targetIndex]; - int idx = span.IndexOf(target); - Assert.Equal(targetIndex, idx); + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOf(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOf(target, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOf(target, GetFalseEqualityComparer())); } } } @@ -50,9 +49,9 @@ public static void TestMultipleMatch() a[length - 1] = 5555; a[length - 2] = 5555; - ReadOnlySpan span = new ReadOnlySpan(a); - int idx = span.IndexOf(5555); - Assert.Equal(length - 2, idx); + Assert.Equal(length - 2, new ReadOnlySpan(a).IndexOf(5555)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 2, new ReadOnlySpan(a).IndexOf(5555, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOf(5555, GetFalseEqualityComparer())); } } @@ -110,18 +109,16 @@ public static void MakeSureNoChecksGoOutOfRange() a[GuardLength + i] = new TInt(10 * (i + 1), checkForOutOfRangeAccess); } - ReadOnlySpan span = new ReadOnlySpan(a, GuardLength, length); - int idx = span.IndexOf(new TInt(9999, checkForOutOfRangeAccess)); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a, GuardLength, length).IndexOf(new TInt(9999, checkForOutOfRangeAccess))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, GuardLength, length).IndexOf(new TInt(9999, checkForOutOfRangeAccess), comparer))); } } [Fact] public static void ZeroLengthIndexOf_String() { - ReadOnlySpan sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.IndexOf("a"); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOf("a")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOf("a", comparer))); } [Fact] @@ -134,13 +131,12 @@ public static void TestMatchIndexOf_String() { a[i] = (10 * (i + 1)).ToString(); } - ReadOnlySpan span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { - string target = a[targetIndex]; - int idx = span.IndexOf(target); - Assert.Equal(targetIndex, idx); + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOf(a[targetIndex])); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOf(a[targetIndex], comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOf(a[targetIndex], GetFalseEqualityComparer())); } } } @@ -158,10 +154,9 @@ public static void TestNoMatchIndexOf_String() string val = (i + 1).ToString(); a[i] = val == target ? (target + 1) : val; } - ReadOnlySpan span = new ReadOnlySpan(a); - int idx = span.IndexOf(target); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOf(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).IndexOf(target, comparer))); } } @@ -179,9 +174,9 @@ public static void TestMultipleMatchIndexOf_String() a[length - 1] = "5555"; a[length - 2] = "5555"; - ReadOnlySpan span = new ReadOnlySpan(a); - int idx = span.IndexOf("5555"); - Assert.Equal(length - 2, idx); + Assert.Equal(length - 2, new ReadOnlySpan(a).IndexOf("5555")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 2, new ReadOnlySpan(a).IndexOf("5555", comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOf("5555", GetFalseEqualityComparer())); } } @@ -189,8 +184,9 @@ public static void TestMultipleMatchIndexOf_String() [MemberData(nameof(TestHelpers.IndexOfNullData), MemberType = typeof(TestHelpers))] public static void IndexOfNull_String(string[] spanInput, int expected) { - ReadOnlySpan theStrings = spanInput; - Assert.Equal(expected, theStrings.IndexOf((string)null)); + Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOf((string)null)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOf((string)null, comparer))); + Assert.Equal(-1, new ReadOnlySpan(spanInput).IndexOf((string)null, GetFalseEqualityComparer())); } } } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOfAny.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOfAny.T.cs index 70e2f177c49e2f..da57b026907644 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOfAny.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOfAny.T.cs @@ -10,9 +10,8 @@ public static partial class ReadOnlySpanTests [Fact] public static void ZeroLengthIndexOfAny_TwoInteger() { - var sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.IndexOfAny(0, 0); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(0, 0)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(0, 0, comparer))); } [Fact] @@ -23,7 +22,6 @@ public static void DefaultFilledIndexOfAny_TwoInteger() for (int length = 0; length < byte.MaxValue; length++) { var a = new int[length]; - var span = new ReadOnlySpan(a); int[] targets = { default, 99 }; @@ -32,8 +30,9 @@ public static void DefaultFilledIndexOfAny_TwoInteger() int index = rnd.Next(0, 2) == 0 ? 0 : 1; int target0 = targets[index]; int target1 = targets[(index + 1) % 2]; - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(0, idx); + Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, GetFalseEqualityComparer())); } } } @@ -50,14 +49,14 @@ public static void TestMatchIndexOfAny_TwoInteger() { a[i] = i + 1; } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target0 = a[targetIndex]; int target1 = 0; - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(targetIndex, idx); + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 1; targetIndex++) @@ -65,16 +64,18 @@ public static void TestMatchIndexOfAny_TwoInteger() int index = rnd.Next(0, 2) == 0 ? 0 : 1; int target0 = a[targetIndex + index]; int target1 = a[targetIndex + (index + 1) % 2]; - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(targetIndex, idx); + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target0 = 0; int target1 = a[targetIndex]; - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(targetIndex, idx); + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, GetFalseEqualityComparer())); } } } @@ -88,10 +89,9 @@ public static void TestNoMatchIndexOfAny_TwoInteger() var a = new int[length]; int target0 = rnd.Next(1, 256); int target1 = rnd.Next(1, 256); - var span = new ReadOnlySpan(a); - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); } } @@ -111,9 +111,9 @@ public static void TestMultipleMatchIndexOfAny_TwoInteger() a[length - 2] = 200; a[length - 3] = 200; - var span = new ReadOnlySpan(a); - int idx = span.IndexOfAny(200, 200); - Assert.Equal(length - 3, idx); + Assert.Equal(length - 3, new ReadOnlySpan(a).IndexOfAny(200, 200)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 3, new ReadOnlySpan(a).IndexOfAny(200, 200, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(200, 200, GetFalseEqualityComparer())); } } @@ -125,9 +125,9 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_TwoInteger() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 98; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.IndexOfAny(99, 98); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(99, 98)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(99, 98, comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -135,18 +135,17 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_TwoInteger() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 99; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.IndexOfAny(99, 99); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(99, 99)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(99, 99, comparer))); } } [Fact] public static void ZeroLengthIndexOfAny_ThreeInteger() { - var sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.IndexOfAny(0, 0, 0); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(0, 0, 0)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(0, 0, 0))); } [Fact] @@ -157,7 +156,6 @@ public static void DefaultFilledIndexOfAny_ThreeInteger() for (int length = 0; length < byte.MaxValue; length++) { var a = new int[length]; - var span = new ReadOnlySpan(a); int[] targets = { default, 99, 98 }; @@ -167,8 +165,10 @@ public static void DefaultFilledIndexOfAny_ThreeInteger() int target0 = targets[index]; int target1 = targets[(index + 1) % 2]; int target2 = targets[(index + 1) % 3]; - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(0, idx); + + Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } } } @@ -185,15 +185,16 @@ public static void TestMatchIndexOfAny_ThreeInteger() { a[i] = i + 1; } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target0 = a[targetIndex]; int target1 = 0; int target2 = 0; - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 2; targetIndex++) @@ -202,8 +203,10 @@ public static void TestMatchIndexOfAny_ThreeInteger() int target0 = a[targetIndex + index]; int target1 = a[targetIndex + (index + 1) % 2]; int target2 = a[targetIndex + (index + 1) % 3]; - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length; targetIndex++) @@ -211,8 +214,10 @@ public static void TestMatchIndexOfAny_ThreeInteger() int target0 = 0; int target1 = 0; int target2 = a[targetIndex]; - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } } } @@ -227,10 +232,9 @@ public static void TestNoMatchIndexOfAny_ThreeInteger() int target0 = rnd.Next(1, 256); int target1 = rnd.Next(1, 256); int target2 = rnd.Next(1, 256); - var span = new ReadOnlySpan(a); - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); } } @@ -251,9 +255,9 @@ public static void TestMultipleMatchIndexOfAny_ThreeInteger() a[length - 3] = 200; a[length - 4] = 200; - var span = new ReadOnlySpan(a); - int idx = span.IndexOfAny(200, 200, 200); - Assert.Equal(length - 4, idx); + Assert.Equal(length - 4, new ReadOnlySpan(a).IndexOfAny(200, 200, 200)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 4, new ReadOnlySpan(a).IndexOfAny(200, 200, 200, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(200, 200, 200, GetFalseEqualityComparer())); } } @@ -265,9 +269,9 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_ThreeInteger() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 98; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.IndexOfAny(99, 98, 99); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(99, 98, 99)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(99, 98, 99, comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -275,23 +279,22 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_ThreeInteger() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 99; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.IndexOfAny(99, 99, 99); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(99, 99, 99)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(99, 99, 99, comparer))); } } [Fact] public static void ZeroLengthIndexOfAny_ManyInteger() { - var sp = new ReadOnlySpan(Array.Empty()); - var values = new ReadOnlySpan(new int[] { 0, 0, 0, 0 }); - int idx = sp.IndexOfAny(values); - Assert.Equal(-1, idx); + var values = new int[] { 0, 0, 0, 0 }; + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(values, comparer))); - values = new ReadOnlySpan(new int[] { }); - idx = sp.IndexOfAny(values); - Assert.Equal(-1, idx); + values = new int[] { }; + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(values, comparer))); } [Fact] @@ -300,14 +303,13 @@ public static void DefaultFilledIndexOfAny_ManyInteger() for (int length = 0; length < byte.MaxValue; length++) { var a = new int[length]; - var span = new ReadOnlySpan(a); - - var values = new ReadOnlySpan(new int[] { default, 99, 98, 0 }); + var values = new int[] { default, 99, 98, 0 }; for (int i = 0; i < length; i++) { - int idx = span.IndexOfAny(values); - Assert.Equal(0, idx); + Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(values, GetFalseEqualityComparer())); } } } @@ -324,34 +326,35 @@ public static void TestMatchIndexOfAny_ManyInteger() { a[i] = i + 1; } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { - var values = new ReadOnlySpan(new int[] { a[targetIndex], 0, 0, 0 }); - int idx = span.IndexOfAny(values); - Assert.Equal(targetIndex, idx); + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(new ReadOnlySpan(new int[] { a[targetIndex], 0, 0, 0 }))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(new ReadOnlySpan(new int[] { a[targetIndex], 0, 0, 0 }), comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(new ReadOnlySpan(new int[] { a[targetIndex], 0, 0, 0 }), GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 3; targetIndex++) { int index = rnd.Next(0, 4) == 0 ? 0 : 1; - var values = new ReadOnlySpan(new int[] + var values = new int[] { a[targetIndex + index], a[targetIndex + (index + 1) % 2], a[targetIndex + (index + 1) % 3], a[targetIndex + (index + 1) % 4] - }); - int idx = span.IndexOfAny(values); - Assert.Equal(targetIndex, idx); + }; + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(values, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length; targetIndex++) { - var values = new ReadOnlySpan(new int[] { 0, 0, 0, a[targetIndex] }); - int idx = span.IndexOfAny(values); - Assert.Equal(targetIndex, idx); + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(new ReadOnlySpan(new int[] { 0, 0, 0, a[targetIndex] }))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(new ReadOnlySpan(new int[] { 0, 0, 0, a[targetIndex] }), comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(new ReadOnlySpan(new int[] { 0, 0, 0, a[targetIndex] }), GetFalseEqualityComparer())); } } } @@ -372,7 +375,6 @@ public static void TestMatchValuesLargerIndexOfAny_ManyInteger() } a[i] = 255; } - var span = new ReadOnlySpan(a); var targets = new int[length * 2]; for (int i = 0; i < targets.Length; i++) @@ -384,9 +386,9 @@ public static void TestMatchValuesLargerIndexOfAny_ManyInteger() targets[i] = rnd.Next(1, 255); } - var values = new ReadOnlySpan(targets); - int idx = span.IndexOfAny(values); - Assert.Equal(expectedIndex, idx); + Assert.Equal(expectedIndex, new ReadOnlySpan(a).IndexOfAny(new ReadOnlySpan(targets))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expectedIndex, new ReadOnlySpan(a).IndexOfAny(new ReadOnlySpan(targets), comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(new ReadOnlySpan(targets), GetFalseEqualityComparer())); } } @@ -402,11 +404,9 @@ public static void TestNoMatchIndexOfAny_ManyInteger() { targets[i] = rnd.Next(1, 256); } - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(targets); - int idx = span.IndexOfAny(values); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(targets, comparer))); } } @@ -422,11 +422,9 @@ public static void TestNoMatchValuesLargerIndexOfAny_ManyInteger() { targets[i] = rnd.Next(1, 256); } - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(targets); - int idx = span.IndexOfAny(values); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(targets, comparer))); } } @@ -448,10 +446,11 @@ public static void TestMultipleMatchIndexOfAny_ManyInteger() a[length - 4] = 200; a[length - 5] = 200; - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(new int[] { 200, 200, 200, 200, 200, 200, 200, 200, 200 }); - int idx = span.IndexOfAny(values); - Assert.Equal(length - 5, idx); + var values = new int[] { 200, 200, 200, 200, 200, 200, 200, 200, 200 }; + + Assert.Equal(length - 5, new ReadOnlySpan(a).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 5, new ReadOnlySpan(a).IndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(values, GetFalseEqualityComparer())); } } @@ -463,10 +462,10 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_ManyInteger() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 98; - var span = new ReadOnlySpan(a, 1, length - 1); - var values = new ReadOnlySpan(new int[] { 99, 98, 99, 98, 99, 98 }); - int index = span.IndexOfAny(values); - Assert.Equal(-1, index); + var values = new int[] { 99, 98, 99, 98, 99, 98 }; + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(values, comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -474,19 +473,19 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_ManyInteger() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 99; - var span = new ReadOnlySpan(a, 1, length - 1); - var values = new ReadOnlySpan(new int[] { 99, 99, 99, 99, 99, 99 }); - int index = span.IndexOfAny(values); - Assert.Equal(-1, index); + + var values = new int[] { 99, 99, 99, 99, 99, 99 }; + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(values, comparer))); } } [Fact] public static void ZeroLengthIndexOfAny_TwoString() { - var sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.IndexOfAny("0", "0"); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny("0", "0")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny("0", "0", comparer))); } [Fact] @@ -497,9 +496,7 @@ public static void DefaultFilledIndexOfAny_TwoString() for (int length = 0; length < byte.MaxValue; length++) { var a = new string[length]; - var tempSpan = new Span(a); - tempSpan.Fill(""); - ReadOnlySpan span = tempSpan; + Array.Fill(a, ""); string[] targets = { "", "99" }; @@ -508,8 +505,10 @@ public static void DefaultFilledIndexOfAny_TwoString() int index = rnd.Next(0, 2) == 0 ? 0 : 1; string target0 = targets[index]; string target1 = targets[(index + 1) % 2]; - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(0, idx); + + Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, GetFalseEqualityComparer())); } } } @@ -526,14 +525,15 @@ public static void TestMatchIndexOfAny_TwoString() { a[i] = (i + 1).ToString(); } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { string target0 = a[targetIndex]; string target1 = "0"; - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 1; targetIndex++) @@ -541,16 +541,20 @@ public static void TestMatchIndexOfAny_TwoString() int index = rnd.Next(0, 2) == 0 ? 0 : 1; string target0 = a[targetIndex + index]; string target1 = a[targetIndex + (index + 1) % 2]; - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 1; targetIndex++) { string target0 = "0"; string target1 = a[targetIndex + 1]; - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(targetIndex + 1, idx); + + Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, GetFalseEqualityComparer())); } } } @@ -564,10 +568,9 @@ public static void TestNoMatchIndexOfAny_TwoString() var a = new string[length]; string target0 = rnd.Next(1, 256).ToString(); string target1 = rnd.Next(1, 256).ToString(); - var span = new ReadOnlySpan(a); - int idx = span.IndexOfAny(target0, target1); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, comparer))); } } @@ -587,9 +590,9 @@ public static void TestMultipleMatchIndexOfAny_TwoString() a[length - 2] = "200"; a[length - 3] = "200"; - var span = new ReadOnlySpan(a); - int idx = span.IndexOfAny("200", "200"); - Assert.Equal(length - 3, idx); + Assert.Equal(length - 3, new ReadOnlySpan(a).IndexOfAny("200", "200")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 3, new ReadOnlySpan(a).IndexOfAny("200", "200", comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny("200", "200", GetFalseEqualityComparer())); } } @@ -601,9 +604,9 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_TwoString() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "98"; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.IndexOfAny("99", "98"); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny("99", "98")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny("99", "98", comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -611,18 +614,17 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_TwoString() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "99"; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.IndexOfAny("99", "99"); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny("99", "99")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny("99", "99", comparer))); } } [Fact] public static void ZeroLengthIndexOf_ThreeString() { - var sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.IndexOfAny("0", "0", "0"); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny("0", "0", "0")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny("0", "0", "0", comparer))); } [Fact] @@ -633,9 +635,7 @@ public static void DefaultFilledIndexOfAny_ThreeString() for (int length = 0; length < byte.MaxValue; length++) { var a = new string[length]; - var tempSpan = new Span(a); - tempSpan.Fill(""); - ReadOnlySpan span = tempSpan; + Array.Fill(a, ""); string[] targets = { "", "99", "98" }; @@ -645,8 +645,10 @@ public static void DefaultFilledIndexOfAny_ThreeString() string target0 = targets[index]; string target1 = targets[(index + 1) % 2]; string target2 = targets[(index + 1) % 3]; - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(0, idx); + + Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } } } @@ -663,15 +665,16 @@ public static void TestMatchIndexOfAny_ThreeString() { a[i] = (i + 1).ToString(); } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { string target0 = a[targetIndex]; string target1 = "0"; string target2 = "0"; - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 2; targetIndex++) @@ -680,8 +683,10 @@ public static void TestMatchIndexOfAny_ThreeString() string target0 = a[targetIndex + index]; string target1 = a[targetIndex + (index + 1) % 2]; string target2 = a[targetIndex + (index + 1) % 3]; - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length; targetIndex++) @@ -689,8 +694,10 @@ public static void TestMatchIndexOfAny_ThreeString() string target0 = "0"; string target1 = "0"; string target2 = a[targetIndex]; - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } } } @@ -705,10 +712,9 @@ public static void TestNoMatchIndexOfAny_ThreeString() string target0 = rnd.Next(1, 256).ToString(); string target1 = rnd.Next(1, 256).ToString(); string target2 = rnd.Next(1, 256).ToString(); - var span = new ReadOnlySpan(a); - int idx = span.IndexOfAny(target0, target1, target2); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(target0, target1, target2, comparer))); } } @@ -729,9 +735,9 @@ public static void TestMultipleMatchIndexOfAny_ThreeString() a[length - 3] = "200"; a[length - 4] = "200"; - var span = new ReadOnlySpan(a); - int idx = span.IndexOfAny("200", "200", "200"); - Assert.Equal(length - 4, idx); + Assert.Equal(length - 4, new ReadOnlySpan(a).IndexOfAny("200", "200", "200")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 4, new ReadOnlySpan(a).IndexOfAny("200", "200", "200", comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny("200", "200", "200", GetFalseEqualityComparer())); } } @@ -743,9 +749,9 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_ThreeString() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "98"; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.IndexOfAny("99", "98", "99"); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny("99", "98", "99")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny("99", "98", "99", comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -753,23 +759,22 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_ThreeString() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "99"; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.IndexOfAny("99", "99", "99"); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny("99", "99", "99")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny("99", "99", "99", comparer))); } } [Fact] public static void ZeroLengthIndexOfAny_ManyString() { - var sp = new ReadOnlySpan(Array.Empty()); - var values = new ReadOnlySpan(new string[] { "0", "0", "0", "0" }); - int idx = sp.IndexOfAny(values); - Assert.Equal(-1, idx); + var values = new string[] { "0", "0", "0", "0" }; + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(values, comparer))); - values = new ReadOnlySpan(new string[] { }); - idx = sp.IndexOfAny(values); - Assert.Equal(-1, idx); + values = new string[] { }; + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).IndexOfAny(values, comparer))); } [Fact] @@ -778,16 +783,15 @@ public static void DefaultFilledIndexOfAny_ManyString() for (int length = 0; length < byte.MaxValue; length++) { var a = new string[length]; - var tempSpan = new Span(a); - tempSpan.Fill(""); - ReadOnlySpan span = tempSpan; + Array.Fill(a, ""); - var values = new ReadOnlySpan(new string[] { "", "99", "98", "0" }); + var values = new string[] { "", "99", "98", "0" }; for (int i = 0; i < length; i++) { - int idx = span.IndexOfAny(values); - Assert.Equal(0, idx); + Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a).IndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(values, GetFalseEqualityComparer())); } } } @@ -804,34 +808,39 @@ public static void TestMatchIndexOfAny_ManyString() { a[i] = (i + 1).ToString(); } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { - var values = new ReadOnlySpan(new string[] { a[targetIndex], "0", "0", "0" }); - int idx = span.IndexOfAny(values); - Assert.Equal(targetIndex, idx); + var values = new string[] { a[targetIndex], "0", "0", "0" }; + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(values, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 3; targetIndex++) { int index = rnd.Next(0, 4) == 0 ? 0 : 1; - var values = new ReadOnlySpan(new string[] + var values = new string[] { a[targetIndex + index], a[targetIndex + (index + 1) % 2], a[targetIndex + (index + 1) % 3], a[targetIndex + (index + 1) % 4] - }); - int idx = span.IndexOfAny(values); - Assert.Equal(targetIndex, idx); + }; + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(values, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length; targetIndex++) { - var values = new ReadOnlySpan(new string[] { "0", "0", "0", a[targetIndex] }); - int idx = span.IndexOfAny(values); - Assert.Equal(targetIndex, idx); + var values = new string[] { "0", "0", "0", a[targetIndex] }; + + Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).IndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(values, GetFalseEqualityComparer())); } } } @@ -853,7 +862,6 @@ public static void TestMatchValuesLargerIndexOfAny_ManyString() } a[i] = "255"; } - var span = new ReadOnlySpan(a); var targets = new string[length * 2]; for (int i = 0; i < targets.Length; i++) @@ -866,9 +874,9 @@ public static void TestMatchValuesLargerIndexOfAny_ManyString() targets[i] = rnd.Next(1, 255).ToString(); } - var values = new ReadOnlySpan(targets); - int idx = span.IndexOfAny(values); - Assert.Equal(expectedIndex, idx); + Assert.Equal(expectedIndex, new ReadOnlySpan(a).IndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expectedIndex, new ReadOnlySpan(a).IndexOfAny(targets, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(targets, GetFalseEqualityComparer())); } } @@ -884,11 +892,9 @@ public static void TestNoMatchIndexOfAny_ManyString() { targets[i] = rnd.Next(1, 256).ToString(); } - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(targets); - int idx = span.IndexOfAny(values); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(targets, comparer))); } } @@ -904,11 +910,9 @@ public static void TestNoMatchValuesLargerIndexOfAny_ManyString() { targets[i] = rnd.Next(1, 256).ToString(); } - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(targets); - int idx = span.IndexOfAny(values); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(targets, comparer))); } } @@ -930,10 +934,11 @@ public static void TestMultipleMatchIndexOfAny_ManyString() a[length - 4] = "200"; a[length - 5] = "200"; - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(new string[] { "200", "200", "200", "200", "200", "200", "200", "200", "200" }); - int idx = span.IndexOfAny(values); - Assert.Equal(length - 5, idx); + var values = new string[] { "200", "200", "200", "200", "200", "200", "200", "200", "200" }; + + Assert.Equal(length - 5, new ReadOnlySpan(a).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 5, new ReadOnlySpan(a).IndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).IndexOfAny(values, GetFalseEqualityComparer())); } } @@ -945,10 +950,10 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_ManyString() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "98"; - var span = new ReadOnlySpan(a, 1, length - 1); - var values = new ReadOnlySpan(new string[] { "99", "98", "99", "98", "99", "98" }); - int index = span.IndexOfAny(values); - Assert.Equal(-1, index); + var values = new string[] { "99", "98", "99", "98", "99", "98" }; + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(values, comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -956,10 +961,10 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_ManyString() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "99"; - var span = new ReadOnlySpan(a, 1, length - 1); - var values = new ReadOnlySpan(new string[] { "99", "99", "99", "99", "99", "99" }); - int index = span.IndexOfAny(values); - Assert.Equal(-1, index); + var values = new string[] { "99", "99", "99", "99", "99", "99" }; + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).IndexOfAny(values, comparer))); } } @@ -967,20 +972,27 @@ public static void MakeSureNoChecksGoOutOfRangeIndexOfAny_ManyString() [MemberData(nameof(TestHelpers.IndexOfAnyNullSequenceData), MemberType = typeof(TestHelpers))] public static void IndexOfAnyNullSequence_String(string[] spanInput, string[] searchInput, int expected) { - ReadOnlySpan theStrings = spanInput; - Assert.Equal(expected, theStrings.IndexOfAny(searchInput)); - Assert.Equal(expected, theStrings.IndexOfAny((ReadOnlySpan)searchInput)); + Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOfAny(searchInput)); + Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOfAny((ReadOnlySpan)searchInput)); + + Assert.All(GetDefaultEqualityComparers(), comparer => + { + Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOfAny(searchInput, comparer)); + Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOfAny((ReadOnlySpan)searchInput, comparer)); + }); if (searchInput != null) { if (searchInput.Length >= 3) { - Assert.Equal(expected, theStrings.IndexOfAny(searchInput[0], searchInput[1], searchInput[2])); + Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOfAny(searchInput[0], searchInput[1], searchInput[2])); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOfAny(searchInput[0], searchInput[1], searchInput[2], comparer))); } if (searchInput.Length >= 2) { - Assert.Equal(expected, theStrings.IndexOfAny(searchInput[0], searchInput[1])); + Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOfAny(searchInput[0], searchInput[1])); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(spanInput).IndexOfAny(searchInput[0], searchInput[1], comparer))); } } } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOfSequence.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOfSequence.T.cs index 9d07604f312d4a..66cdab3d41d388 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOfSequence.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/IndexOfSequence.T.cs @@ -10,228 +10,262 @@ public static partial class ReadOnlySpanTests [Fact] public static void IndexOfSequenceMatchAtStart() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 5, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 5, 1, 77 }); - int index = span.IndexOf(value); - Assert.Equal(0, index); + var source = new int[] { 5, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }; + var value = new int[] { 5, 1, 77 }; + + Assert.Equal(0, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceMultipleMatch() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 1, 2, 3, 1, 2, 3, 1, 2, 3 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 2, 3 }); - int index = span.IndexOf(value); - Assert.Equal(1, index); + var source = new int[] { 1, 2, 3, 1, 2, 3, 1, 2, 3 }; + var value = new int[] { 2, 3 }; + + Assert.Equal(1, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(1, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceRestart() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 77, 77, 88 }); - int index = span.IndexOf(value); - Assert.Equal(10, index); + var source = new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }; + var value = new int[] { 77, 77, 88 }; + + Assert.Equal(10, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(10, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceNoMatch() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 77, 77, 88, 99 }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }; + var value = new int[] { 77, 77, 88, 99 }; + + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceNotEvenAHeadMatch() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 100, 77, 88, 99 }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }; + var value = new int[] { 100, 77, 88, 99 }; + + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceMatchAtVeryEnd() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 3, 4, 5 }); - int index = span.IndexOf(value); - Assert.Equal(3, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 3, 4, 5 }; + + Assert.Equal(3, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(3, new ReadOnlySpan(source).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceJustPastVeryEnd() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }, 0, 5); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 3, 4, 5 }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 3, 4, 5 }; + + Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceZeroLengthValue() { - // A zero-length value is always "found" at the start of the span. - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); - ReadOnlySpan value = new ReadOnlySpan(Array.Empty()); - int index = span.IndexOf(value); - Assert.Equal(0, index); + // A zero-length value is always "found" at the start of the source. + var source = new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }; + var value = Array.Empty(); + + Assert.Equal(0, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(source).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceZeroLengthSpan() { - ReadOnlySpan span = new ReadOnlySpan(Array.Empty()); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 1, 2, 3 }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = Array.Empty(); + var value = new int[] { 1, 2, 3 }; + + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceLengthOneValue() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 2 }); - int index = span.IndexOf(value); - Assert.Equal(2, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 2 }; + + Assert.Equal(2, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(2, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceLengthOneValueAtVeryEnd() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 5 }); - int index = span.IndexOf(value); - Assert.Equal(5, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 5 }; + + Assert.Equal(5, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(5, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceLengthOneValueJustPasttVeryEnd() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }, 0, 5); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 5 }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 5 }; + + Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceMatchAtStart_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "5", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "5", "1", "77" }); - int index = span.IndexOf(value); - Assert.Equal(0, index); + var source = new string[] { "5", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }; + var value = new string[] { "5", "1", "77" }; + + Assert.Equal(0, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceMultipleMatch_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "1", "2", "3", "1", "2", "3", "1", "2", "3" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "2", "3" }); - int index = span.IndexOf(value); - Assert.Equal(1, index); + var source = new string[] { "1", "2", "3", "1", "2", "3", "1", "2", "3" }; + var value = new string[] { "2", "3" }; + + Assert.Equal(1, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(1, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceRestart_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "77", "77", "88" }); - int index = span.IndexOf(value); - Assert.Equal(10, index); + var source = new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }; + var value = new string[] { "77", "77", "88" }; + + Assert.Equal(10, source.IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(10, source.IndexOf(value, comparer))); + Assert.Equal(-1, source.IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceNoMatch_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "77", "77", "88", "99" }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }; + var value = new string[] { "77", "77", "88", "99" }; + + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceNotEvenAHeadMatch_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "100", "77", "88", "99" }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }; + var value = new string[] { "100", "77", "88", "99" }; + + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceMatchAtVeryEnd_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "3", "4", "5" }); - int index = span.IndexOf(value); - Assert.Equal(3, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "3", "4", "5" }; + + Assert.Equal(3, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(3, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceJustPastVeryEnd_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "3", "4", "5" }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "3", "4", "5" }; + + Assert.Equal(-1, source.AsSpan(0, 5).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, source.AsSpan(0, 5).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceZeroLengthValue_String() { - // A zero-length value is always "found" at the start of the span. - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); - ReadOnlySpan value = new ReadOnlySpan(Array.Empty()); - int index = span.IndexOf(value); - Assert.Equal(0, index); + // A zero-length value is always "found" at the start of the source. + var source = new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }; + var value = Array.Empty(); + + Assert.Equal(0, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(source).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceZeroLengthSpan_String() { - ReadOnlySpan span = new ReadOnlySpan(Array.Empty()); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "1", "2", "3" }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = Array.Empty(); + var value = new string[] { "1", "2", "3" }; + + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, comparer))); } [Fact] public static void IndexOfSequenceLengthOneValue_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "2" }); - int index = span.IndexOf(value); - Assert.Equal(2, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "2" }; + + Assert.Equal(2, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(2, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceLengthOneValueAtVeryEnd_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "5" }); - int index = span.IndexOf(value); - Assert.Equal(5, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "5" }; + + Assert.Equal(5, new ReadOnlySpan(source).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(5, new ReadOnlySpan(source).IndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).IndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void IndexOfSequenceLengthOneValueJustPasttVeryEnd_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "5" }); - int index = span.IndexOf(value); - Assert.Equal(-1, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "5" }; + + Assert.Equal(-1, source.AsSpan(0, 5).IndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, source.AsSpan(0, 5).IndexOf(value, comparer))); } [Theory] [MemberData(nameof(TestHelpers.IndexOfNullSequenceData), MemberType = typeof(TestHelpers))] - public static void IndexOfNullSequence_String(string[] spanInput, string[] searchInput, int expected) + public static void IndexOfNullSequence_String(string[] source, string[] target, int expected) { - ReadOnlySpan theStrings = spanInput; - Assert.Equal(expected, theStrings.IndexOf(searchInput)); - Assert.Equal(expected, theStrings.IndexOf((ReadOnlySpan)searchInput)); + Assert.Equal(expected, new ReadOnlySpan(source).IndexOf(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(source).IndexOf(target, comparer))); } } } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOf.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOf.T.cs index 30af16699a50ed..ce9e01493f3782 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOf.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOf.T.cs @@ -10,9 +10,8 @@ public static partial class ReadOnlySpanTests [Fact] public static void ZeroLengthLastIndexOf() { - ReadOnlySpan sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.LastIndexOf(0); - Assert.Equal(-1, idx); + Assert.Equal(-1, Array.Empty().LastIndexOf(0)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, Array.Empty().LastIndexOf(0, comparer))); } [Fact] @@ -25,13 +24,14 @@ public static void TestMatchLastIndexOf() { a[i] = 10 * (i + 1); } - ReadOnlySpan span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target = a[targetIndex]; - int idx = span.LastIndexOf(target); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOf(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOf(target, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOf(target, GetFalseEqualityComparer())); } } } @@ -50,9 +50,9 @@ public static void TestMultipleMatchLastIndexOf() a[length - 1] = 5555; a[length - 2] = 5555; - ReadOnlySpan span = new ReadOnlySpan(a); - int idx = span.LastIndexOf(5555); - Assert.Equal(length - 1, idx); + Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOf(5555)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOf(5555, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOf(5555, GetFalseEqualityComparer())); } } @@ -110,18 +110,16 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOf() a[GuardLength + i] = new TInt(10 * (i + 1), checkForOutOfRangeAccess); } - ReadOnlySpan span = new ReadOnlySpan(a, GuardLength, length); - int idx = span.LastIndexOf(new TInt(9999, checkForOutOfRangeAccess)); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a, GuardLength, length).LastIndexOf(new TInt(9999, checkForOutOfRangeAccess))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, GuardLength, length).LastIndexOf(new TInt(9999, checkForOutOfRangeAccess), comparer))); } } [Fact] public static void ZeroLengthLastIndexOf_String() { - ReadOnlySpan sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.LastIndexOf("a"); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOf("a")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOf("a", comparer))); } [Fact] @@ -134,13 +132,14 @@ public static void TestMatchLastIndexOf_String() { a[i] = (10 * (i + 1)).ToString(); } - ReadOnlySpan span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { string target = a[targetIndex]; - int idx = span.LastIndexOf(target); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOf(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOf(target, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOf(target, GetFalseEqualityComparer())); } } } @@ -158,10 +157,9 @@ public static void TestNoMatchLastIndexOf_String() string val = (i + 1).ToString(); a[i] = val == target ? (target + 1) : val; } - ReadOnlySpan span = new ReadOnlySpan(a); - int idx = span.LastIndexOf(target); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOf(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOf(target, comparer))); } } @@ -179,9 +177,9 @@ public static void TestMultipleMatchLastIndexOf_String() a[length - 1] = "5555"; a[length - 2] = "5555"; - ReadOnlySpan span = new ReadOnlySpan(a); - int idx = span.LastIndexOf("5555"); - Assert.Equal(length - 1, idx); + Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOf("5555")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOf("5555", comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOf("5555", GetFalseEqualityComparer())); } } @@ -189,8 +187,8 @@ public static void TestMultipleMatchLastIndexOf_String() [MemberData(nameof(TestHelpers.LastIndexOfNullData), MemberType = typeof(TestHelpers))] public static void LastIndexOfNull_String(string[] spanInput, int expected) { - ReadOnlySpan theStrings = spanInput; - Assert.Equal(expected, theStrings.LastIndexOf((string)null)); + Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOf((string)null)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOf((string)null, comparer))); } } } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOfAny.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOfAny.T.cs index aad66673dc6048..0c81bc33840cc0 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOfAny.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOfAny.T.cs @@ -10,9 +10,8 @@ public static partial class ReadOnlySpanTests [Fact] public static void ZeroLengthLastIndexOfAny_TwoByte() { - var sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.LastIndexOfAny(0, 0); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(0, 0)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(0, 0, comparer))); } [Fact] @@ -23,7 +22,6 @@ public static void DefaultFilledLastIndexOfAny_TwoByte() for (int length = 0; length < byte.MaxValue; length++) { var a = new int[length]; - var span = new ReadOnlySpan(a); int[] targets = { default, 99 }; @@ -32,8 +30,10 @@ public static void DefaultFilledLastIndexOfAny_TwoByte() int index = rnd.Next(0, 2) == 0 ? 0 : 1; int target0 = targets[index]; int target1 = targets[(index + 1) % 2]; - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(span.Length - 1, idx); + + Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, GetFalseEqualityComparer())); } } } @@ -48,30 +48,35 @@ public static void TestMatchLastIndexOfAny_TwoByte() { a[i] = i + 1; } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target0 = a[targetIndex]; int target1 = 0; - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 1; targetIndex++) { int target0 = a[targetIndex]; int target1 = a[targetIndex + 1]; - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(targetIndex + 1, idx); + + Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 1; targetIndex++) { int target0 = 0; int target1 = a[targetIndex + 1]; - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(targetIndex + 1, idx); + + Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, GetFalseEqualityComparer())); } } } @@ -85,10 +90,9 @@ public static void TestNoMatchLastIndexOfAny_TwoByte() var a = new int[length]; int target0 = rnd.Next(1, 256); int target1 = rnd.Next(1, 256); - var span = new ReadOnlySpan(a); - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); } } @@ -108,9 +112,9 @@ public static void TestMultipleMatchLastIndexOfAny_TwoByte() a[length - 2] = 200; a[length - 3] = 200; - var span = new ReadOnlySpan(a); - int idx = span.LastIndexOfAny(200, 200); - Assert.Equal(length - 1, idx); + Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny(200, 200)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny(200, 200, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(200, 200, GetFalseEqualityComparer())); } } @@ -122,9 +126,9 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_TwoByte() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 98; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.LastIndexOfAny(99, 98); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(99, 98)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(99, 98, comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -132,18 +136,17 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_TwoByte() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 99; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.LastIndexOfAny(99, 99); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(99, 99)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(99, 99, comparer))); } } [Fact] public static void ZeroLengthIndexOf_ThreeByte() { - var sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.LastIndexOfAny(0, 0, 0); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(0, 0, 0)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(0, 0, 0, comparer))); } [Fact] @@ -154,7 +157,6 @@ public static void DefaultFilledLastIndexOfAny_ThreeByte() for (int length = 0; length < byte.MaxValue; length++) { var a = new int[length]; - var span = new ReadOnlySpan(a); int[] targets = { default, 99, 98 }; @@ -164,8 +166,10 @@ public static void DefaultFilledLastIndexOfAny_ThreeByte() int target0 = targets[index]; int target1 = targets[(index + 1) % 2]; int target2 = targets[(index + 1) % 3]; - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(span.Length - 1, idx); + + Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } } } @@ -180,15 +184,16 @@ public static void TestMatchLastIndexOfAny_ThreeByte() { a[i] = i + 1; } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { int target0 = a[targetIndex]; int target1 = 0; int target2 = 0; - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 2; targetIndex++) @@ -196,8 +201,10 @@ public static void TestMatchLastIndexOfAny_ThreeByte() int target0 = a[targetIndex]; int target1 = a[targetIndex + 1]; int target2 = a[targetIndex + 2]; - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex + 2, idx); + + Assert.Equal(targetIndex + 2, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 2, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 2; targetIndex++) @@ -205,8 +212,10 @@ public static void TestMatchLastIndexOfAny_ThreeByte() int target0 = 0; int target1 = 0; int target2 = a[targetIndex + 2]; - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex + 2, idx); + + Assert.Equal(targetIndex + 2, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 2, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } } } @@ -221,10 +230,9 @@ public static void TestNoMatchLastIndexOfAny_ThreeByte() int target0 = rnd.Next(1, 256); int target1 = rnd.Next(1, 256); int target2 = rnd.Next(1, 256); - var span = new ReadOnlySpan(a); - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); } } @@ -245,9 +253,9 @@ public static void TestMultipleMatchLastIndexOfAny_ThreeByte() a[length - 3] = 200; a[length - 4] = 200; - var span = new ReadOnlySpan(a); - int idx = span.LastIndexOfAny(200, 200, 200); - Assert.Equal(length - 1, idx); + Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny(200, 200, 200)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny(200, 200, 200, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(200, 200, 200, GetFalseEqualityComparer())); } } @@ -259,9 +267,9 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_ThreeByte() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 98; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.LastIndexOfAny(99, 98, 99); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(99, 98, 99)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(99, 98, 99, comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -269,23 +277,22 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_ThreeByte() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 99; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.LastIndexOfAny(99, 99, 99); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(99, 99, 99)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(99, 99, 99, comparer))); } } [Fact] public static void ZeroLengthLastIndexOfAny_ManyByte() { - var sp = new ReadOnlySpan(Array.Empty()); - var values = new ReadOnlySpan(new int[] { 0, 0, 0, 0 }); - int idx = sp.LastIndexOfAny(values); - Assert.Equal(-1, idx); + var values = new int[] { 0, 0, 0, 0 }; + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(values, comparer))); - values = new ReadOnlySpan(new int[] { }); - idx = sp.LastIndexOfAny(values); - Assert.Equal(-1, idx); + values = new int[] { }; + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(values, comparer))); } [Fact] @@ -294,14 +301,14 @@ public static void DefaultFilledLastIndexOfAny_ManyByte() for (int length = 0; length < byte.MaxValue; length++) { var a = new int[length]; - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(new int[] { default, 99, 98, 0 }); + var values = new int[] { default, 99, 98, 0 }; for (int i = 0; i < length; i++) { - int idx = span.LastIndexOfAny(values); - Assert.Equal(span.Length - 1, idx); + Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } } } @@ -316,27 +323,32 @@ public static void TestMatchLastIndexOfAny_ManyByte() { a[i] = i + 1; } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { - var values = new ReadOnlySpan(new int[] { a[targetIndex], 0, 0, 0 }); - int idx = span.LastIndexOfAny(values); - Assert.Equal(targetIndex, idx); + var values = new int[] { a[targetIndex], 0, 0, 0 }; + + Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 3; targetIndex++) { - var values = new ReadOnlySpan(new int[] { a[targetIndex], a[targetIndex + 1], a[targetIndex + 2], a[targetIndex + 3] }); - int idx = span.LastIndexOfAny(values); - Assert.Equal(targetIndex + 3, idx); + var values = new int[] { a[targetIndex], a[targetIndex + 1], a[targetIndex + 2], a[targetIndex + 3] }; + + Assert.Equal(targetIndex + 3, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 3, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 3; targetIndex++) { - var values = new ReadOnlySpan(new int[] { 0, 0, 0, a[targetIndex + 3] }); - int idx = span.LastIndexOfAny(values); - Assert.Equal(targetIndex + 3, idx); + var values = new int[] { 0, 0, 0, a[targetIndex + 3] }; + + Assert.Equal(targetIndex + 3, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 3, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } } } @@ -357,7 +369,6 @@ public static void TestMatchValuesLargerLastIndexOfAny_ManyByte() } a[i] = 255; } - var span = new ReadOnlySpan(a); var targets = new int[length * 2]; for (int i = 0; i < targets.Length; i++) @@ -369,9 +380,9 @@ public static void TestMatchValuesLargerLastIndexOfAny_ManyByte() targets[i] = rnd.Next(1, 255); } - var values = new ReadOnlySpan(targets); - int idx = span.LastIndexOfAny(values); - Assert.Equal(expectedIndex, idx); + Assert.Equal(expectedIndex, new ReadOnlySpan(a).LastIndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expectedIndex, new ReadOnlySpan(a).LastIndexOfAny(targets, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets, GetFalseEqualityComparer())); } } @@ -387,11 +398,9 @@ public static void TestNoMatchLastIndexOfAny_ManyByte() { targets[i] = rnd.Next(1, 256); } - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(targets); - int idx = span.LastIndexOfAny(values); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets, comparer))); } } @@ -407,11 +416,9 @@ public static void TestNoMatchValuesLargerLastIndexOfAny_ManyByte() { targets[i] = rnd.Next(1, 256); } - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(targets); - int idx = span.LastIndexOfAny(values); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets, comparer))); } } @@ -433,10 +440,11 @@ public static void TestMultipleMatchLastIndexOfAny_ManyByte() a[length - 4] = 200; a[length - 5] = 200; - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(new int[] { 200, 200, 200, 200, 200, 200, 200, 200, 200 }); - int idx = span.LastIndexOfAny(values); - Assert.Equal(length - 1, idx); + var values = new int[] { 200, 200, 200, 200, 200, 200, 200, 200, 200 }; + + Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } } @@ -448,10 +456,10 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_ManyByte() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 98; - var span = new ReadOnlySpan(a, 1, length - 1); - var values = new ReadOnlySpan(new int[] { 99, 98, 99, 98, 99, 98 }); - int index = span.LastIndexOfAny(values); - Assert.Equal(-1, index); + var values = new int[] { 99, 98, 99, 98, 99, 98 }; + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(values, comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -459,19 +467,18 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_ManyByte() var a = new int[length + 2]; a[0] = 99; a[length + 1] = 99; - var span = new ReadOnlySpan(a, 1, length - 1); - var values = new ReadOnlySpan(new int[] { 99, 99, 99, 99, 99, 99 }); - int index = span.LastIndexOfAny(values); - Assert.Equal(-1, index); + var values = new int[] { 99, 99, 99, 99, 99, 99 }; + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(values, comparer))); } } [Fact] public static void ZeroLengthLastIndexOfAny_String_TwoByte() { - var sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.LastIndexOfAny("0", "0"); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny("0", "0")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny("0", "0", comparer))); } [Fact] @@ -482,9 +489,7 @@ public static void DefaultFilledLastIndexOfAny_String_TwoByte() for (int length = 0; length < byte.MaxValue; length++) { var a = new string[length]; - var tempSpan = new Span(a); - tempSpan.Fill(""); - ReadOnlySpan span = tempSpan; + Array.Fill(a, ""); string[] targets = { "", "99" }; @@ -493,8 +498,10 @@ public static void DefaultFilledLastIndexOfAny_String_TwoByte() int index = rnd.Next(0, 2) == 0 ? 0 : 1; string target0 = targets[index]; string target1 = targets[(index + 1) % 2]; - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(span.Length - 1, idx); + + Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, GetFalseEqualityComparer())); } } } @@ -509,30 +516,35 @@ public static void TestMatchLastIndexOfAny_String_TwoByte() { a[i] = (i + 1).ToString(); } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { string target0 = a[targetIndex]; string target1 = "0"; - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 1; targetIndex++) { string target0 = a[targetIndex]; string target1 = a[targetIndex + 1]; - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(targetIndex + 1, idx); + + Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 1; targetIndex++) { string target0 = "0"; string target1 = a[targetIndex + 1]; - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(targetIndex + 1, idx); + + Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, GetFalseEqualityComparer())); } } } @@ -546,10 +558,9 @@ public static void TestNoMatchLastIndexOfAny_String_TwoByte() var a = new string[length]; string target0 = rnd.Next(1, 256).ToString(); string target1 = rnd.Next(1, 256).ToString(); - var span = new ReadOnlySpan(a); - int idx = span.LastIndexOfAny(target0, target1); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, comparer))); } } @@ -569,9 +580,9 @@ public static void TestMultipleMatchLastIndexOfAny_String_TwoByte() a[length - 2] = "200"; a[length - 3] = "200"; - var span = new ReadOnlySpan(a); - int idx = span.LastIndexOfAny("200", "200"); - Assert.Equal(length - 1, idx); + Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny("200", "200")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny("200", "200", comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny("200", "200", GetFalseEqualityComparer())); } } @@ -583,9 +594,9 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_String_TwoByte() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "98"; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.LastIndexOfAny("99", "98"); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny("99", "98")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny("99", "98", comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -593,18 +604,17 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_String_TwoByte() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "99"; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.LastIndexOfAny("99", "99"); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny("99", "99")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny("99", "99", comparer))); } } [Fact] public static void ZeroLengthIndexOf_String_ThreeByte() { - var sp = new ReadOnlySpan(Array.Empty()); - int idx = sp.LastIndexOfAny("0", "0", "0"); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny("0", "0", "0")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny("0", "0", "0", comparer))); } [Fact] @@ -615,9 +625,7 @@ public static void DefaultFilledLastIndexOfAny_String_ThreeByte() for (int length = 0; length < byte.MaxValue; length++) { var a = new string[length]; - var tempSpan = new Span(a); - tempSpan.Fill(""); - ReadOnlySpan span = tempSpan; + Array.Fill(a, ""); string[] targets = { "", "99", "98" }; @@ -627,8 +635,10 @@ public static void DefaultFilledLastIndexOfAny_String_ThreeByte() string target0 = targets[index]; string target1 = targets[(index + 1) % 2]; string target2 = targets[(index + 1) % 3]; - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(span.Length - 1, idx); + + Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } } } @@ -643,15 +653,16 @@ public static void TestMatchLastIndexOfAny_String_ThreeByte() { a[i] = (i + 1).ToString(); } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { string target0 = a[targetIndex]; string target1 = "0"; string target2 = "0"; - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex, idx); + + Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 2; targetIndex++) @@ -659,8 +670,10 @@ public static void TestMatchLastIndexOfAny_String_ThreeByte() string target0 = a[targetIndex]; string target1 = a[targetIndex + 1]; string target2 = a[targetIndex + 2]; - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex + 2, idx); + + Assert.Equal(targetIndex + 2, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 2, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 2; targetIndex++) @@ -668,8 +681,10 @@ public static void TestMatchLastIndexOfAny_String_ThreeByte() string target0 = "0"; string target1 = "0"; string target2 = a[targetIndex + 2]; - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(targetIndex + 2, idx); + + Assert.Equal(targetIndex + 2, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 2, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, GetFalseEqualityComparer())); } } } @@ -684,10 +699,9 @@ public static void TestNoMatchLastIndexOfAny_String_ThreeByte() string target0 = rnd.Next(1, 256).ToString(); string target1 = rnd.Next(1, 256).ToString(); string target2 = rnd.Next(1, 256).ToString(); - var span = new ReadOnlySpan(a); - int idx = span.LastIndexOfAny(target0, target1, target2); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(target0, target1, target2, comparer))); } } @@ -708,9 +722,9 @@ public static void TestMultipleMatchLastIndexOfAny_String_ThreeByte() a[length - 3] = "200"; a[length - 4] = "200"; - var span = new ReadOnlySpan(a); - int idx = span.LastIndexOfAny("200", "200", "200"); - Assert.Equal(length - 1, idx); + Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny("200", "200", "200")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny("200", "200", "200", comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny("200", "200", "200", GetFalseEqualityComparer())); } } @@ -722,9 +736,9 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_String_ThreeByte() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "98"; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.LastIndexOfAny("99", "98", "99"); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny("99", "98", "99")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny("99", "98", "99", comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -732,23 +746,22 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_String_ThreeByte() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "99"; - var span = new ReadOnlySpan(a, 1, length - 1); - int index = span.LastIndexOfAny("99", "99", "99"); - Assert.Equal(-1, index); + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny("99", "99", "99")); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny("99", "99", "99", comparer))); } } [Fact] public static void ZeroLengthLastIndexOfAny_String_ManyByte() { - var sp = new ReadOnlySpan(Array.Empty()); - var values = new ReadOnlySpan(new string[] { "0", "0", "0", "0" }); - int idx = sp.LastIndexOfAny(values); - Assert.Equal(-1, idx); + var values = new string[] { "0", "0", "0", "0" }; + + Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(Array.Empty()).LastIndexOfAny(values, comparer))); - values = new ReadOnlySpan(new string[] { }); - idx = sp.LastIndexOfAny(values); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(new string[] { }).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(new string[] { }).LastIndexOfAny(values, comparer))); } [Fact] @@ -757,16 +770,15 @@ public static void DefaultFilledLastIndexOfAny_String_ManyByte() for (int length = 0; length < byte.MaxValue; length++) { var a = new string[length]; - var tempSpan = new Span(a); - tempSpan.Fill(""); - ReadOnlySpan span = tempSpan; + Array.Fill(a, ""); - var values = new ReadOnlySpan(new string[] { "", "99", "98", "0" }); + var values = new string[] { "", "99", "98", "0" }; for (int i = 0; i < length; i++) { - int idx = span.LastIndexOfAny(values); - Assert.Equal(span.Length - 1, idx); + Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(a.Length - 1, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } } } @@ -781,27 +793,32 @@ public static void TestMatchLastIndexOfAny_String_ManyByte() { a[i] = (i + 1).ToString(); } - var span = new ReadOnlySpan(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { - var values = new ReadOnlySpan(new string[] { a[targetIndex], "0", "0", "0" }); - int idx = span.LastIndexOfAny(values); - Assert.Equal(targetIndex, idx); + var values = new string[] { a[targetIndex], "0", "0", "0" }; + + Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 3; targetIndex++) { - var values = new ReadOnlySpan(new string[] { a[targetIndex], a[targetIndex + 1], a[targetIndex + 2], a[targetIndex + 3] }); - int idx = span.LastIndexOfAny(values); - Assert.Equal(targetIndex + 3, idx); + var values = new string[] { a[targetIndex], a[targetIndex + 1], a[targetIndex + 2], a[targetIndex + 3] }; + + Assert.Equal(targetIndex + 3, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 3, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } for (int targetIndex = 0; targetIndex < length - 3; targetIndex++) { - var values = new ReadOnlySpan(new string[] { "0", "0", "0", a[targetIndex + 3] }); - int idx = span.LastIndexOfAny(values); - Assert.Equal(targetIndex + 3, idx); + var values = new string[] { "0", "0", "0", a[targetIndex + 3] }; + + Assert.Equal(targetIndex + 3, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(targetIndex + 3, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } } } @@ -823,7 +840,6 @@ public static void TestMatchValuesLargerLastIndexOfAny_String_ManyByte() } a[i] = "255"; } - var span = new ReadOnlySpan(a); var targets = new string[length * 2]; for (int i = 0; i < targets.Length; i++) @@ -836,9 +852,9 @@ public static void TestMatchValuesLargerLastIndexOfAny_String_ManyByte() targets[i] = rnd.Next(1, 255).ToString(); } - var values = new ReadOnlySpan(targets); - int idx = span.LastIndexOfAny(values); - Assert.Equal(expectedIndex, idx); + Assert.Equal(expectedIndex, new ReadOnlySpan(a).LastIndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expectedIndex, new ReadOnlySpan(a).LastIndexOfAny(targets, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets, GetFalseEqualityComparer())); } } @@ -854,11 +870,9 @@ public static void TestNoMatchLastIndexOfAny_String_ManyByte() { targets[i] = rnd.Next(1, 256).ToString(); } - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(targets); - int idx = span.LastIndexOfAny(values); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets, comparer))); } } @@ -874,11 +888,9 @@ public static void TestNoMatchValuesLargerLastIndexOfAny_String_ManyByte() { targets[i] = rnd.Next(1, 256).ToString(); } - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(targets); - int idx = span.LastIndexOfAny(values); - Assert.Equal(-1, idx); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(targets, comparer))); } } @@ -900,10 +912,11 @@ public static void TestMultipleMatchLastIndexOfAny_String_ManyByte() a[length - 4] = "200"; a[length - 5] = "200"; - var span = new ReadOnlySpan(a); - var values = new ReadOnlySpan(new string[] { "200", "200", "200", "200", "200", "200", "200", "200", "200" }); - int idx = span.LastIndexOfAny(values); - Assert.Equal(length - 1, idx); + var values = new string[] { "200", "200", "200", "200", "200", "200", "200", "200", "200" }; + + Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(length - 1, new ReadOnlySpan(a).LastIndexOfAny(values, comparer))); + Assert.Equal(-1, new ReadOnlySpan(a).LastIndexOfAny(values, GetFalseEqualityComparer())); } } @@ -915,10 +928,11 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_String_ManyByte() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "98"; - var span = new ReadOnlySpan(a, 1, length - 1); - var values = new ReadOnlySpan(new string[] { "99", "98", "99", "98", "99", "98" }); - int index = span.LastIndexOfAny(values); - Assert.Equal(-1, index); + + var values = new string[] { "99", "98", "99", "98", "99", "98" }; + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(values, comparer))); } for (int length = 1; length < byte.MaxValue; length++) @@ -926,10 +940,11 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_String_ManyByte() var a = new string[length + 2]; a[0] = "99"; a[length + 1] = "99"; - var span = new ReadOnlySpan(a, 1, length - 1); - var values = new ReadOnlySpan(new string[] { "99", "99", "99", "99", "99", "99" }); - int index = span.LastIndexOfAny(values); - Assert.Equal(-1, index); + + var values = new string[] { "99", "99", "99", "99", "99", "99" }; + + Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(values)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(a, 1, length - 1).LastIndexOfAny(values, comparer))); } } @@ -937,20 +952,27 @@ public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_String_ManyByte() [MemberData(nameof(TestHelpers.LastIndexOfAnyNullSequenceData), MemberType = typeof(TestHelpers))] public static void LastIndexOfAnyNullSequence_String(string[] spanInput, string[] searchInput, int expected) { - ReadOnlySpan theStrings = spanInput; - Assert.Equal(expected, theStrings.LastIndexOfAny(searchInput)); - Assert.Equal(expected, theStrings.LastIndexOfAny((ReadOnlySpan)searchInput)); + Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOfAny(searchInput)); + Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOfAny((ReadOnlySpan)searchInput)); + + Assert.All(GetDefaultEqualityComparers(), comparer => + { + Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOfAny(searchInput, comparer)); + Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOfAny((ReadOnlySpan)searchInput, comparer)); + }); if (searchInput != null) { if (searchInput.Length >= 3) { - Assert.Equal(expected, theStrings.LastIndexOfAny(searchInput[0], searchInput[1], searchInput[2])); + Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOfAny(searchInput[0], searchInput[1], searchInput[2])); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOfAny(searchInput[0], searchInput[1], searchInput[2], comparer))); } if (searchInput.Length >= 2) { - Assert.Equal(expected, theStrings.LastIndexOfAny(searchInput[0], searchInput[1])); + Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOfAny(searchInput[0], searchInput[1])); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(spanInput).LastIndexOfAny(searchInput[0], searchInput[1], comparer))); } } } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.T.cs index 1e5938ddc41503..73d0ae27cb394b 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/LastIndexOfSequence.T.cs @@ -10,237 +10,274 @@ public static partial class ReadOnlySpanTests [Fact] public static void LastIndexOfSequenceMatchAtStart() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 5, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 5, 1, 77 }); - int index = span.LastIndexOf(value); - Assert.Equal(0, index); + var source = new int[] { 5, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }; + var value = new int[] { 5, 1, 77 }; + + Assert.Equal(0, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceMultipleMatch() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 1, 2, 3, 1, 2, 3, 1, 2, 3, 1 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 2, 3 }); - int index = span.LastIndexOf(value); - Assert.Equal(7, index); + var source = new int[] { 1, 2, 3, 1, 2, 3, 1, 2, 3, 1 }; + var value = new int[] { 2, 3 }; + + Assert.Equal(7, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(7, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceRestart() { - ReadOnlySpan span = new ReadOnlySpan(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 value = new ReadOnlySpan(new int[] { 77, 77, 88 }); - int index = span.LastIndexOf(value); - Assert.Equal(10, index); + var source = new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 8, 9, 77, 0, 1 }; + var value = new int[] { 77, 77, 88 }; + + Assert.Equal(10, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(10, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceNoMatch() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 77, 77, 88, 99 }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }; + var value = new int[] { 77, 77, 88, 99 }; + + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceNotEvenAHeadMatch() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 100, 77, 88, 99 }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }; + var value = new int[] { 100, 77, 88, 99 }; + + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceMatchAtVeryEnd() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 3, 4, 5 }); - int index = span.LastIndexOf(value); - Assert.Equal(3, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 3, 4, 5 }; + + Assert.Equal(3, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(3, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceJustPastVeryEnd() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }, 0, 5); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 3, 4, 5 }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 3, 4, 5 }; + + Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceZeroLengthValue() { - // A zero-length value is always "found" at the end of the span. - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }); - ReadOnlySpan value = new ReadOnlySpan(Array.Empty()); - int index = span.LastIndexOf(value); - Assert.Equal(span.Length, index); + // A zero-length value is always "found" at the end of the source. + var source = new int[] { 0, 1, 77, 2, 3, 77, 77, 4, 5, 77, 77, 77, 88, 6, 6, 77, 77, 88, 9 }; + var value = Array.Empty(); + + Assert.Equal(source.Length, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(source.Length, new ReadOnlySpan(source).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceZeroLengthSpan() { - ReadOnlySpan span = new ReadOnlySpan(Array.Empty()); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 1, 2, 3 }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = Array.Empty(); + var value = new int[] { 1, 2, 3 }; + + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceLengthOneValue() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 2 }); - int index = span.LastIndexOf(value); - Assert.Equal(2, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 2 }; + + Assert.Equal(2, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(2, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceLengthOneValueAtVeryEnd() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 5 }); - int index = span.LastIndexOf(value); - Assert.Equal(5, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 5 }; + + Assert.Equal(5, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(5, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceLengthOneValueMultipleTimes() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 5, 3, 4, 5 }); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 5 }); - int index = span.LastIndexOf(value); - Assert.Equal(5, index); + var source = new int[] { 0, 1, 5, 3, 4, 5 }; + var value = new int[] { 5 }; + + Assert.Equal(5, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(5, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd() { - ReadOnlySpan span = new ReadOnlySpan(new int[] { 0, 1, 2, 3, 4, 5 }, 0, 5); - ReadOnlySpan value = new ReadOnlySpan(new int[] { 5 }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = new int[] { 0, 1, 2, 3, 4, 5 }; + var value = new int[] { 5 }; + + Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceMatchAtStart_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "5", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "5", "1", "77" }); - int index = span.LastIndexOf(value); - Assert.Equal(0, index); + var source = new string[] { "5", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }; + var value = new string[] { "5", "1", "77" }; + + Assert.Equal(0, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceMultipleMatch_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "1", "2", "3", "1", "2", "3", "1", "2", "3" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "2", "3" }); - int index = span.LastIndexOf(value); - Assert.Equal(7, index); + var source = new string[] { "1", "2", "3", "1", "2", "3", "1", "2", "3" }; + var value = new string[] { "2", "3" }; + + Assert.Equal(7, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(7, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceRestart_String() { - ReadOnlySpan span = new ReadOnlySpan(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 value = new ReadOnlySpan(new string[] { "77", "77", "88" }); - int index = span.LastIndexOf(value); - Assert.Equal(10, index); + var source = new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "8", "9", "77", "0", "1" }; + var value = new string[] { "77", "77", "88" }; + + Assert.Equal(10, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(10, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceNoMatch_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "77", "77", "88", "99" }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }; + var value = new string[] { "77", "77", "88", "99" }; + + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceNotEvenAHeadMatch_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "100", "77", "88", "99" }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }; + var value = new string[] { "100", "77", "88", "99" }; + + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceMatchAtVeryEnd_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "3", "4", "5" }); - int index = span.LastIndexOf(value); - Assert.Equal(3, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "3", "4", "5" }; + + Assert.Equal(3, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(3, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceJustPastVeryEnd_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "3", "4", "5" }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "3", "4", "5" }; + + Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceZeroLengthValue_String() { - // A zero-length value is always "found" at the end of the span. - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }); - ReadOnlySpan value = new ReadOnlySpan(Array.Empty()); - int index = span.LastIndexOf(value); - Assert.Equal(span.Length, index); + // A zero-length value is always "found" at the end of the source. + var source = new string[] { "0", "1", "77", "2", "3", "77", "77", "4", "5", "77", "77", "77", "88", "6", "6", "77", "77", "88", "9" }; + var value = Array.Empty(); + + Assert.Equal(source.Length, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(source.Length, new ReadOnlySpan(source).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceZeroLengthSpan_String() { - ReadOnlySpan span = new ReadOnlySpan(Array.Empty()); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "1", "2", "3" }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = Array.Empty(); + var value = new string[] { "1", "2", "3" }; + + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, comparer))); } [Fact] public static void LastIndexOfSequenceLengthOneValue_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "2" }); - int index = span.LastIndexOf(value); - Assert.Equal(2, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "2" }; + + Assert.Equal(2, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(2, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceLengthOneValueAtVeryEnd_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "5" }); - int index = span.LastIndexOf(value); - Assert.Equal(5, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "5" }; + + Assert.Equal(5, new ReadOnlySpan(source).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(5, new ReadOnlySpan(source).LastIndexOf(value, comparer))); + Assert.Equal(-1, new ReadOnlySpan(source).LastIndexOf(value, GetFalseEqualityComparer())); } [Fact] public static void LastIndexOfSequenceLengthOneValueJustPasttVeryEnd_String() { - ReadOnlySpan span = new ReadOnlySpan(new string[] { "0", "1", "2", "3", "4", "5" }, 0, 5); - ReadOnlySpan value = new ReadOnlySpan(new string[] { "5" }); - int index = span.LastIndexOf(value); - Assert.Equal(-1, index); + var source = new string[] { "0", "1", "2", "3", "4", "5" }; + var value = new string[] { "5" }; + + Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).LastIndexOf(value)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(-1, new ReadOnlySpan(source, 0, 5).LastIndexOf(value, comparer))); } [Theory] [MemberData(nameof(TestHelpers.LastIndexOfNullSequenceData), MemberType = typeof(TestHelpers))] - public static void LastIndexOfNullSequence_String(string[] spanInput, string[] searchInput, int expected) + public static void LastIndexOfNullSequence_String(string[] source, string[] target, int expected) { - ReadOnlySpan theStrings = spanInput; - Assert.Equal(expected, theStrings.LastIndexOf(searchInput)); - Assert.Equal(expected, theStrings.LastIndexOf((ReadOnlySpan)searchInput)); + Assert.Equal(expected, new ReadOnlySpan(source).LastIndexOf(target)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.Equal(expected, new ReadOnlySpan(source).LastIndexOf(target, comparer))); } } } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.T.cs index c6f37293b656dc..ec4a4691aa714b 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.T.cs @@ -136,28 +136,26 @@ public static void ZeroLengthSequenceCompareTo_String() { var a = new string[3]; - var first = new ReadOnlySpan(a, 1, 0); - var second = new ReadOnlySpan(a, 2, 0); - int result = first.SequenceCompareTo(second); - Assert.Equal(0, result); + Assert.Equal(0, new ReadOnlySpan(a, 1, 0).SequenceCompareTo(new ReadOnlySpan(a, 2, 0))); + Assert.All(GetDefaultComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a, 1, 0).SequenceCompareTo(new ReadOnlySpan(a, 2, 0), comparer))); } [Fact] public static void SameSpanSequenceCompareTo_String() { string[] a = { "fourth", "fifth", "sixth" }; - var span = new ReadOnlySpan(a); - int result = span.SequenceCompareTo(span); - Assert.Equal(0, result); + + Assert.Equal(0, new ReadOnlySpan(a).SequenceCompareTo(a)); + Assert.All(GetDefaultComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a).SequenceCompareTo(a, comparer))); } [Fact] public static void SequenceCompareToArrayImplicit_String() { string[] a = { "fourth", "fifth", "sixth" }; - var first = new ReadOnlySpan(a, 0, 3); - int result = first.SequenceCompareTo(a); - Assert.Equal(0, result); + + Assert.Equal(0, new ReadOnlySpan(a, 0, 3).SequenceCompareTo(a)); + Assert.All(GetDefaultComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(a, 0, 3).SequenceCompareTo(a, comparer))); } [Fact] @@ -167,31 +165,29 @@ public static void SequenceCompareToArraySegmentImplicit_String() string[] dst = { "fifth", "first", "second", "third", "tenth" }; var segment = new ArraySegment(dst, 1, 3); - var first = new ReadOnlySpan(src, 0, 3); - int result = first.SequenceCompareTo(segment); - Assert.Equal(0, result); + Assert.Equal(0, new ReadOnlySpan(src, 0, 3).SequenceCompareTo(segment)); + Assert.All(GetDefaultComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(src, 0, 3).SequenceCompareTo(segment, comparer))); } [Fact] public static void LengthMismatchSequenceCompareTo_String() { string[] a = { "fourth", "fifth", "sixth" }; - var first = new ReadOnlySpan(a, 0, 2); - var second = new ReadOnlySpan(a, 0, 3); - int result = first.SequenceCompareTo(second); - Assert.True(result < 0); - result = second.SequenceCompareTo(first); - Assert.True(result > 0); + Assert.True(new ReadOnlySpan(a, 0, 2).SequenceCompareTo(new ReadOnlySpan(a, 0, 3)) < 0); + Assert.True(new ReadOnlySpan(a, 0, 3).SequenceCompareTo(new ReadOnlySpan(a, 0, 2)) > 0); - // one sequence is empty - first = new Span(a, 1, 0); + Assert.True(new Span(a, 1, 0).SequenceCompareTo(new ReadOnlySpan(a, 0, 3)) < 0); + Assert.True(new ReadOnlySpan(a, 0, 3).SequenceCompareTo(new Span(a, 1, 0)) > 0); - result = first.SequenceCompareTo(second); - Assert.True(result < 0); + Assert.All(GetDefaultComparers(), comparer => + { + Assert.True(new ReadOnlySpan(a, 0, 2).SequenceCompareTo(new ReadOnlySpan(a, 0, 3), comparer) < 0); + Assert.True(new ReadOnlySpan(a, 0, 3).SequenceCompareTo(new ReadOnlySpan(a, 0, 2), comparer) > 0); - result = second.SequenceCompareTo(first); - Assert.True(result > 0); + Assert.True(new Span(a, 1, 0).SequenceCompareTo(new ReadOnlySpan(a, 0, 3), comparer) < 0); + Assert.True(new ReadOnlySpan(a, 0, 3).SequenceCompareTo(new Span(a, 1, 0), comparer) > 0); + }); } [Fact] @@ -210,13 +206,14 @@ public static void SequenceCompareToWithSingleMismatch_String() second[mismatchIndex] = (string)(second[mismatchIndex] + 1); - var firstSpan = new ReadOnlySpan(first); - var secondSpan = new ReadOnlySpan(second); - int result = firstSpan.SequenceCompareTo(secondSpan); - Assert.True(result < 0); + Assert.True(new ReadOnlySpan(first).SequenceCompareTo(second) < 0); + Assert.True(new ReadOnlySpan(second).SequenceCompareTo(first) > 0); - result = secondSpan.SequenceCompareTo(firstSpan); - Assert.True(result > 0); + Assert.All(GetDefaultComparers(), comparer => + { + Assert.True(new ReadOnlySpan(first).SequenceCompareTo(second, comparer) < 0); + Assert.True(new ReadOnlySpan(second).SequenceCompareTo(first, comparer) > 0); + }); } } } @@ -235,13 +232,14 @@ public static void SequenceCompareToNoMatch_string() second[i] = $"item {int.MaxValue - i}"; } - var firstSpan = new ReadOnlySpan(first); - var secondSpan = new ReadOnlySpan(second); - int result = firstSpan.SequenceCompareTo(secondSpan); - Assert.True(result < 0); + Assert.True(new ReadOnlySpan(first).SequenceCompareTo(new ReadOnlySpan(second)) < 0); + Assert.True(new ReadOnlySpan(second).SequenceCompareTo(new ReadOnlySpan(first)) > 0); - result = secondSpan.SequenceCompareTo(firstSpan); - Assert.True(result > 0); + Assert.All(GetDefaultComparers(), comparer => + { + Assert.True(new ReadOnlySpan(first).SequenceCompareTo(new ReadOnlySpan(second), comparer) < 0); + Assert.True(new ReadOnlySpan(second).SequenceCompareTo(new ReadOnlySpan(first), comparer) > 0); + }); } } @@ -262,10 +260,8 @@ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_string() second[k] = string.Empty; second[length + 1] = "100"; - var span1 = new ReadOnlySpan(first, 1, length); - var span2 = new ReadOnlySpan(second, 1, length); - int result = span1.SequenceCompareTo(span2); - Assert.Equal(0, result); + Assert.Equal(0, new ReadOnlySpan(first, 1, length).SequenceCompareTo(new ReadOnlySpan(second, 1, length))); + Assert.All(GetDefaultComparers(), comparer => Assert.Equal(0, new ReadOnlySpan(first, 1, length).SequenceCompareTo(new ReadOnlySpan(second, 1, length), comparer))); } } } diff --git a/src/libraries/System.Memory/tests/ReadOnlySpan/StartsWith.T.cs b/src/libraries/System.Memory/tests/ReadOnlySpan/StartsWith.T.cs index dea9f22e9c7eb8..de06c16f1ee247 100644 --- a/src/libraries/System.Memory/tests/ReadOnlySpan/StartsWith.T.cs +++ b/src/libraries/System.Memory/tests/ReadOnlySpan/StartsWith.T.cs @@ -12,39 +12,37 @@ public static void ZeroLengthStartsWith() { int[] a = new int[3]; - ReadOnlySpan first = new ReadOnlySpan(a, 1, 0); - ReadOnlySpan second = new ReadOnlySpan(a, 2, 0); - bool b = first.StartsWith(second); - Assert.True(b); + Assert.True(new ReadOnlySpan(a, 1, 0).StartsWith(new ReadOnlySpan(a, 2, 0))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a, 1, 0).StartsWith(new ReadOnlySpan(a, 2, 0), comparer))); + Assert.True(new ReadOnlySpan(a, 1, 0).StartsWith(new ReadOnlySpan(a, 2, 0), GetFalseEqualityComparer())); } [Fact] public static void SameSpanStartsWith() { int[] a = { 4, 5, 6 }; - ReadOnlySpan span = new ReadOnlySpan(a); - bool b = span.StartsWith(span); - Assert.True(b); + Assert.True(new ReadOnlySpan(a).StartsWith(a)); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a).StartsWith(a, comparer))); + Assert.False(new ReadOnlySpan(a).StartsWith(a, GetFalseEqualityComparer())); } [Fact] public static void LengthMismatchStartsWith() { int[] a = { 4, 5, 6 }; - ReadOnlySpan first = new ReadOnlySpan(a, 0, 2); - ReadOnlySpan second = new ReadOnlySpan(a, 0, 3); - bool b = first.StartsWith(second); - Assert.False(b); + + Assert.False(new ReadOnlySpan(a, 0, 2).StartsWith(new ReadOnlySpan(a, 0, 3))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.False(new ReadOnlySpan(a, 0, 2).StartsWith(new ReadOnlySpan(a, 0, 3), comparer))); } [Fact] public static void StartsWithMatch() { int[] a = { 4, 5, 6 }; - ReadOnlySpan span = new ReadOnlySpan(a, 0, 3); - ReadOnlySpan slice = new ReadOnlySpan(a, 0, 2); - bool b = span.StartsWith(slice); - Assert.True(b); + + Assert.True(new ReadOnlySpan(a, 0, 3).StartsWith(new ReadOnlySpan(a, 0, 2))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a, 0, 3).StartsWith(new ReadOnlySpan(a, 0, 2), comparer))); + Assert.False(new ReadOnlySpan(a, 0, 3).StartsWith(new ReadOnlySpan(a, 0, 2), GetFalseEqualityComparer())); } [Fact] @@ -52,10 +50,10 @@ public static void StartsWithMatchDifferentSpans() { int[] a = { 4, 5, 6 }; int[] b = { 4, 5, 6 }; - ReadOnlySpan span = new ReadOnlySpan(a, 0, 3); - ReadOnlySpan slice = new ReadOnlySpan(b, 0, 3); - bool c = span.StartsWith(slice); - Assert.True(c); + + Assert.True(new ReadOnlySpan(a, 0, 3).StartsWith(new ReadOnlySpan(b, 0, 3))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(a, 0, 3).StartsWith(new ReadOnlySpan(b, 0, 3), comparer))); + Assert.False(new ReadOnlySpan(a, 0, 3).StartsWith(new ReadOnlySpan(b, 0, 3), GetFalseEqualityComparer())); } [Fact] @@ -144,10 +142,8 @@ public static void MakeSureNoStartsWithChecksGoOutOfRange() first[GuardLength + i] = second[GuardLength + i] = new TInt(10 * (i + 1), checkForOutOfRangeAccess); } - ReadOnlySpan firstSpan = new ReadOnlySpan(first, GuardLength, length); - ReadOnlySpan secondSpan = new ReadOnlySpan(second, GuardLength, length); - bool b = firstSpan.StartsWith(secondSpan); - Assert.True(b); + Assert.True(new ReadOnlySpan(first, GuardLength, length).StartsWith(new ReadOnlySpan(second, GuardLength, length))); + Assert.All(GetDefaultEqualityComparers(), comparer => Assert.True(new ReadOnlySpan(first, GuardLength, length).StartsWith(new ReadOnlySpan(second, GuardLength, length), comparer))); } } } diff --git a/src/libraries/System.Memory/tests/System.Memory.Tests.csproj b/src/libraries/System.Memory/tests/System.Memory.Tests.csproj index 38b40b284d1b25..63c2d9088f7153 100644 --- a/src/libraries/System.Memory/tests/System.Memory.Tests.csproj +++ b/src/libraries/System.Memory/tests/System.Memory.Tests.csproj @@ -27,6 +27,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs index 174fac083981be..86b27c206f8584 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs @@ -361,6 +361,17 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.Contains(ref MemoryMarshal.GetReference(span), value, span.Length); } + /// + /// Searches for the specified value and returns true if found. If not found, returns false. + /// + /// + /// The span to search. + /// The value to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Contains(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null) => + IndexOf(span, value, comparer) >= 0; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [OverloadResolutionPriority(-1)] @@ -443,6 +454,17 @@ public static bool ContainsAnyExceptInRange(this Span span, T lowInclusive public static bool ContainsAny(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? => IndexOfAny(span, value0, value1) >= 0; + /// + /// Searches for any occurrence of the specified or , and returns true if found. If not found, returns false. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsAny(this ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer = null) => + IndexOfAny(span, value0, value1, comparer) >= 0; + /// /// Searches for any occurrence of the specified , , or , and returns true if found. If not found, returns false. /// @@ -454,6 +476,18 @@ public static bool ContainsAny(this ReadOnlySpan span, T value0, T value1) public static bool ContainsAny(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? => IndexOfAny(span, value0, value1, value2) >= 0; + /// + /// Searches for any occurrence of the specified , , or , and returns true if found. If not found, returns false. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// One of the values to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsAny(this ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer = null) => + IndexOfAny(span, value0, value1, value2, comparer) >= 0; + /// /// Searches for any occurrence of any of the specified and returns true if found. If not found, returns false. /// @@ -463,6 +497,16 @@ public static bool ContainsAny(this ReadOnlySpan span, T value0, T value1, public static bool ContainsAny(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? => IndexOfAny(span, values) >= 0; + /// + /// Searches for any occurrence of any of the specified and returns true if found. If not found, returns false. + /// + /// The span to search. + /// The set of values to search for. + /// The comparer to use. If , is used. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsAny(this ReadOnlySpan span, ReadOnlySpan values, IEqualityComparer? comparer = null) => + IndexOfAny(span, values, comparer) >= 0; + /// /// Searches for any occurrence of any of the specified and returns true if found. If not found, returns false. /// @@ -501,6 +545,20 @@ public static bool ContainsAny(this ReadOnlySpan span, SearchValues(this ReadOnlySpan span, T value) where T : IEquatable? => IndexOfAnyExcept(span, value) >= 0; + /// + /// Searches for any value other than the specified . + /// + /// The span to search. + /// A value to avoid. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// True if any value other than is present in the span. + /// If all of the values are , returns false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsAnyExcept(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null) => + IndexOfAnyExcept(span, value, comparer) >= 0; + /// /// Searches for any value other than the specified or . /// @@ -515,6 +573,21 @@ public static bool ContainsAnyExcept(this ReadOnlySpan span, T value) wher public static bool ContainsAnyExcept(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? => IndexOfAnyExcept(span, value0, value1) >= 0; + /// + /// Searches for any value other than the specified or . + /// + /// The span to search. + /// A value to avoid. + /// A value to avoid. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// True if any value other than and is present in the span. + /// If all of the values are or , returns false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsAnyExcept(this ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer = null) => + IndexOfAnyExcept(span, value0, value1, comparer) >= 0; + /// /// Searches for any value other than the specified , , or . /// @@ -530,6 +603,22 @@ public static bool ContainsAnyExcept(this ReadOnlySpan span, T value0, T v public static bool ContainsAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? => IndexOfAnyExcept(span, value0, value1, value2) >= 0; + /// + /// Searches for any value other than the specified , , or . + /// + /// The span to search. + /// A value to avoid. + /// A value to avoid. + /// A value to avoid. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// True if any value other than , , and is present in the span. + /// If all of the values are , , or , returns false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer = null) => + IndexOfAnyExcept(span, value0, value1, value2, comparer) >= 0; + /// /// Searches for any value other than the specified . /// @@ -543,6 +632,20 @@ public static bool ContainsAnyExcept(this ReadOnlySpan span, T value0, T v public static bool ContainsAnyExcept(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? => IndexOfAnyExcept(span, values) >= 0; + /// + /// Searches for any value other than the specified . + /// + /// The span to search. + /// The values to avoid. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// True if any value other than those in is present in the span. + /// If all of the values are in , returns false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsAnyExcept(this ReadOnlySpan span, ReadOnlySpan values, IEqualityComparer? comparer = null) => + IndexOfAnyExcept(span, values, comparer) >= 0; + /// /// Searches for any value other than the specified . /// @@ -737,6 +840,86 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.IndexOfAnyExcept(ref MemoryMarshal.GetReference(span), value, span.Length); } + /// Searches for the first index of any value other than the specified . + /// The type of the span and values. + /// The span to search. + /// A value to avoid. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// The index in the span of the first occurrence of any value other than . + /// If all of the values are , returns -1. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.IndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.IndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(int)) + { + return SpanHelpers.IndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(long)) + { + return SpanHelpers.IndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + } + + return IndexOfAnyExceptDefaultComparer(span, value); + static int IndexOfAnyExceptDefaultComparer(ReadOnlySpan span, T value) + { + for (int i = 0; i < span.Length; i++) + { + if (!EqualityComparer.Default.Equals(span[i], value)) + { + return i; + } + } + + return -1; + } + } + else + { + return IndexOfAnyExceptComparer(span, value, comparer); + static int IndexOfAnyExceptComparer(ReadOnlySpan span, T value, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + + for (int i = 0; i < span.Length; i++) + { + if (!comparer.Equals(span[i], value)) + { + return i; + } + } + + return -1; + } + } + } + /// Searches for the first index of any value other than the specified or . /// The type of the span and values. /// The span to search. @@ -772,6 +955,77 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.IndexOfAnyExcept(ref MemoryMarshal.GetReference(span), value0, value1, span.Length); } + /// Searches for the first index of any value other than the specified or . + /// The type of the span and values. + /// The span to search. + /// A value to avoid. + /// A value to avoid + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// The index in the span of the first occurrence of any value other than and . + /// If all of the values are or , returns -1. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.IndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.IndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + span.Length); + } + } + + return IndexOfAnyExceptDefaultComparer(span, value0, value1); + static int IndexOfAnyExceptDefaultComparer(ReadOnlySpan span, T value0, T value1) + { + for (int i = 0; i < span.Length; i++) + { + if (!EqualityComparer.Default.Equals(span[i], value0) && + !EqualityComparer.Default.Equals(span[i], value1)) + { + return i; + } + } + + return -1; + } + } + else + { + return IndexOfAnyExceptComparer(span, value0, value1, comparer); + static int IndexOfAnyExceptComparer(ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + + for (int i = 0; i < span.Length; i++) + { + if (!comparer.Equals(span[i], value0) && + !comparer.Equals(span[i], value1)) + { + return i; + } + } + + return -1; + } + } + } + /// Searches for the first index of any value other than the specified , , or . /// The type of the span and values. /// The span to search. @@ -810,6 +1064,81 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.IndexOfAnyExcept(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length); } + /// Searches for the first index of any value other than the specified , , or . + /// The type of the span and values. + /// The span to search. + /// A value to avoid. + /// A value to avoid + /// A value to avoid + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// The index in the span of the first occurrence of any value other than , , and . + /// If all of the values are , , and , returns -1. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.IndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.IndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + span.Length); + } + } + + return IndexOfAnyExceptDefaultComparer(span, value0, value1, value2); + static int IndexOfAnyExceptDefaultComparer(ReadOnlySpan span, T value0, T value1, T value2) + { + for (int i = 0; i < span.Length; i++) + { + if (!EqualityComparer.Default.Equals(span[i], value0) && + !EqualityComparer.Default.Equals(span[i], value1) && + !EqualityComparer.Default.Equals(span[i], value2)) + { + return i; + } + } + + return -1; + } + } + else + { + return IndexOfAnyExceptComparer(span, value0, value1, value2, comparer); + static int IndexOfAnyExceptComparer(ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + for (int i = 0; i < span.Length; i++) + { + if (!comparer.Equals(span[i], value0) && + !comparer.Equals(span[i], value1) && + !comparer.Equals(span[i], value2)) + { + return i; + } + } + + return -1; + } + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2, T value3) where T : IEquatable? { @@ -926,28 +1255,66 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(values)), /// The type of the span and values. /// The span to search. /// The values to avoid. + /// The implementation to use when comparing elements, or to use the default for the type of an element. /// /// The index in the span of the first occurrence of any value other than those in . /// If all of the values are in , returns -1. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfAnyExcept(this ReadOnlySpan span, SearchValues values) where T : IEquatable? + public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, ReadOnlySpan values, IEqualityComparer? comparer = null) { - if (values is null) + switch (values.Length) { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); - } + case 0: + return span.IsEmpty ? -1 : 0; - return values.IndexOfAnyExcept(span); + case 1: + return IndexOfAnyExcept(span, values[0], comparer); + + case 2: + return IndexOfAnyExcept(span, values[0], values[1], comparer); + + case 3: + return IndexOfAnyExcept(span, values[0], values[1], values[2], comparer); + + default: + for (int i = 0; i < span.Length; i++) + { + if (!values.Contains(span[i], comparer)) + { + return i; + } + } + + return -1; + } } - /// Searches for the last index of any value other than the specified . + /// Searches for the first index of any value other than the specified . /// The type of the span and values. /// The span to search. - /// A value to avoid. + /// The values to avoid. /// - /// The index in the span of the last occurrence of any value other than . - /// If all of the values are , returns -1. + /// The index in the span of the first occurrence of any value other than those in . + /// If all of the values are in , returns -1. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfAnyExcept(this ReadOnlySpan span, SearchValues values) where T : IEquatable? + { + if (values is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); + } + + return values.IndexOfAnyExcept(span); + } + + /// Searches for the last index of any value other than the specified . + /// The type of the span and values. + /// The span to search. + /// A value to avoid. + /// + /// The index in the span of the last occurrence of any value other than . + /// If all of the values are , returns -1. /// [OverloadResolutionPriority(-1)] public static int LastIndexOfAnyExcept(this Span span, T value) where T : IEquatable? => @@ -1051,6 +1418,86 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.LastIndexOfAnyExcept(ref MemoryMarshal.GetReference(span), value, span.Length); } + /// Searches for the last index of any value other than the specified . + /// The type of the span and values. + /// The span to search. + /// A value to avoid. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// The index in the span of the last occurrence of any value other than . + /// If all of the values are , returns -1. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.LastIndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.LastIndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(int)) + { + return SpanHelpers.LastIndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(long)) + { + return SpanHelpers.LastIndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + } + + return LastIndexOfAnyExceptDefaultComparer(span, value); + static int LastIndexOfAnyExceptDefaultComparer(ReadOnlySpan span, T value) + { + for (int i = span.Length - 1; i >= 0; i--) + { + if (!EqualityComparer.Default.Equals(span[i], value)) + { + return i; + } + } + + return -1; + } + } + else + { + return LastIndexOfAnyExceptComparer(span, value, comparer); + static int LastIndexOfAnyExceptComparer(ReadOnlySpan span, T value, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + + for (int i = span.Length - 1; i >= 0; i--) + { + if (!comparer.Equals(span[i], value)) + { + return i; + } + } + + return -1; + } + } + } + /// Searches for the last index of any value other than the specified or . /// The type of the span and values. /// The span to search. @@ -1086,6 +1533,77 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.LastIndexOfAnyExcept(ref MemoryMarshal.GetReference(span), value0, value1, span.Length); } + /// Searches for the last index of any value other than the specified or . + /// The type of the span and values. + /// The span to search. + /// A value to avoid. + /// A value to avoid + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// The index in the span of the last occurrence of any value other than and . + /// If all of the values are or , returns -1. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.LastIndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.LastIndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + span.Length); + } + } + + return LastIndexOfAnyExceptDefaultComparer(span, value0, value1); + static int LastIndexOfAnyExceptDefaultComparer(ReadOnlySpan span, T value0, T value1) + { + for (int i = span.Length - 1; i >= 0; i--) + { + if (!EqualityComparer.Default.Equals(span[i], value0) && + !EqualityComparer.Default.Equals(span[i], value1)) + { + return i; + } + } + + return -1; + } + } + else + { + return LastIndexOfAnyExceptComparer(span, value0, value1, comparer); + static int LastIndexOfAnyExceptComparer(ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + + for (int i = span.Length - 1; i >= 0; i--) + { + if (!comparer.Equals(span[i], value0) && + !comparer.Equals(span[i], value1)) + { + return i; + } + } + + return -1; + } + } + } + /// Searches for the last index of any value other than the specified , , or . /// The type of the span and values. /// The span to search. @@ -1124,6 +1642,82 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.LastIndexOfAnyExcept(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length); } + /// Searches for the last index of any value other than the specified , , or . + /// The type of the span and values. + /// The span to search. + /// A value to avoid. + /// A value to avoid + /// A value to avoid + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// The index in the span of the last occurrence of any value other than , , and . + /// If all of the values are , , and , returns -1. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.LastIndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.LastIndexOfAnyExceptValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + span.Length); + } + } + + return LastIndexOfAnyExceptDefaultComparer(span, value0, value1, value2); + static int LastIndexOfAnyExceptDefaultComparer(ReadOnlySpan span, T value0, T value1, T value2) + { + for (int i = span.Length - 1; i >= 0; i--) + { + if (!EqualityComparer.Default.Equals(span[i], value0) && + !EqualityComparer.Default.Equals(span[i], value1) && + !EqualityComparer.Default.Equals(span[i], value2)) + { + return i; + } + } + + return -1; + } + } + else + { + return LastIndexOfAnyExceptComparer(span, value0, value1, value2, comparer); + static int LastIndexOfAnyExceptComparer(ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + + for (int i = span.Length - 1; i >= 0; i--) + { + if (!comparer.Equals(span[i], value0) && + !comparer.Equals(span[i], value1) && + !comparer.Equals(span[i], value2)) + { + return i; + } + } + + return -1; + } + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2, T value3) where T : IEquatable? { @@ -1237,6 +1831,44 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(values)), } } + /// Searches for the last index of any value other than the specified . + /// The type of the span and values. + /// The span to search. + /// The values to avoid. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// + /// The index in the span of the first occurrence of any value other than those in . + /// If all of the values are in , returns -1. + /// + public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, ReadOnlySpan values, IEqualityComparer? comparer = null) + { + switch (values.Length) + { + case 0: + return span.Length - 1; + + case 1: + return LastIndexOfAnyExcept(span, values[0], comparer); + + case 2: + return LastIndexOfAnyExcept(span, values[0], values[1], comparer); + + case 3: + return LastIndexOfAnyExcept(span, values[0], values[1], values[2], comparer); + + default: + for (int i = span.Length - 1; i >= 0; i--) + { + if (!values.Contains(span[i], comparer)) + { + return i; + } + } + + return -1; + } + } + /// Searches for the last index of any value other than the specified . /// The type of the span and values. /// The span to search. @@ -1578,6 +2210,77 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length); } + /// + /// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The value to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int IndexOf(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + return SpanHelpers.IndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + + if (sizeof(T) == sizeof(short)) + return SpanHelpers.IndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + + if (sizeof(T) == sizeof(int)) + return SpanHelpers.IndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + + if (sizeof(T) == sizeof(long)) + return SpanHelpers.IndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + + return IndexOfDefaultComparer(span, value); + static int IndexOfDefaultComparer(ReadOnlySpan span, T value) + { + for (int i = 0; i < span.Length; i++) + { + if (EqualityComparer.Default.Equals(span[i], value)) + { + return i; + } + } + + return -1; + } + } + else + { + return IndexOfComparer(span, value, comparer); + static int IndexOfComparer(ReadOnlySpan span, T value, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + for (int i = 0; i < span.Length; i++) + { + if (comparer.Equals(span[i], value)) + { + return i; + } + } + + return -1; + } + } + } + /// /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). /// @@ -1607,26 +2310,84 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(value)), } /// - /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). /// /// The span to search. - /// The value to search for. + /// The sequence to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe int LastIndexOf(this ReadOnlySpan span, T value) where T : IEquatable? + public static unsafe int IndexOf(this ReadOnlySpan span, ReadOnlySpan value, IEqualityComparer? comparer = null) { - if (RuntimeHelpers.IsBitwiseEquatable()) + if (RuntimeHelpers.IsBitwiseEquatable() && (comparer is null || comparer == EqualityComparer.Default)) { if (sizeof(T) == sizeof(byte)) - { - return SpanHelpers.LastIndexOfValueType( + return SpanHelpers.IndexOf( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.BitCast(value), - span.Length); - } - else if (sizeof(T) == sizeof(short)) - { - return SpanHelpers.LastIndexOfValueType( - ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + + if (sizeof(T) == sizeof(char)) + return SpanHelpers.IndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + } + + return IndexOfComparer(span, value, comparer); + static int IndexOfComparer(ReadOnlySpan span, ReadOnlySpan value, IEqualityComparer? comparer) + { + if (value.Length == 0) + { + return 0; + } + + comparer ??= EqualityComparer.Default; + + int total = 0; + while (!span.IsEmpty) + { + int pos = span.IndexOf(value[0], comparer); + if (pos < 0) + { + break; + } + + if (span.Slice(pos + 1).StartsWith(value.Slice(1), comparer)) + { + return total + pos; + } + + total += pos + 1; + span = span.Slice(pos + 1); + } + + return -1; + } + } + + /// + /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The value to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int LastIndexOf(this ReadOnlySpan span, T value) where T : IEquatable? + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.LastIndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.LastIndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), Unsafe.BitCast(value), span.Length); } @@ -1649,6 +2410,83 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), value, span.Length); } + /// + /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The value to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int LastIndexOf(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.LastIndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.LastIndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(int)) + { + return SpanHelpers.LastIndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(long)) + { + return SpanHelpers.LastIndexOfValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + } + + return LastIndexOfDefaultComparer(span, value); + static int LastIndexOfDefaultComparer(ReadOnlySpan span, T value) + { + for (int i = span.Length - 1; i >= 0; i--) + { + if (EqualityComparer.Default.Equals(span[i], value)) + { + return i; + } + } + + return -1; + } + } + else + { + return LastIndexOfComparer(span, value, comparer); + static int LastIndexOfComparer(ReadOnlySpan span, T value, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + + for (int i = span.Length - 1; i >= 0; i--) + { + if (comparer.Equals(span[i], value)) + { + return i; + } + } + + return -1; + } + } + } + /// /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). /// @@ -1680,6 +2518,64 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(value)), return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length); } + /// + /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The sequence to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int LastIndexOf(this ReadOnlySpan span, ReadOnlySpan value, IEqualityComparer? comparer = null) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.LastIndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + } + if (sizeof(T) == sizeof(char)) + { + return SpanHelpers.LastIndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + } + } + + return LastIndexOfComparer(span, value, comparer); + static int LastIndexOfComparer(ReadOnlySpan span, ReadOnlySpan value, IEqualityComparer? comparer) + { + if (value.Length == 0) + { + return span.Length; + } + + comparer ??= EqualityComparer.Default; + + int pos = span.Length; + while (true) + { + pos = span.Slice(0, pos).LastIndexOf(value[0], comparer); + if (pos < 0) + { + break; + } + + if (span.Slice(pos + 1).StartsWith(value.Slice(1), comparer)) + { + return pos; + } + } + + return -1; + } + } + /// /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. /// @@ -1765,6 +2661,73 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length); } + /// + /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int IndexOfAny(this ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.IndexOfAnyValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.IndexOfAnyValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + span.Length); + } + } + + return IndexOfAnyDefaultComparer(span, value0, value1); + static int IndexOfAnyDefaultComparer(ReadOnlySpan span, T value0, T value1) + { + for (int i = 0; i < span.Length; i++) + { + if (EqualityComparer.Default.Equals(span[i], value0) || + EqualityComparer.Default.Equals(span[i], value1)) + { + return i; + } + } + + return -1; + } + } + else + { + return IndexOfAnyComparer(span, value0, value1, comparer); + static int IndexOfAnyComparer(ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + for (int i = 0; i < span.Length; i++) + { + if (comparer.Equals(span[i], value0) || + comparer.Equals(span[i], value1)) + { + return i; + } + } + + return -1; + } + } + } + /// /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. /// @@ -1800,6 +2763,78 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length); } + /// + /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// One of the values to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int IndexOfAny(this ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.IndexOfAnyValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.IndexOfAnyValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + span.Length); + } + } + + return IndexOfAnyDefaultComparer(span, value0, value1, value2); + static int IndexOfAnyDefaultComparer(ReadOnlySpan span, T value0, T value1, T value2) + { + for (int i = 0; i < span.Length; i++) + { + if (EqualityComparer.Default.Equals(span[i], value0) || + EqualityComparer.Default.Equals(span[i], value1) || + EqualityComparer.Default.Equals(span[i], value2)) + { + return i; + } + } + + return -1; + } + } + else + { + return IndexOfAnyComparer(span, value0, value1, value2, comparer); + static int IndexOfAnyComparer(ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + for (int i = 0; i < span.Length; i++) + { + if (comparer.Equals(span[i], value0) || + comparer.Equals(span[i], value1) || + comparer.Equals(span[i], value2)) + { + return i; + } + } + + return -1; + } + } + } + /// /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. /// @@ -1900,6 +2935,43 @@ public static unsafe int IndexOfAny(this ReadOnlySpan span, ReadOnlySpan + /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// The set of values to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + public static int IndexOfAny(this ReadOnlySpan span, ReadOnlySpan values, IEqualityComparer? comparer = null) + { + switch (values.Length) + { + case 0: + return -1; + + case 1: + return IndexOf(span, values[0], comparer); + + case 2: + return IndexOfAny(span, values[0], values[1], comparer); + + case 3: + return IndexOfAny(span, values[0], values[1], values[2], comparer); + + default: + comparer ??= EqualityComparer.Default; + + for (int i = 0; i < span.Length; i++) + { + if (values.Contains(span[i], comparer)) + { + return i; + } + } + + return -1; + } + } + /// /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. /// @@ -2009,6 +3081,74 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length); } + /// + /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int LastIndexOfAny(this ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.LastIndexOfAnyValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.LastIndexOfAnyValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + span.Length); + } + } + + return LastIndexOfAnyDefaultComparer(span, value0, value1); + static int LastIndexOfAnyDefaultComparer(ReadOnlySpan span, T value0, T value1) + { + for (int i = span.Length - 1; i >= 0; i--) + { + if (EqualityComparer.Default.Equals(span[i], value0) || + EqualityComparer.Default.Equals(span[i], value1)) + { + return i; + } + } + + return -1; + } + } + else + { + return LastIndexOfAnyComparer(span, value0, value1, comparer); + static int LastIndexOfAnyComparer(ReadOnlySpan span, T value0, T value1, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + + for (int i = span.Length - 1; i >= 0; i--) + { + if (comparer.Equals(span[i], value0) || + comparer.Equals(span[i], value1)) + { + return i; + } + } + + return -1; + } + } + } + /// /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. /// @@ -2040,8 +3180,81 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length); } } - - return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length); + + return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length); + } + + /// + /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// One of the values to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int LastIndexOfAny(this ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.LastIndexOfAnyValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.LastIndexOfAnyValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + span.Length); + } + } + + return LastIndexOfAnyDefaultComparer(span, value0, value1, value2); + static int LastIndexOfAnyDefaultComparer(ReadOnlySpan span, T value0, T value1, T value2) + { + for (int i = span.Length - 1; i >= 0; i--) + { + if (EqualityComparer.Default.Equals(span[i], value0) || + EqualityComparer.Default.Equals(span[i], value1) || + EqualityComparer.Default.Equals(span[i], value2)) + { + return i; + } + } + + return -1; + } + } + else + { + return LastIndexOfAnyComparer(span, value0, value1, value2, comparer); + static int LastIndexOfAnyComparer(ReadOnlySpan span, T value0, T value1, T value2, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + + for (int i = span.Length - 1; i >= 0; i--) + { + if (comparer.Equals(span[i], value0) || + comparer.Equals(span[i], value1) || + comparer.Equals(span[i], value2)) + { + return i; + } + } + + return -1; + } + } } /// @@ -2144,6 +3357,43 @@ public static unsafe int LastIndexOfAny(this ReadOnlySpan span, ReadOnlySp return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length); } + /// + /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// The set of values to search for. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + public static unsafe int LastIndexOfAny(this ReadOnlySpan span, ReadOnlySpan values, IEqualityComparer? comparer = null) + { + switch (values.Length) + { + case 0: + return -1; + + case 1: + return LastIndexOf(span, values[0], comparer); + + case 2: + return LastIndexOfAny(span, values[0], values[1], comparer); + + case 3: + return LastIndexOfAny(span, values[0], values[1], values[2], comparer); + + default: + comparer ??= EqualityComparer.Default; + + for (int i = span.Length - 1; i >= 0; i--) + { + if (values.Contains(span[i], comparer)) + { + return i; + } + } + + return -1; + } + } + /// /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. /// @@ -2187,7 +3437,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(other)), /// /// The first sequence to compare. /// The second sequence to compare. - /// The implementation to use when comparing elements, or null to use the default for the type of an element. + /// The implementation to use when comparing elements, or to use the default for the type of an element. /// true if the two sequences are equal; otherwise, false. [OverloadResolutionPriority(-1)] public static bool SequenceEqual(this Span span, ReadOnlySpan other, IEqualityComparer? comparer = null) => @@ -2198,7 +3448,7 @@ public static bool SequenceEqual(this Span span, ReadOnlySpan other, IE /// /// The first sequence to compare. /// The second sequence to compare. - /// The implementation to use when comparing elements, or null to use the default for the type of an element. + /// The implementation to use when comparing elements, or to use the default for the type of an element. /// true if the two sequences are equal; otherwise, false. public static unsafe bool SequenceEqual(this ReadOnlySpan span, ReadOnlySpan other, IEqualityComparer? comparer = null) { @@ -2273,6 +3523,26 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(other)), return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(other), other.Length); } + /// + /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T). + /// + public static unsafe int SequenceCompareTo(this ReadOnlySpan span, ReadOnlySpan other, IComparer? comparer = null) + { + int minLength = Math.Min(span.Length, other.Length); + comparer ??= Comparer.Default; + + for (int i = 0; i < minLength; i++) + { + int c = comparer.Compare(span[i], other[i]); + if (c != 0) + { + return c; + } + } + + return span.Length.CompareTo(other.Length); + } + /// /// Determines whether the specified sequence appears at the start of the span. /// @@ -2302,6 +3572,17 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(value)), return valueLength <= span.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), valueLength); } + /// + /// Determines whether a specified sequence appears at the start of a read-only span. + /// + /// The source span. + /// The sequence to compare to the start of . + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool StartsWith(this ReadOnlySpan span, ReadOnlySpan value, IEqualityComparer? comparer = null) => + value.Length <= span.Length && + SequenceEqual(span.Slice(0, value.Length), value, comparer); + /// /// Determines whether the specified sequence appears at the end of the span. /// @@ -2336,6 +3617,17 @@ ref MemoryMarshal.GetReference(value), valueLength); } + /// + /// Determines whether the specified sequence appears at the end of the read-only span. + /// + /// The source span. + /// The sequence to compare to the end of . + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool EndsWith(this ReadOnlySpan span, ReadOnlySpan value, IEqualityComparer? comparer = null) => + value.Length <= span.Length && + SequenceEqual(span.Slice(span.Length - value.Length), value, comparer); + /// /// Determines whether the specified value appears at the start of the span. /// @@ -2347,6 +3639,19 @@ ref MemoryMarshal.GetReference(value), public static bool StartsWith(this ReadOnlySpan span, T value) where T : IEquatable? => span.Length != 0 && (span[0]?.Equals(value) ?? (object?)value is null); + /// + /// Determines whether the specified value appears at the start of the span. + /// + /// The type of elements in the span. + /// The span to search. + /// The value to compare. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// if matches the beginning of ; otherwise, . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool StartsWith(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null) => + span.Length != 0 && + (comparer is null ? EqualityComparer.Default.Equals(span[0], value) : comparer.Equals(span[0], value)); + /// /// Determines whether the specified value appears at the end of the span. /// @@ -2358,6 +3663,19 @@ public static bool StartsWith(this ReadOnlySpan span, T value) where T : I public static bool EndsWith(this ReadOnlySpan span, T value) where T : IEquatable? => span.Length != 0 && (span[^1]?.Equals(value) ?? (object?)value is null); + /// + /// Determines whether the specified value appears at the end of the span. + /// + /// The type of the elements in the span. + /// The span to search. + /// The value to compare. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// if matches the end of ; otherwise, . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool EndsWith(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null) => + span.Length != 0 && + (comparer is null ? EqualityComparer.Default.Equals(span[^1], value) : comparer.Equals(span[^1], value)); + /// /// Reverses the sequence of the elements in the entire span. /// @@ -2953,7 +4271,7 @@ public static int BinarySearch( this ReadOnlySpan span, T value, TComparer comparer) where TComparer : IComparer, allows ref struct { - if (comparer == null) + if (comparer is null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparer); var comparable = new SpanHelpers.ComparerComparable( @@ -3156,6 +4474,97 @@ public static unsafe void Replace(this Span span, T oldValue, T newValue) SpanHelpers.Replace(ref src2, ref src2, oldValue, newValue, length); } + /// + /// Replaces all occurrences of with . + /// + /// The type of the elements in the span. + /// The span in which the elements should be replaced. + /// The value to be replaced with . + /// The value to replace all occurrences of . + /// The implementation to use when comparing elements, or to use the default for the type of an element. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void Replace(this Span span, T oldValue, T newValue, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + ref byte src = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); + SpanHelpers.ReplaceValueType( + ref src, + ref src, + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), + (uint)span.Length); + return; + } + else if (sizeof(T) == sizeof(ushort)) + { + // Use ushort rather than short, as this avoids a sign-extending move. + ref ushort src = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); + SpanHelpers.ReplaceValueType( + ref src, + ref src, + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), + (uint)span.Length); + return; + } + else if (sizeof(T) == sizeof(int)) + { + ref int src = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); + SpanHelpers.ReplaceValueType( + ref src, + ref src, + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), + (uint)span.Length); + return; + } + else if (sizeof(T) == sizeof(long)) + { + ref long src = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); + SpanHelpers.ReplaceValueType( + ref src, + ref src, + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), + (uint)span.Length); + return; + } + } + + ReplaceDefaultComparer(span, oldValue, newValue); + static void ReplaceDefaultComparer(Span span, T oldValue, T newValue) + { + for (int i = 0; i < span.Length; i++) + { + if (EqualityComparer.Default.Equals(span[i], oldValue)) + { + span[i] = newValue; + } + } + } + } + else + { + ReplaceComparer(span, oldValue, newValue, comparer); + static void ReplaceComparer(Span span, T oldValue, T newValue, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + for (int i = 0; i < span.Length; i++) + { + if (comparer.Equals(span[i], oldValue)) + { + span[i] = newValue; + } + } + } + } + } + /// /// Copies to , replacing all occurrences of with . /// @@ -3239,6 +4648,112 @@ ref Unsafe.As(ref dst), SpanHelpers.Replace(ref src, ref dst, oldValue, newValue, length); } + /// + /// Copies to , replacing all occurrences of with . + /// + /// The type of the elements in the spans. + /// The span to copy. + /// The span into which the copied and replaced values should be written. + /// The value to be replaced with . + /// The value to replace all occurrences of . + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// The span was shorter than the span. + /// The and were overlapping but not referring to the same starting location. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void Replace(this ReadOnlySpan source, Span destination, T oldValue, T newValue, IEqualityComparer? comparer = null) + { + nuint length = (uint)source.Length; + if (length == 0) + { + return; + } + + if (length > (uint)destination.Length) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + + ref T src = ref MemoryMarshal.GetReference(source); + ref T dst = ref MemoryMarshal.GetReference(destination); + + nint byteOffset = Unsafe.ByteOffset(ref src, ref dst); + if (byteOffset != 0 && + ((nuint)byteOffset < (nuint)((nint)source.Length * sizeof(T)) || + (nuint)byteOffset > (nuint)(-((nint)destination.Length * sizeof(T))))) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.InvalidOperation_SpanOverlappedOperation); + } + + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + SpanHelpers.ReplaceValueType( + ref Unsafe.As(ref src), + ref Unsafe.As(ref dst), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), + length); + return; + } + else if (sizeof(T) == sizeof(ushort)) + { + // Use ushort rather than short, as this avoids a sign-extending move. + SpanHelpers.ReplaceValueType( + ref Unsafe.As(ref src), + ref Unsafe.As(ref dst), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), + length); + return; + } + else if (sizeof(T) == sizeof(int)) + { + SpanHelpers.ReplaceValueType( + ref Unsafe.As(ref src), + ref Unsafe.As(ref dst), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), + length); + return; + } + else if (sizeof(T) == sizeof(long)) + { + SpanHelpers.ReplaceValueType( + ref Unsafe.As(ref src), + ref Unsafe.As(ref dst), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), + length); + return; + } + } + + ReplaceDefaultComparer(source, destination, oldValue, newValue); + static void ReplaceDefaultComparer(ReadOnlySpan source, Span destination, T oldValue, T newValue) + { + for (int i = 0; i < source.Length; i++) + { + destination[i] = EqualityComparer.Default.Equals(source[i], oldValue) ? newValue : source[i]; + } + } + } + else + { + ReplaceComparer(source, destination, oldValue, newValue, comparer); + static void ReplaceComparer(ReadOnlySpan source, Span destination, T oldValue, T newValue, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + for (int i = 0; i < source.Length; i++) + { + destination[i] = comparer.Equals(source[i], oldValue) ? newValue : source[i]; + } + } + } + } + /// Finds the length of any common prefix shared between and . /// The type of the elements in the spans. /// The first sequence to compare. @@ -3252,7 +4767,7 @@ public static int CommonPrefixLength(this Span span, ReadOnlySpan other /// The type of the elements in the spans. /// The first sequence to compare. /// The second sequence to compare. - /// The implementation to use when comparing elements, or null to use the default for the type of an element. + /// The implementation to use when comparing elements, or to use the default for the type of an element. /// The length of the common prefix shared by the two spans. If there's no shared prefix, 0 is returned. [OverloadResolutionPriority(-1)] public static int CommonPrefixLength(this Span span, ReadOnlySpan other, IEqualityComparer? comparer) => @@ -3309,7 +4824,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(other)), /// The type of the elements in the sequences. /// The first sequence to compare. /// The second sequence to compare. - /// The implementation to use when comparing elements, or null to use the default for the type of an element. + /// The implementation to use when comparing elements, or to use the default for the type of an element. /// The length of the common prefix shared by the two spans. If there's no shared prefix, 0 is returned. public static int CommonPrefixLength(this ReadOnlySpan span, ReadOnlySpan other, IEqualityComparer? comparer) { @@ -3797,6 +5312,85 @@ ref MemoryMarshal.GetReference(span), span.Length); } + /// Counts the number of times the specified occurs in the . + /// The element type of the span. + /// The span to search. + /// The value for which to search. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// The number of times was found in the . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int Count(this ReadOnlySpan span, T value, IEqualityComparer? comparer = null) + { + if (typeof(T).IsValueType && (comparer is null || comparer == EqualityComparer.Default)) + { + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (sizeof(T) == sizeof(byte)) + { + return SpanHelpers.CountValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(short)) + { + return SpanHelpers.CountValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(int)) + { + return SpanHelpers.CountValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + else if (sizeof(T) == sizeof(long)) + { + return SpanHelpers.CountValueType( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.BitCast(value), + span.Length); + } + } + + return CountDefaultComparer(span, value); + static int CountDefaultComparer(ReadOnlySpan span, T value) + { + int count = 0; + for (int i = 0; i < span.Length; i++) + { + if (EqualityComparer.Default.Equals(span[i], value)) + { + count++; + } + } + + return count; + } + } + else + { + return CountComparer(span, value, comparer); + static int CountComparer(ReadOnlySpan span, T value, IEqualityComparer? comparer) + { + comparer ??= EqualityComparer.Default; + + int count = 0; + for (int i = 0; i < span.Length; i++) + { + if (comparer.Equals(span[i], value)) + { + count++; + } + } + + return count; + } + } + } + /// Counts the number of times the specified occurs in the . /// The element type of the span. /// The span to search. @@ -3835,6 +5429,36 @@ public static int Count(this ReadOnlySpan span, ReadOnlySpan value) whe } } + /// Counts the number of times the specified occurs in the . + /// The element type of the span. + /// The span to search. + /// The value for which to search. + /// The implementation to use when comparing elements, or to use the default for the type of an element. + /// The number of times was found in the . + public static int Count(this ReadOnlySpan span, ReadOnlySpan value, IEqualityComparer? comparer = null) + { + switch (value.Length) + { + case 0: + return 0; + + case 1: + return Count(span, value[0], comparer); + + default: + int count = 0; + + int pos; + while ((pos = span.IndexOf(value, comparer)) >= 0) + { + span = span.Slice(pos + value.Length); + count++; + } + + return count; + } + } + /// Writes the specified interpolated string to the character span. /// The span to which the interpolated string should be formatted. /// The interpolated string.