Skip to content
5 changes: 5 additions & 0 deletions src/libraries/System.Memory/ref/System.Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ public static partial class MemoryExtensions
public static bool ContainsAnyInRange<T>(this System.ReadOnlySpan<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
[System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)]
public static bool ContainsAnyInRange<T>(this System.Span<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
public static bool ContainsAnyWhiteSpace(this System.ReadOnlySpan<char> span) { throw null; }
public static void CopyTo<T>(this T[]? source, System.Memory<T> destination) { }
public static void CopyTo<T>(this T[]? source, System.Span<T> destination) { }
[System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)]
Expand Down Expand Up @@ -331,6 +332,7 @@ public static void CopyTo<T>(this T[]? source, System.Span<T> destination) { }
public static int IndexOfAnyExceptInRange<T>(this System.ReadOnlySpan<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
[System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)]
public static int IndexOfAnyExceptInRange<T>(this System.Span<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
public static int IndexOfAnyExceptWhiteSpace(this System.ReadOnlySpan<char> span) { throw null; }
public static int IndexOf<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> value) where T : System.IEquatable<T>? { throw null; }
public static int IndexOf<T>(this System.ReadOnlySpan<T> span, T value) where T : System.IEquatable<T>? { throw null; }
[System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)]
Expand All @@ -340,6 +342,7 @@ public static void CopyTo<T>(this T[]? source, System.Span<T> destination) { }
public static int IndexOfAnyInRange<T>(this System.ReadOnlySpan<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
[System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)]
public static int IndexOfAnyInRange<T>(this System.Span<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
public static int IndexOfAnyWhiteSpace(this System.ReadOnlySpan<char> span) { throw null; }
public static bool IsWhiteSpace(this System.ReadOnlySpan<char> span) { throw null; }
public static int LastIndexOf(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> value, System.StringComparison comparisonType) { throw null; }
public static int LastIndexOfAny<T>(this System.ReadOnlySpan<T> span, System.Buffers.SearchValues<T> values) where T : System.IEquatable<T>? { throw null; }
Expand Down Expand Up @@ -372,6 +375,7 @@ public static void CopyTo<T>(this T[]? source, System.Span<T> destination) { }
public static int LastIndexOfAnyExceptInRange<T>(this System.ReadOnlySpan<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
[System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)]
public static int LastIndexOfAnyExceptInRange<T>(this System.Span<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
public static int LastIndexOfAnyExceptWhiteSpace(this System.ReadOnlySpan<char> span) { throw null; }
public static int LastIndexOf<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> value) where T : System.IEquatable<T>? { throw null; }
public static int LastIndexOf<T>(this System.ReadOnlySpan<T> span, T value) where T : System.IEquatable<T>? { throw null; }
[System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)]
Expand All @@ -381,6 +385,7 @@ public static void CopyTo<T>(this T[]? source, System.Span<T> destination) { }
public static int LastIndexOfAnyInRange<T>(this System.ReadOnlySpan<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
[System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)]
public static int LastIndexOfAnyInRange<T>(this System.Span<T> span, T lowInclusive, T highInclusive) where T : System.IComparable<T> { throw null; }
public static int LastIndexOfAnyWhiteSpace(this System.ReadOnlySpan<char> span) { throw null; }
public static bool Overlaps<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> other) { throw null; }
public static bool Overlaps<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> other, out int elementOffset) { throw null; }
[System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(-1)]
Expand Down
249 changes: 249 additions & 0 deletions src/libraries/System.Memory/tests/Span/StringSearchValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
Expand Down Expand Up @@ -469,6 +470,254 @@ public static void TestIndexOfAny_RandomInputs()
helper.TestRandomInputs();
}

[Fact]
public static void IsWhiteSpace_True()
{
Assert.True(Span<char>.Empty.IsWhiteSpace());

List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

Assert.True(CollectionsMarshal.AsSpan(chars).IsWhiteSpace());
}

[Fact]
public static void IsWhiteSpace_False()
{
List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

var index = chars.Count;
chars.AddRange(chars.ToArray());
chars.Insert(index, ' ');
var span = CollectionsMarshal.AsSpan(chars);

for (int i = 0; i <= char.MaxValue; i++)
{
if (!char.IsWhiteSpace((char)i))
{
chars[index] = (char)i;
Assert.False(span.IsWhiteSpace());
}
}
}

[Fact]
public static void ContainsAnyWhiteSpace_Found()
{
List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (!char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

var index = chars.Count;
chars.AddRange(chars.ToArray());
chars.Insert(index, ' ');
var span = CollectionsMarshal.AsSpan(chars);

for (int i = 0; i <= char.MaxValue; i++)
{
if (char.IsWhiteSpace((char)i))
{
chars[index] = (char)i;
Assert.True(span.ContainsAnyWhiteSpace());
}
}
}

[Fact]
public static void ContainsAnyWhiteSpace_NotFound()
{
Assert.False(Span<char>.Empty.ContainsAnyWhiteSpace());

List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (!char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

Assert.False(CollectionsMarshal.AsSpan(chars).ContainsAnyWhiteSpace());
}

[Fact]
public static void IndexOfAnyWhiteSpace_Found()
{
List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (!char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

var index = chars.Count;
chars.AddRange(chars.ToArray());
chars.Insert(index, ' ');
chars.Insert(index, ' ');
var span = CollectionsMarshal.AsSpan(chars);

for (int i = 0; i <= char.MaxValue; i++)
{
if (char.IsWhiteSpace((char)i))
{
chars[index] = (char)i;
chars[index + 1] = (char)i;
Assert.Equal(index, span.IndexOfAnyWhiteSpace());
}
}
}

[Fact]
public static void IndexOfAnyWhiteSpace_NotFound()
{
Assert.Equal(-1, Span<char>.Empty.IndexOfAnyWhiteSpace());

List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (!char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

Assert.Equal(-1, CollectionsMarshal.AsSpan(chars).IndexOfAnyWhiteSpace());
}

[Fact]
public static void IndexOfAnyExceptWhiteSpace_Found()
{
List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

var index = chars.Count;
chars.AddRange(chars.ToArray());
chars.Insert(index, ' ');
chars.Insert(index, ' ');
var span = CollectionsMarshal.AsSpan(chars);

for (int i = 0; i <= char.MaxValue; i++)
{
if (!char.IsWhiteSpace((char)i))
{
chars[index] = (char)i;
chars[index + 1] = (char)i;
Assert.Equal(index, span.IndexOfAnyExceptWhiteSpace());
}
}
}

[Fact]
public static void IndexOfAnyExceptWhiteSpace_NotFound()
{
Assert.Equal(-1, Span<char>.Empty.IndexOfAnyExceptWhiteSpace());

List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

Assert.Equal(-1, CollectionsMarshal.AsSpan(chars).IndexOfAnyExceptWhiteSpace());
}

[Fact]
public static void LastIndexOfAnyWhiteSpace_Found()
{
List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (!char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

var index = chars.Count;
chars.AddRange(chars.ToArray());
chars.Insert(index, ' ');
chars.Insert(index, ' ');
var span = CollectionsMarshal.AsSpan(chars);

for (int i = 0; i <= char.MaxValue; i++)
{
if (char.IsWhiteSpace((char)i))
{
chars[index] = (char)i;
chars[index + 1] = (char)i;
Assert.Equal(index + 1, span.LastIndexOfAnyWhiteSpace());
}
}
}

[Fact]
public static void LastIndexOfAnyWhiteSpace_NotFound()
{
Assert.Equal(-1, Span<char>.Empty.LastIndexOfAnyWhiteSpace());

List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (!char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

Assert.Equal(-1, CollectionsMarshal.AsSpan(chars).LastIndexOfAnyWhiteSpace());
}

[Fact]
public static void LastIndexOfAnyExceptWhiteSpace_Found()
{
List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

var index = chars.Count;
chars.AddRange(chars.ToArray());
chars.Insert(index, ' ');
chars.Insert(index, ' ');
var span = CollectionsMarshal.AsSpan(chars);

for (int i = 0; i <= char.MaxValue; i++)
{
if (!char.IsWhiteSpace((char)i))
{
chars[index] = (char)i;
chars[index + 1] = (char)i;
Assert.Equal(index + 1, span.LastIndexOfAnyExceptWhiteSpace());
}
}
}

[Fact]
public static void LastIndexOfAnyExceptWhiteSpace_NotFound()
{
Assert.Equal(-1, Span<char>.Empty.LastIndexOfAnyExceptWhiteSpace());

List<char> chars = [];
for (int i = 0; i <= char.MaxValue; i++)
{
if (char.IsWhiteSpace((char)i))
chars.Add((char)i);
}

Assert.Equal(-1, CollectionsMarshal.AsSpan(chars).LastIndexOfAnyExceptWhiteSpace());
}

[ConditionalFact(nameof(CanTestInvariantCulture))]
[SkipOnPlatform(TestPlatforms.LinuxBionic, "Remote executor has problems with exit codes")]
public static void TestIndexOfAny_RandomInputs_InvariantCulture()
Expand Down
Original file line number Diff line number Diff line change
@@ -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.Buffers;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
Expand All @@ -14,15 +15,8 @@ public static partial class MemoryExtensions
/// <summary>
/// Indicates whether the specified span contains only white-space characters.
/// </summary>
public static bool IsWhiteSpace(this ReadOnlySpan<char> span)
{
for (int i = 0; i < span.Length; i++)
{
if (!char.IsWhiteSpace(span[i]))
return false;
}
return true;
}
public static bool IsWhiteSpace(this ReadOnlySpan<char> span) =>
SearchValues.WhiteSpaces.IndexOfAnyExcept(span) < 0;

/// <summary>
/// Returns a value indicating whether the specified <paramref name="value"/> occurs within the <paramref name="span"/>.
Expand All @@ -35,6 +29,16 @@ public static bool Contains(this ReadOnlySpan<char> span, ReadOnlySpan<char> val
return IndexOf(span, value, comparisonType) >= 0;
}

/// <summary>
/// Returns a value indicating whether the specified span contains <see cref="char.IsWhiteSpace(char)">any
/// white-space characters</see>, and returns <see langword="true"/> if found. If not found, returns
/// <see langword="false"/>.
/// </summary>
/// <param name="span">The source span.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool ContainsAnyWhiteSpace(this ReadOnlySpan<char> span) =>
SearchValues.WhiteSpaces.IndexOfAny(span) >= 0;

/// <summary>
/// Determines whether this <paramref name="span"/> and the specified <paramref name="other"/> span have the same characters
/// when compared using the specified <paramref name="comparisonType"/> option.
Expand Down Expand Up @@ -149,6 +153,22 @@ public static int IndexOf(this ReadOnlySpan<char> span, ReadOnlySpan<char> value
}
}

/// <summary>
/// Reports the zero-based index of the first occurrence of <see cref="char.IsWhiteSpace(char)">any white-space
/// characters</see> in the current <paramref name="span"/>, or -1 if not founded.
/// </summary>
/// <param name="span">The source span.</param>
public static int IndexOfAnyWhiteSpace(this ReadOnlySpan<char> span) =>
SearchValues.WhiteSpaces.IndexOfAny(span);

/// <summary>
/// Reports the zero-based index of the first occurrence of <see cref="char.IsWhiteSpace(char)">any
/// non-white-space characters</see> in the current <paramref name="span"/>, or -1 if not founded.
/// </summary>
/// <param name="span">The source span.</param>
public static int IndexOfAnyExceptWhiteSpace(this ReadOnlySpan<char> span) =>
SearchValues.WhiteSpaces.IndexOfAnyExcept(span);

/// <summary>
/// Reports the zero-based index of the last occurrence of the specified <paramref name="value"/> in the current <paramref name="span"/>.
/// </summary>
Expand Down Expand Up @@ -184,6 +204,22 @@ ref MemoryMarshal.GetReference(value),
}
}

/// <summary>
/// Reports the zero-based index of the last occurrence of <see cref="char.IsWhiteSpace(char)">any white-space
/// characters</see> in the current <paramref name="span"/>, or -1 if not founded.
/// </summary>
/// <param name="span">The source span.</param>
public static int LastIndexOfAnyWhiteSpace(this ReadOnlySpan<char> span) =>
SearchValues.WhiteSpaces.LastIndexOfAny(span);

/// <summary>
/// Reports the zero-based index of the last occurrence of <see cref="char.IsWhiteSpace(char)">any
/// non-white-space characters</see> in the current <paramref name="span"/>, or -1 if not founded.
/// </summary>
/// <param name="span">The source span.</param>
public static int LastIndexOfAnyExceptWhiteSpace(this ReadOnlySpan<char> span) =>
SearchValues.WhiteSpaces.LastIndexOfAnyExcept(span);

/// <summary>
/// Copies the characters from the source span into the destination, converting each character to lowercase,
/// using the casing rules of the specified culture.
Expand Down
Loading
Loading