Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/libraries/System.Memory/ref/System.Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ public static partial class MemoryExtensions
public static bool Contains(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> value, System.StringComparison comparisonType) { throw null; }
public static bool Contains<T>(this System.ReadOnlySpan<T> span, T value) where T : System.IEquatable<T>? { throw null; }
public static bool Contains<T>(this System.Span<T> span, T value) where T : System.IEquatable<T>? { throw null; }
public static bool ContainsAny(this System.ReadOnlySpan<char> span, System.Buffers.SearchValues<string> values) { throw null; }
public static bool ContainsAny(this System.Span<char> span, System.Buffers.SearchValues<string> values) { throw null; }
public static bool ContainsAny<T>(this System.ReadOnlySpan<T> span, System.Buffers.SearchValues<T> values) where T : System.IEquatable<T>? { throw null; }
public static bool ContainsAny<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> values) where T : System.IEquatable<T>? { throw null; }
public static bool ContainsAny<T>(this System.ReadOnlySpan<T> span, T value0, T value1) where T : System.IEquatable<T>? { throw null; }
Expand Down Expand Up @@ -271,6 +273,8 @@ public static void CopyTo<T>(this T[]? source, System.Span<T> destination) { }
public static System.Text.SpanRuneEnumerator EnumerateRunes(this System.Span<char> span) { throw null; }
public static bool Equals(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> other, System.StringComparison comparisonType) { throw null; }
public static int IndexOf(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> value, System.StringComparison comparisonType) { throw null; }
public static int IndexOfAny(this System.ReadOnlySpan<char> span, System.Buffers.SearchValues<string> values) { throw null; }
public static int IndexOfAny(this System.Span<char> span, System.Buffers.SearchValues<string> values) { throw null; }
public static int IndexOfAny<T>(this System.ReadOnlySpan<T> span, System.Buffers.SearchValues<T> values) where T : System.IEquatable<T>? { throw null; }
public static int IndexOfAny<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> values) where T : System.IEquatable<T>? { throw null; }
public static int IndexOfAny<T>(this System.ReadOnlySpan<T> span, T value0, T value1) where T : System.IEquatable<T>? { throw null; }
Expand Down
504 changes: 504 additions & 0 deletions src/libraries/System.Memory/tests/Span/StringSearchValues.cs

Large diffs are not rendered by default.

13 changes: 5 additions & 8 deletions src/libraries/System.Memory/tests/System.Memory.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@
<Compile Include="MemoryMarshal\CreateSpan.cs" />
<Compile Include="MemoryMarshal\CreateReadOnlySpan.cs" />
<Compile Include="MemoryMarshal\CreateReadOnlySpanFromNullTerminated.cs" />
<Compile Include="$(CommonPath)..\tests\System\RealFormatterTestsBase.cs"
Link="ParsersAndFormatters\Formatter\RealFormatterTestsBase.cs" />
<Compile Include="$(CommonPath)..\tests\System\RealFormatterTestsBase.cs" Link="ParsersAndFormatters\Formatter\RealFormatterTestsBase.cs" />
<Compile Include="ParsersAndFormatters\Formatter\RealFormatterTests.cs" />
<Compile Include="$(CommonPath)..\tests\System\RealParserTestsBase.cs"
Link="ParsersAndFormatters\Parser\RealParserTestsBase.cs" />
<Compile Include="$(CommonPath)..\tests\System\RealParserTestsBase.cs" Link="ParsersAndFormatters\Parser\RealParserTestsBase.cs" />
<Compile Include="ParsersAndFormatters\Parser\RealParserTests.cs" />
<Compile Include="ReadOnlySpan\Contains.byte.cs" />
<Compile Include="ReadOnlySpan\Contains.T.cs" />
<Compile Include="Span\StringSearchValues.cs" />
<Compile Include="Span\Reflection.cs" />
<Compile Include="SequenceReader\Advance.cs" />
<Compile Include="SequenceReader\BasicTests.cs" />
Expand Down Expand Up @@ -276,9 +275,7 @@
<Compile Include="Base64\Base64ValidationUnitTests.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(CommonTestPath)System\Buffers\NativeMemoryManager.cs"
Link="Common\System\Buffers\NativeMemoryManager.cs" />
<Compile Include="$(CommonPath)System\MutableDecimal.cs"
Link="Common\System\MutableDecimal.cs" />
<Compile Include="$(CommonTestPath)System\Buffers\NativeMemoryManager.cs" Link="Common\System\Buffers\NativeMemoryManager.cs" />
<Compile Include="$(CommonPath)System\MutableDecimal.cs" Link="Common\System\MutableDecimal.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -4235,4 +4235,7 @@
<data name="OutOfMemory_StringTooLong" xml:space="preserve">
<value>String length exceeded supported range.</value>
</data>
<data name="Argument_SearchValues_UnsupportedStringComparison" xml:space="preserve">
<value>SearchValues&lt;string&gt; supports only Ordinal and OrdinalIgnoreCase StringComparison semantics.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,25 @@
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\SearchValuesDebugView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\EmptySearchValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\ProbabilisticMap.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\Helpers\AhoCorasick.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\Helpers\AhoCorasickBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\Helpers\CharacterFrequencyHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\Helpers\EightPackedReferences.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\Helpers\RabinKarp.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\Helpers\StringSearchValuesHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\Helpers\TeddyBucketizer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\Helpers\TeddyHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\AsciiStringSearchValuesTeddyBucketizedN2.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\AsciiStringSearchValuesTeddyBucketizedN3.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\AsciiStringSearchValuesTeddyNonBucketizedN2.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\AsciiStringSearchValuesTeddyNonBucketizedN3.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\AsciiStringSearchValuesTeddyBase.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\SingleStringSearchValuesThreeChars.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\SingleStringSearchValuesFallback.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\StringSearchValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\StringSearchValuesBase.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\StringSearchValuesAhoCorasick.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\Strings\StringSearchValuesRabinKarp.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOutOfRangeException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\InsufficientExecutionStackException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\InsufficientMemoryException.cs" />
Expand Down Expand Up @@ -2583,11 +2602,11 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\LowLevelLifoSemaphore.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\LowLevelLifoSemaphore.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PreAllocatedOverlapped.Windows.cs" Condition="'$(TargetsWindows)' == 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PreAllocatedOverlapped.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PreAllocatedOverlapped.Unix.cs" Condition="'$(TargetsUnix)' == 'true' or '$(TargetsBrowser)' == 'true' or '$(TargetsWasi)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PreAllocatedOverlapped.Portable.cs" Condition="('$(TargetsBrowser)' != 'true' and '$(TargetsWasi)' != 'true') or '$(FeatureWasmThreads)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\RegisteredWaitHandle.Windows.cs" Condition="'$(TargetsWindows)' == 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\RegisteredWaitHandle.Unix.cs" Condition="'$(TargetsWindows)' != 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\RegisteredWaitHandle.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\RegisteredWaitHandle.Unix.cs" Condition="'$(TargetsWindows)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\RegisteredWaitHandle.Portable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\LowLevelLifoSemaphoreBase.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPoolBoundHandle.Portable.cs" />
Expand Down Expand Up @@ -2657,4 +2676,4 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnaryPlusOperators.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnsignedNumber.cs" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ internal static int CompareStringIgnoreCaseNonAscii(ref char strA, int lengthA,
return OrdinalCasing.CompareStringIgnoreCase(ref strA, lengthA, ref strB, lengthB);
}

private static bool EqualsIgnoreCase_Vector128(ref char charA, ref char charB, int length)
internal static bool EqualsIgnoreCase_Vector128(ref char charA, ref char charB, int length)
{
Debug.Assert(length >= Vector128<ushort>.Count);
Debug.Assert(Vector128.IsHardwareAccelerated);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ public string ToUpper(string str)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static char ToUpperAsciiInvariant(char c)
internal static char ToUpperAsciiInvariant(char c)
{
if (char.IsAsciiLetterLower(c))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,11 @@ public static bool ContainsAny<T>(this Span<T> span, ReadOnlySpan<T> values) whe
public static bool ContainsAny<T>(this Span<T> span, SearchValues<T> values) where T : IEquatable<T>? =>
ContainsAny((ReadOnlySpan<T>)span, values);

/// <inheritdoc cref="ContainsAny(ReadOnlySpan{char}, SearchValues{string})"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool ContainsAny(this Span<char> span, SearchValues<string> values) =>
ContainsAny((ReadOnlySpan<char>)span, values);

/// <inheritdoc cref="ContainsAnyExcept{T}(ReadOnlySpan{T}, T)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool ContainsAnyExcept<T>(this Span<T> span, T value) where T : IEquatable<T>? =>
Expand Down Expand Up @@ -490,6 +495,15 @@ public static bool ContainsAny<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> val
public static bool ContainsAny<T>(this ReadOnlySpan<T> span, SearchValues<T> values) where T : IEquatable<T>? =>
IndexOfAny(span, values) >= 0;

/// <summary>
/// Searches for any occurance of any of the specified substring <paramref name="values"/> and returns true if found. If not found, returns false.
/// </summary>
/// <param name="span">The span to search.</param>
/// <param name="values">The set of values to search for.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool ContainsAny(this ReadOnlySpan<char> span, SearchValues<string> values) =>
IndexOfAny(span, values) >= 0;

/// <summary>
/// Searches for any value other than the specified <paramref name="value"/>.
/// </summary>
Expand Down Expand Up @@ -1872,6 +1886,15 @@ public static int IndexOfAny<T>(this Span<T> span, ReadOnlySpan<T> values) where
public static int IndexOfAny<T>(this Span<T> span, SearchValues<T> values) where T : IEquatable<T>? =>
IndexOfAny((ReadOnlySpan<T>)span, values);

/// <summary>
/// Searches for the first index of any of the specified substring values.
/// </summary>
/// <param name="span">The span to search.</param>
/// <param name="values">The set of values to search for.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfAny(this Span<char> span, SearchValues<string> values) =>
IndexOfAny((ReadOnlySpan<char>)span, values);

/// <summary>
/// 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.
/// </summary>
Expand Down Expand Up @@ -2061,6 +2084,22 @@ public static unsafe int IndexOfAny<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T
public static int IndexOfAny<T>(this ReadOnlySpan<T> span, SearchValues<T> values) where T : IEquatable<T>? =>
SearchValues<T>.IndexOfAny(span, values);

/// <summary>
/// Searches for the first index of any of the specified substring values.
/// </summary>
/// <param name="span">The span to search.</param>
/// <param name="values">The set of values to search for.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfAny(this ReadOnlySpan<char> span, SearchValues<string> values)
{
if (values is null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values);
}

return values.IndexOfAnyMultiString(span);
}

/// <summary>
/// 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.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@ internal override int LastIndexOfAny(ReadOnlySpan<T> span) =>

internal override int LastIndexOfAnyExcept(ReadOnlySpan<T> span) =>
span.Length - 1;

internal override int IndexOfAnyMultiString(ReadOnlySpan<char> span) =>
-1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ internal static class IndexOfAnyAsciiSearcher
{
internal static bool IsVectorizationSupported => Ssse3.IsSupported || AdvSimd.Arm64.IsSupported || PackedSimd.IsSupported;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool BitmapContains(ref Vector256<byte> bitmap, char c) =>
c <= 127 &&
(bitmap.GetElementUnsafe(c & 0xF) & (1 << (c >> 4))) != 0;

internal static unsafe void ComputeBitmap256(ReadOnlySpan<byte> values, out Vector256<byte> bitmap0, out Vector256<byte> bitmap1, out BitVector256 lookup)
{
// The exact format of these bitmaps differs from the other ComputeBitmap overloads as it's meant for the full [0, 255] range algorithm.
Expand Down Expand Up @@ -1023,7 +1028,7 @@ private static unsafe int ComputeFirstIndex<T, TNegator>(ref T searchSpace, ref
{
if (typeof(T) == typeof(short))
{
result = FixUpPackedVector256Result(result);
result = PackedSpanHelpers.FixUpPackedVector256Result(result);
}

uint mask = TNegator.ExtractMask(result);
Expand All @@ -1039,7 +1044,7 @@ private static unsafe int ComputeFirstIndexOverlapped<T, TNegator>(ref T searchS
{
if (typeof(T) == typeof(short))
{
result = FixUpPackedVector256Result(result);
result = PackedSpanHelpers.FixUpPackedVector256Result(result);
}

uint mask = TNegator.ExtractMask(result);
Expand All @@ -1061,7 +1066,7 @@ private static unsafe int ComputeLastIndex<T, TNegator>(ref T searchSpace, ref T
{
if (typeof(T) == typeof(short))
{
result = FixUpPackedVector256Result(result);
result = PackedSpanHelpers.FixUpPackedVector256Result(result);
}

uint mask = TNegator.ExtractMask(result);
Expand All @@ -1077,7 +1082,7 @@ private static unsafe int ComputeLastIndexOverlapped<T, TNegator>(ref T searchSp
{
if (typeof(T) == typeof(short))
{
result = FixUpPackedVector256Result(result);
result = PackedSpanHelpers.FixUpPackedVector256Result(result);
}

uint mask = TNegator.ExtractMask(result);
Expand All @@ -1092,18 +1097,6 @@ private static unsafe int ComputeLastIndexOverlapped<T, TNegator>(ref T searchSp
return offsetInVector - Vector256<short>.Count + (int)((nuint)Unsafe.ByteOffset(ref searchSpace, ref secondVector) / (nuint)sizeof(T));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
[CompExactlyDependsOn(typeof(Avx2))]
private static Vector256<byte> FixUpPackedVector256Result(Vector256<byte> result)
{
Debug.Assert(Avx2.IsSupported);
// Avx2.PackUnsignedSaturate(Vector256.Create((short)1), Vector256.Create((short)2)) will result in
// 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2
// We want to swap the X and Y bits
// 1, 1, 1, 1, 1, 1, 1, 1, X, X, X, X, X, X, X, X, Y, Y, Y, Y, Y, Y, Y, Y, 2, 2, 2, 2, 2, 2, 2, 2
return Avx2.Permute4x64(result.AsInt64(), 0b_11_01_10_00).AsByte();
}

internal interface INegator
{
static abstract bool NegateIfNeeded(bool result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,7 @@ private static int IndexOfAnyVectorized(ref uint charMap, ref char searchSpace,

if (result != Vector256<byte>.Zero)
{
// Account for how ContainsMask32CharsAvx2 packed the source chars (Avx2.PackUnsignedSaturate).
result = Avx2.Permute4x64(result.AsInt64(), 0b_11_01_10_00).AsByte();
result = PackedSpanHelpers.FixUpPackedVector256Result(result);

uint mask = result.ExtractMostSignificantBits();
do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ private protected SearchValues() { }
internal virtual int LastIndexOfAny(ReadOnlySpan<T> span) => throw new UnreachableException();
internal virtual int LastIndexOfAnyExcept(ReadOnlySpan<T> span) => throw new UnreachableException();

// This is only implemented and used by SearchValues<string>.
internal virtual int IndexOfAnyMultiString(ReadOnlySpan<char> span) => throw new UnreachableException();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int IndexOfAny(ReadOnlySpan<T> span, SearchValues<T> values)
{
Expand Down
Loading