diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/AnyByteSearchValues.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/AnyByteSearchValues.cs index a510214633fc1..d95d557bd89a4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/AnyByteSearchValues.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/AnyByteSearchValues.cs @@ -3,94 +3,56 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.Wasm; +using System.Runtime.Intrinsics.X86; namespace System.Buffers { internal sealed class AnyByteSearchValues : SearchValues { - private Vector512 _bitmaps; - private readonly BitVector256 _lookup; + private IndexOfAnyAsciiSearcher.AnyByteState _state; - public AnyByteSearchValues(ReadOnlySpan values) - { - IndexOfAnyAsciiSearcher.ComputeBitmap256(values, out Vector256 bitmap0, out Vector256 bitmap1, out _lookup); - _bitmaps = Vector512.Create(bitmap0, bitmap1); - } + public AnyByteSearchValues(ReadOnlySpan values) => + IndexOfAnyAsciiSearcher.ComputeAnyByteState(values, out _state); - internal override byte[] GetValues() => _lookup.GetByteValues(); + internal override byte[] GetValues() => + _state.Lookup.GetByteValues(); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override bool ContainsCore(byte value) => - _lookup.Contains(value); + _state.Lookup.Contains(value); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int IndexOfAny(ReadOnlySpan span) => - IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); + IndexOfAnyAsciiSearcher.IndexOfAnyVectorizedAnyByte( + ref MemoryMarshal.GetReference(span), span.Length, ref _state); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int IndexOfAnyExcept(ReadOnlySpan span) => - IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); + IndexOfAnyAsciiSearcher.IndexOfAnyVectorizedAnyByte( + ref MemoryMarshal.GetReference(span), span.Length, ref _state); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int LastIndexOfAny(ReadOnlySpan span) => - LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); + IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorizedAnyByte( + ref MemoryMarshal.GetReference(span), span.Length, ref _state); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int LastIndexOfAnyExcept(ReadOnlySpan span) => - LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int IndexOfAny(ref byte searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= sizeof(ulong) - ? IndexOfAnyAsciiSearcher.IndexOfAnyVectorizedAnyByte(ref searchSpace, searchSpaceLength, ref _bitmaps) - : IndexOfAnyScalar(ref searchSpace, searchSpaceLength); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int LastIndexOfAny(ref byte searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= sizeof(ulong) - ? IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorizedAnyByte(ref searchSpace, searchSpaceLength, ref _bitmaps) - : LastIndexOfAnyScalar(ref searchSpace, searchSpaceLength); - } - - private int IndexOfAnyScalar(ref byte searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - ref byte searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength); - ref byte cur = ref searchSpace; - - while (!Unsafe.AreSame(ref cur, ref searchSpaceEnd)) - { - byte b = cur; - if (TNegator.NegateIfNeeded(_lookup.Contains(b))) - { - return (int)Unsafe.ByteOffset(ref searchSpace, ref cur); - } - - cur = ref Unsafe.Add(ref cur, 1); - } - - return -1; - } - - private int LastIndexOfAnyScalar(ref byte searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - for (int i = searchSpaceLength - 1; i >= 0; i--) - { - byte b = Unsafe.Add(ref searchSpace, i); - if (TNegator.NegateIfNeeded(_lookup.Contains(b))) - { - return i; - } - } - - return -1; - } + IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorizedAnyByte( + ref MemoryMarshal.GetReference(span), span.Length, ref _state); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/AsciiByteSearchValues.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/AsciiByteSearchValues.cs index 371695e272c8a..3fc67d6086a19 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/AsciiByteSearchValues.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/AsciiByteSearchValues.cs @@ -3,91 +3,56 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.Wasm; +using System.Runtime.Intrinsics.X86; namespace System.Buffers { internal sealed class AsciiByteSearchValues : SearchValues { - private Vector256 _bitmap; - private readonly BitVector256 _lookup; + private IndexOfAnyAsciiSearcher.AsciiState _state; public AsciiByteSearchValues(ReadOnlySpan values) => - IndexOfAnyAsciiSearcher.ComputeBitmap(values, out _bitmap, out _lookup); + IndexOfAnyAsciiSearcher.ComputeAsciiState(values, out _state); - internal override byte[] GetValues() => _lookup.GetByteValues(); + internal override byte[] GetValues() => + _state.Lookup.GetByteValues(); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override bool ContainsCore(byte value) => - _lookup.Contains(value); + _state.Lookup.Contains(value); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int IndexOfAny(ReadOnlySpan span) => - IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); + IndexOfAnyAsciiSearcher.IndexOfAnyVectorized( + ref MemoryMarshal.GetReference(span), span.Length, ref _state); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int IndexOfAnyExcept(ReadOnlySpan span) => - IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); + IndexOfAnyAsciiSearcher.IndexOfAnyVectorized( + ref MemoryMarshal.GetReference(span), span.Length, ref _state); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int LastIndexOfAny(ReadOnlySpan span) => - LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); + IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized( + ref MemoryMarshal.GetReference(span), span.Length, ref _state); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int LastIndexOfAnyExcept(ReadOnlySpan span) => - LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int IndexOfAny(ref byte searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= sizeof(ulong) - ? IndexOfAnyAsciiSearcher.IndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref _bitmap) - : IndexOfAnyScalar(ref searchSpace, searchSpaceLength); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int LastIndexOfAny(ref byte searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= sizeof(ulong) - ? IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref _bitmap) - : LastIndexOfAnyScalar(ref searchSpace, searchSpaceLength); - } - - private int IndexOfAnyScalar(ref byte searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - ref byte searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength); - ref byte cur = ref searchSpace; - - while (!Unsafe.AreSame(ref cur, ref searchSpaceEnd)) - { - byte b = cur; - if (TNegator.NegateIfNeeded(_lookup.Contains(b))) - { - return (int)Unsafe.ByteOffset(ref searchSpace, ref cur); - } - - cur = ref Unsafe.Add(ref cur, 1); - } - - return -1; - } - - private int LastIndexOfAnyScalar(ref byte searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - for (int i = searchSpaceLength - 1; i >= 0; i--) - { - byte b = Unsafe.Add(ref searchSpace, i); - if (TNegator.NegateIfNeeded(_lookup.Contains(b))) - { - return i; - } - } - - return -1; - } + IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized( + ref MemoryMarshal.GetReference(span), span.Length, ref _state); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/AsciiCharSearchValues.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/AsciiCharSearchValues.cs index 150512672a457..4df9f55252f19 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/AsciiCharSearchValues.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/AsciiCharSearchValues.cs @@ -3,95 +3,57 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.Wasm; +using System.Runtime.Intrinsics.X86; namespace System.Buffers { internal sealed class AsciiCharSearchValues : SearchValues where TOptimizations : struct, IndexOfAnyAsciiSearcher.IOptimizations { - private Vector256 _bitmap; - private readonly BitVector256 _lookup; + private IndexOfAnyAsciiSearcher.AsciiState _state; - public AsciiCharSearchValues(Vector256 bitmap, BitVector256 lookup) - { - _bitmap = bitmap; - _lookup = lookup; - } + public AsciiCharSearchValues(ReadOnlySpan values) => + IndexOfAnyAsciiSearcher.ComputeAsciiState(values, out _state); - internal override char[] GetValues() => _lookup.GetCharValues(); + internal override char[] GetValues() => + _state.Lookup.GetCharValues(); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override bool ContainsCore(char value) => - _lookup.Contains128(value); + _state.Lookup.Contains128(value); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int IndexOfAny(ReadOnlySpan span) => - IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); + IndexOfAnyAsciiSearcher.IndexOfAnyVectorized( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, ref _state); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int IndexOfAnyExcept(ReadOnlySpan span) => - IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); + IndexOfAnyAsciiSearcher.IndexOfAnyVectorized( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, ref _state); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int LastIndexOfAny(ReadOnlySpan span) => - LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); + IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, ref _state); + [CompExactlyDependsOn(typeof(Ssse3))] + [CompExactlyDependsOn(typeof(AdvSimd))] + [CompExactlyDependsOn(typeof(PackedSimd))] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override int LastIndexOfAnyExcept(ReadOnlySpan span) => - LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int IndexOfAny(ref char searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= Vector128.Count - ? IndexOfAnyAsciiSearcher.IndexOfAnyVectorized(ref Unsafe.As(ref searchSpace), searchSpaceLength, ref _bitmap) - : IndexOfAnyScalar(ref searchSpace, searchSpaceLength); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int LastIndexOfAny(ref char searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= Vector128.Count - ? IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized(ref Unsafe.As(ref searchSpace), searchSpaceLength, ref _bitmap) - : LastIndexOfAnyScalar(ref searchSpace, searchSpaceLength); - } - - private int IndexOfAnyScalar(ref char searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - ref char searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength); - ref char cur = ref searchSpace; - - while (!Unsafe.AreSame(ref cur, ref searchSpaceEnd)) - { - char c = cur; - if (TNegator.NegateIfNeeded(_lookup.Contains128(c))) - { - return (int)((nuint)Unsafe.ByteOffset(ref searchSpace, ref cur) / sizeof(char)); - } - - cur = ref Unsafe.Add(ref cur, 1); - } - - return -1; - } - - private int LastIndexOfAnyScalar(ref char searchSpace, int searchSpaceLength) - where TNegator : struct, IndexOfAnyAsciiSearcher.INegator - { - for (int i = searchSpaceLength - 1; i >= 0; i--) - { - char c = Unsafe.Add(ref searchSpace, i); - if (TNegator.NegateIfNeeded(_lookup.Contains128(c))) - { - return i; - } - } - - return -1; - } + IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, ref _state); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/BitVector256.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/BitVector256.cs index a276d0dc2996a..56e68907c86d7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/BitVector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/BitVector256.cs @@ -11,6 +11,18 @@ internal unsafe struct BitVector256 { private fixed uint _values[8]; + public readonly BitVector256 CreateInverse() + { + BitVector256 inverse = default; + + for (int i = 0; i < 8; i++) + { + inverse._values[i] = ~_values[i]; + } + + return inverse; + } + public void Set(int c) { Debug.Assert(c < 256); diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs index f98d6a580d487..4f3ff556492ff 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.Numerics; -using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; @@ -17,14 +16,25 @@ namespace System.Buffers { internal static class IndexOfAnyAsciiSearcher { - internal static bool IsVectorizationSupported => Ssse3.IsSupported || AdvSimd.Arm64.IsSupported || PackedSimd.IsSupported; + public struct AsciiState(Vector128 bitmap, BitVector256 lookup) + { + public Vector256 Bitmap = Vector256.Create(bitmap, bitmap); + public BitVector256 Lookup = lookup; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool BitmapContains(ref Vector256 bitmap, char c) => - c <= 127 && - (bitmap.GetElementUnsafe(c & 0xF) & (1 << (c >> 4))) != 0; + public readonly AsciiState CreateInverse() => + new AsciiState(~Bitmap._lower, Lookup.CreateInverse()); + } + + public struct AnyByteState(Vector128 bitmap0, Vector128 bitmap1, BitVector256 lookup) + { + public Vector256 Bitmap0 = Vector256.Create(bitmap0, bitmap0); + public Vector256 Bitmap1 = Vector256.Create(bitmap1, bitmap1); + public BitVector256 Lookup = lookup; + } + + internal static bool IsVectorizationSupported => Ssse3.IsSupported || AdvSimd.Arm64.IsSupported || PackedSimd.IsSupported; - internal static unsafe void ComputeBitmap256(ReadOnlySpan values, out Vector256 bitmap0, out Vector256 bitmap1, out BitVector256 lookup) + internal static unsafe void ComputeAnyByteState(ReadOnlySpan values, out AnyByteState state) { // The exact format of these bitmaps differs from the other ComputeBitmap overloads as it's meant for the full [0, 255] range algorithm. // See http://0x80.pl/articles/simd-byte-lookup.html#universal-algorithm @@ -52,12 +62,10 @@ internal static unsafe void ComputeBitmap256(ReadOnlySpan values, out Vect } } - bitmap0 = Vector256.Create(bitmapSpace0, bitmapSpace0); - bitmap1 = Vector256.Create(bitmapSpace1, bitmapSpace1); - lookup = lookupLocal; + state = new AnyByteState(bitmapSpace0, bitmapSpace1, lookupLocal); } - internal static unsafe void ComputeBitmap(ReadOnlySpan values, out Vector256 bitmap, out BitVector256 lookup) + internal static unsafe void ComputeAsciiState(ReadOnlySpan values, out AsciiState state) where T : struct, IUnsignedNumber { Debug.Assert(typeof(T) == typeof(byte) || typeof(T) == typeof(char)); @@ -83,8 +91,7 @@ internal static unsafe void ComputeBitmap(ReadOnlySpan values, out Vector2 bitmapLocal[(uint)lowNibble] |= (byte)(1 << highNibble); } - bitmap = Vector256.Create(bitmapSpace, bitmapSpace); - lookup = lookupLocal; + state = new AsciiState(bitmapSpace, lookupLocal); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -134,14 +141,17 @@ private static unsafe bool TryIndexOfAny(ref short searchSpace, int se if (IsVectorizationSupported) { - Vector128 bitmap = default; - if (TryComputeBitmap(asciiValues, (byte*)&bitmap, out bool needleContainsZero)) + AsciiState state = default; + + if (TryComputeBitmap(asciiValues, (byte*)&state.Bitmap._lower, out bool needleContainsZero)) { - Vector256 bitmap256 = Vector256.Create(bitmap, bitmap); + // Only initializing the bitmap here is okay as we can only get here if the search space is long enough + // and we support vectorization, so the IndexOfAnyVectorized implementation will never touch state.Lookup. + state.Bitmap = Vector256.Create(state.Bitmap._lower, state.Bitmap._lower); index = (Ssse3.IsSupported || PackedSimd.IsSupported) && needleContainsZero - ? IndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref bitmap256) - : IndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref bitmap256); + ? IndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref state) + : IndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref state); return true; } } @@ -158,14 +168,17 @@ private static unsafe bool TryLastIndexOfAny(ref short searchSpace, in if (IsVectorizationSupported) { - Vector128 bitmap = default; - if (TryComputeBitmap(asciiValues, (byte*)&bitmap, out bool needleContainsZero)) + AsciiState state = default; + + if (TryComputeBitmap(asciiValues, (byte*)&state.Bitmap._lower, out bool needleContainsZero)) { - Vector256 bitmap256 = Vector256.Create(bitmap, bitmap); + // Only initializing the bitmap here is okay as we can only get here if the search space is long enough + // and we support vectorization, so the LastIndexOfAnyVectorized implementation will never touch state.Lookup. + state.Bitmap = Vector256.Create(state.Bitmap._lower, state.Bitmap._lower); index = (Ssse3.IsSupported || PackedSimd.IsSupported) && needleContainsZero - ? LastIndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref bitmap256) - : LastIndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref bitmap256); + ? LastIndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref state) + : LastIndexOfAnyVectorized(ref searchSpace, searchSpaceLength, ref state); return true; } } @@ -177,17 +190,35 @@ private static unsafe bool TryLastIndexOfAny(ref short searchSpace, in [CompExactlyDependsOn(typeof(Ssse3))] [CompExactlyDependsOn(typeof(AdvSimd))] [CompExactlyDependsOn(typeof(PackedSimd))] - internal static int IndexOfAnyVectorized(ref short searchSpace, int searchSpaceLength, ref Vector256 bitmapRef) + internal static int IndexOfAnyVectorized(ref short searchSpace, int searchSpaceLength, ref AsciiState state) where TNegator : struct, INegator where TOptimizations : struct, IOptimizations { ref short currentSearchSpace = ref searchSpace; + if (searchSpaceLength < Vector128.Count) + { + ref short searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength); + + while (!Unsafe.AreSame(ref currentSearchSpace, ref searchSpaceEnd)) + { + char c = (char)currentSearchSpace; + if (TNegator.NegateIfNeeded(state.Lookup.Contains128(c))) + { + return (int)((nuint)Unsafe.ByteOffset(ref searchSpace, ref currentSearchSpace) / sizeof(char)); + } + + currentSearchSpace = ref Unsafe.Add(ref currentSearchSpace, 1); + } + + return -1; + } + #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough // The behavior of the rest of the function remains the same if Avx2.IsSupported is false if (Avx2.IsSupported && searchSpaceLength > 2 * Vector128.Count) #pragma warning restore IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough { - Vector256 bitmap256 = bitmapRef; + Vector256 bitmap256 = state.Bitmap; if (searchSpaceLength > 2 * Vector256.Count) { @@ -238,7 +269,7 @@ internal static int IndexOfAnyVectorized(ref short sea return -1; } - Vector128 bitmap = bitmapRef._lower; + Vector128 bitmap = state.Bitmap._lower; #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough // The behavior of the rest of the function remains the same if Avx2.IsSupported is false if (!Avx2.IsSupported && searchSpaceLength > 2 * Vector128.Count) @@ -294,17 +325,31 @@ internal static int IndexOfAnyVectorized(ref short sea [CompExactlyDependsOn(typeof(Ssse3))] [CompExactlyDependsOn(typeof(AdvSimd))] [CompExactlyDependsOn(typeof(PackedSimd))] - internal static int LastIndexOfAnyVectorized(ref short searchSpace, int searchSpaceLength, ref Vector256 bitmapRef) + internal static int LastIndexOfAnyVectorized(ref short searchSpace, int searchSpaceLength, ref AsciiState state) where TNegator : struct, INegator where TOptimizations : struct, IOptimizations { + if (searchSpaceLength < Vector128.Count) + { + for (int i = searchSpaceLength - 1; i >= 0; i--) + { + char c = (char)Unsafe.Add(ref searchSpace, i); + if (TNegator.NegateIfNeeded(state.Lookup.Contains128(c))) + { + return i; + } + } + + return -1; + } + ref short currentSearchSpace = ref Unsafe.Add(ref searchSpace, searchSpaceLength); #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough // The else clause is semantically equivalent if (Avx2.IsSupported && searchSpaceLength > 2 * Vector128.Count) #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough { - Vector256 bitmap256 = bitmapRef; + Vector256 bitmap256 = state.Bitmap; if (searchSpaceLength > 2 * Vector256.Count) { @@ -355,7 +400,7 @@ internal static int LastIndexOfAnyVectorized(ref short return -1; } - Vector128 bitmap = bitmapRef._lower; + Vector128 bitmap = state.Bitmap._lower; if (!Avx2.IsSupported && searchSpaceLength > 2 * Vector128.Count) { @@ -409,16 +454,34 @@ internal static int LastIndexOfAnyVectorized(ref short [CompExactlyDependsOn(typeof(Ssse3))] [CompExactlyDependsOn(typeof(AdvSimd))] [CompExactlyDependsOn(typeof(PackedSimd))] - internal static int IndexOfAnyVectorized(ref byte searchSpace, int searchSpaceLength, ref Vector256 bitmapRef) + internal static int IndexOfAnyVectorized(ref byte searchSpace, int searchSpaceLength, ref AsciiState state) where TNegator : struct, INegator { ref byte currentSearchSpace = ref searchSpace; + if (searchSpaceLength < sizeof(ulong)) + { + ref byte searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength); + + while (!Unsafe.AreSame(ref currentSearchSpace, ref searchSpaceEnd)) + { + byte b = currentSearchSpace; + if (TNegator.NegateIfNeeded(state.Lookup.Contains(b))) + { + return (int)Unsafe.ByteOffset(ref searchSpace, ref currentSearchSpace); + } + + currentSearchSpace = ref Unsafe.Add(ref currentSearchSpace, 1); + } + + return -1; + } + #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough // The behavior of the rest of the function remains the same if Avx2.IsSupported is false if (Avx2.IsSupported && searchSpaceLength > Vector128.Count) #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough { - Vector256 bitmap256 = bitmapRef; + Vector256 bitmap256 = state.Bitmap; if (searchSpaceLength > Vector256.Count) { @@ -467,7 +530,7 @@ internal static int IndexOfAnyVectorized(ref byte searchSpace, int sea return -1; } - Vector128 bitmap = bitmapRef._lower; + Vector128 bitmap = state.Bitmap._lower; if (!Avx2.IsSupported && searchSpaceLength > Vector128.Count) { @@ -519,16 +582,30 @@ internal static int IndexOfAnyVectorized(ref byte searchSpace, int sea [CompExactlyDependsOn(typeof(Ssse3))] [CompExactlyDependsOn(typeof(AdvSimd))] [CompExactlyDependsOn(typeof(PackedSimd))] - internal static int LastIndexOfAnyVectorized(ref byte searchSpace, int searchSpaceLength, ref Vector256 bitmapRef) + internal static int LastIndexOfAnyVectorized(ref byte searchSpace, int searchSpaceLength, ref AsciiState state) where TNegator : struct, INegator { + if (searchSpaceLength < sizeof(ulong)) + { + for (int i = searchSpaceLength - 1; i >= 0; i--) + { + byte b = Unsafe.Add(ref searchSpace, i); + if (TNegator.NegateIfNeeded(state.Lookup.Contains(b))) + { + return i; + } + } + + return -1; + } + ref byte currentSearchSpace = ref Unsafe.Add(ref searchSpace, searchSpaceLength); #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough // The behavior of the rest of the function remains the same if Avx2.IsSupported is false if (Avx2.IsSupported && searchSpaceLength > Vector128.Count) #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough { - Vector256 bitmap256 = bitmapRef; + Vector256 bitmap256 = state.Bitmap; if (searchSpaceLength > Vector256.Count) { @@ -577,7 +654,7 @@ internal static int LastIndexOfAnyVectorized(ref byte searchSpace, int return -1; } - Vector128 bitmap = bitmapRef._lower; + Vector128 bitmap = state.Bitmap._lower; if (!Avx2.IsSupported && searchSpaceLength > Vector128.Count) { @@ -629,17 +706,35 @@ internal static int LastIndexOfAnyVectorized(ref byte searchSpace, int [CompExactlyDependsOn(typeof(Ssse3))] [CompExactlyDependsOn(typeof(AdvSimd))] [CompExactlyDependsOn(typeof(PackedSimd))] - internal static int IndexOfAnyVectorizedAnyByte(ref byte searchSpace, int searchSpaceLength, ref Vector512 bitmapsRef) + internal static int IndexOfAnyVectorizedAnyByte(ref byte searchSpace, int searchSpaceLength, ref AnyByteState state) where TNegator : struct, INegator { ref byte currentSearchSpace = ref searchSpace; + if (!IsVectorizationSupported || searchSpaceLength < sizeof(ulong)) + { + ref byte searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength); + + while (!Unsafe.AreSame(ref currentSearchSpace, ref searchSpaceEnd)) + { + byte b = currentSearchSpace; + if (TNegator.NegateIfNeeded(state.Lookup.Contains(b))) + { + return (int)Unsafe.ByteOffset(ref searchSpace, ref currentSearchSpace); + } + + currentSearchSpace = ref Unsafe.Add(ref currentSearchSpace, 1); + } + + return -1; + } + #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough // The behavior of the rest of the function remains the same if Avx2.IsSupported is false if (Avx2.IsSupported && searchSpaceLength > Vector128.Count) #pragma warning restore IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough { - Vector256 bitmap256_0 = bitmapsRef._lower; - Vector256 bitmap256_1 = bitmapsRef._upper; + Vector256 bitmap256_0 = state.Bitmap0; + Vector256 bitmap256_1 = state.Bitmap1; if (searchSpaceLength > Vector256.Count) { @@ -688,8 +783,8 @@ internal static int IndexOfAnyVectorizedAnyByte(ref byte searchSpace, return -1; } - Vector128 bitmap0 = bitmapsRef._lower._lower; - Vector128 bitmap1 = bitmapsRef._upper._lower; + Vector128 bitmap0 = state.Bitmap0._lower; + Vector128 bitmap1 = state.Bitmap1._lower; #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough // The behavior of the rest of the function remains the same if Avx2.IsSupported is false if (!Avx2.IsSupported && searchSpaceLength > Vector128.Count) @@ -743,17 +838,31 @@ internal static int IndexOfAnyVectorizedAnyByte(ref byte searchSpace, [CompExactlyDependsOn(typeof(Ssse3))] [CompExactlyDependsOn(typeof(AdvSimd))] [CompExactlyDependsOn(typeof(PackedSimd))] - internal static int LastIndexOfAnyVectorizedAnyByte(ref byte searchSpace, int searchSpaceLength, ref Vector512 bitmapsRef) + internal static int LastIndexOfAnyVectorizedAnyByte(ref byte searchSpace, int searchSpaceLength, ref AnyByteState state) where TNegator : struct, INegator { + if (!IsVectorizationSupported || searchSpaceLength < sizeof(ulong)) + { + for (int i = searchSpaceLength - 1; i >= 0; i--) + { + byte b = Unsafe.Add(ref searchSpace, i); + if (TNegator.NegateIfNeeded(state.Lookup.Contains(b))) + { + return i; + } + } + + return -1; + } + ref byte currentSearchSpace = ref Unsafe.Add(ref searchSpace, searchSpaceLength); #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough // The behavior of the rest of the function remains the same if Avx2.IsSupported is false if (Avx2.IsSupported && searchSpaceLength > Vector128.Count) { #pragma warning restore IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough - Vector256 bitmap256_0 = bitmapsRef._lower; - Vector256 bitmap256_1 = bitmapsRef._upper; + Vector256 bitmap256_0 = state.Bitmap0; + Vector256 bitmap256_1 = state.Bitmap1; if (searchSpaceLength > Vector256.Count) { @@ -802,8 +911,8 @@ internal static int LastIndexOfAnyVectorizedAnyByte(ref byte searchSpa return -1; } - Vector128 bitmap0 = bitmapsRef._lower._lower; - Vector128 bitmap1 = bitmapsRef._upper._lower; + Vector128 bitmap0 = state.Bitmap0._lower; + Vector128 bitmap1 = state.Bitmap1._lower; #pragma warning disable IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough // The behavior of the rest of the function remains the same if Avx2.IsSupported is false if (!Avx2.IsSupported && searchSpaceLength > Vector128.Count) diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticWithAsciiCharSearchValues.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticWithAsciiCharSearchValues.cs index 8a8f09a0d327f..419a57c50283e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticWithAsciiCharSearchValues.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticWithAsciiCharSearchValues.cs @@ -13,8 +13,8 @@ namespace System.Buffers internal sealed class ProbabilisticWithAsciiCharSearchValues : SearchValues where TOptimizations : struct, IndexOfAnyAsciiSearcher.IOptimizations { - private Vector256 _asciiBitmap; - private Vector256 _inverseAsciiBitmap; + private IndexOfAnyAsciiSearcher.AsciiState _asciiState; + private IndexOfAnyAsciiSearcher.AsciiState _inverseAsciiState; private ProbabilisticMap _map; private readonly string _values; @@ -23,8 +23,8 @@ public ProbabilisticWithAsciiCharSearchValues(scoped ReadOnlySpan values) Debug.Assert(IndexOfAnyAsciiSearcher.IsVectorizationSupported); Debug.Assert(values.ContainsAnyInRange((char)0, (char)127)); - IndexOfAnyAsciiSearcher.ComputeBitmap(values, out _asciiBitmap, out _); - _inverseAsciiBitmap = ~_asciiBitmap; + IndexOfAnyAsciiSearcher.ComputeAsciiState(values, out _asciiState); + _inverseAsciiState = _asciiState.CreateInverse(); _values = new string(values); _map = new ProbabilisticMap(_values); @@ -48,29 +48,29 @@ internal override int IndexOfAny(ReadOnlySpan span) // We do this by inverting the bitmap and using the opposite search function (Negate instead of DontNegate). // If the bitmap we're using contains a 0, we have to use 'Ssse3AndWasmHandleZeroInNeedle' when running on X86 and WASM. - // Everything else should use 'Default'. 'TOptimizations' specifies whether '_asciiBitmap' contains a 0. + // Everything else should use 'Default'. 'TOptimizations' specifies whether '_asciiState' contains a 0. // Since we're using the inverse bitmap in this case, we have to use 'Ssse3AndWasmHandleZeroInNeedle' iff we're // running on X86/WASM and 'TOptimizations' is 'Default' (as that means that the inverse bitmap definitely has a 0). - Debug.Assert((_asciiBitmap[0] & 1) != (_inverseAsciiBitmap[0] & 1)); + Debug.Assert(_asciiState.Lookup.Contains(0) != _inverseAsciiState.Lookup.Contains(0)); if ((Ssse3.IsSupported || PackedSimd.IsSupported) && typeof(TOptimizations) == typeof(IndexOfAnyAsciiSearcher.Default)) { - Debug.Assert((_inverseAsciiBitmap[0] & 1) == 1, "The inverse bitmap did not contain a 0."); + Debug.Assert(_inverseAsciiState.Lookup.Contains(0), "The inverse bitmap did not contain a 0."); offset = IndexOfAnyAsciiSearcher.IndexOfAnyVectorized( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, - ref _inverseAsciiBitmap); + ref _inverseAsciiState); } else { - Debug.Assert(!(Ssse3.IsSupported || PackedSimd.IsSupported) || (_inverseAsciiBitmap[0] & 1) == 0, + Debug.Assert(!(Ssse3.IsSupported || PackedSimd.IsSupported) || !_inverseAsciiState.Lookup.Contains(0), "The inverse bitmap contained a 0, but we're not using Ssse3AndWasmHandleZeroInNeedle."); offset = IndexOfAnyAsciiSearcher.IndexOfAnyVectorized( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, - ref _inverseAsciiBitmap); + ref _inverseAsciiState); } // If we've reached the end of the span or stopped at an ASCII character, we've found the result. @@ -110,7 +110,7 @@ internal override int IndexOfAnyExcept(ReadOnlySpan span) offset = IndexOfAnyAsciiSearcher.IndexOfAnyVectorized( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, - ref _asciiBitmap); + ref _asciiState); // If we've reached the end of the span or stopped at an ASCII character, we've found the result. if ((uint)offset >= (uint)span.Length || char.IsAscii(span[offset])) @@ -146,31 +146,31 @@ internal override int LastIndexOfAny(ReadOnlySpan span) // We do this by inverting the bitmap and using the opposite search function (Negate instead of DontNegate). // If the bitmap we're using contains a 0, we have to use 'Ssse3AndWasmHandleZeroInNeedle' when running on X86 and WASM. - // Everything else should use 'Default'. 'TOptimizations' specifies whether '_asciiBitmap' contains a 0. + // Everything else should use 'Default'. 'TOptimizations' specifies whether '_asciiState' contains a 0. // Since we're using the inverse bitmap in this case, we have to use 'Ssse3AndWasmHandleZeroInNeedle' iff we're // running on X86/WASM and 'TOptimizations' is 'Default' (as that means that the inverse bitmap definitely has a 0). - Debug.Assert((_asciiBitmap[0] & 1) != (_inverseAsciiBitmap[0] & 1)); + Debug.Assert(_asciiState.Lookup.Contains(0) != _inverseAsciiState.Lookup.Contains(0)); int offset; if ((Ssse3.IsSupported || PackedSimd.IsSupported) && typeof(TOptimizations) == typeof(IndexOfAnyAsciiSearcher.Default)) { - Debug.Assert((_inverseAsciiBitmap[0] & 1) == 1, "The inverse bitmap did not contain a 0."); + Debug.Assert(_inverseAsciiState.Lookup.Contains(0), "The inverse bitmap did not contain a 0."); offset = IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, - ref _inverseAsciiBitmap); + ref _inverseAsciiState); } else { - Debug.Assert(!(Ssse3.IsSupported || PackedSimd.IsSupported) || (_inverseAsciiBitmap[0] & 1) == 0, + Debug.Assert(!(Ssse3.IsSupported || PackedSimd.IsSupported) ||!_inverseAsciiState.Lookup.Contains(0), "The inverse bitmap contained a 0, but we're not using Ssse3AndWasmHandleZeroInNeedle."); offset = IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, - ref _inverseAsciiBitmap); + ref _inverseAsciiState); } // If we've reached the end of the span or stopped at an ASCII character, we've found the result. @@ -200,7 +200,7 @@ internal override int LastIndexOfAnyExcept(ReadOnlySpan span) int offset = IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length, - ref _asciiBitmap); + ref _asciiState); // If we've reached the end of the span or stopped at an ASCII character, we've found the result. if ((uint)offset >= (uint)span.Length || char.IsAscii(span[offset])) diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/SearchValues.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/SearchValues.cs index 9e606749dc925..13c6779a7d985 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/SearchValues.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/SearchValues.cs @@ -113,11 +113,9 @@ public static SearchValues Create(ReadOnlySpan values) // IndexOfAnyAsciiSearcher for chars is slower than Any3CharSearchValues, but faster than Any4SearchValues if (IndexOfAnyAsciiSearcher.IsVectorizationSupported && maxInclusive < 128) { - IndexOfAnyAsciiSearcher.ComputeBitmap(values, out Vector256 bitmap, out BitVector256 lookup); - - return (Ssse3.IsSupported || PackedSimd.IsSupported) && lookup.Contains(0) - ? new AsciiCharSearchValues(bitmap, lookup) - : new AsciiCharSearchValues(bitmap, lookup); + return (Ssse3.IsSupported || PackedSimd.IsSupported) && minInclusive == 0 + ? new AsciiCharSearchValues(values) + : new AsciiCharSearchValues(values); } // Vector128 isn't valid. Treat the values as shorts instead. diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasick.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasick.cs index 8bedbe3bb47f3..435737f5d2f9b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasick.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasick.cs @@ -18,21 +18,19 @@ namespace System.Buffers internal readonly struct AhoCorasick { private readonly AhoCorasickNode[] _nodes; - private readonly Vector256 _startingCharsAsciiBitmap; + private readonly IndexOfAnyAsciiSearcher.AsciiState _startingAsciiChars; - public AhoCorasick(AhoCorasickNode[] nodes, Vector256 startingAsciiBitmap) + public AhoCorasick(AhoCorasickNode[] nodes, IndexOfAnyAsciiSearcher.AsciiState startingAsciiChars) { _nodes = nodes; - _startingCharsAsciiBitmap = startingAsciiBitmap; + _startingAsciiChars = startingAsciiChars; } public readonly bool ShouldUseAsciiFastScan { get { - Vector256 bitmap = _startingCharsAsciiBitmap; - - if (IndexOfAnyAsciiSearcher.IsVectorizationSupported && bitmap != default) + if (IndexOfAnyAsciiSearcher.IsVectorizationSupported && _startingAsciiChars.Bitmap != default) { // If there are a lot of starting characters such that we often find one early, // the ASCII fast scan may end up performing worse than checking one character at a time. @@ -51,7 +49,7 @@ public readonly bool ShouldUseAsciiFastScan for (int i = 0; i < 128; i++) { - if (IndexOfAnyAsciiSearcher.BitmapContains(ref bitmap, (char)i)) + if (_startingAsciiChars.Lookup.Contains128((char)i)) { frequency += CharacterFrequencyHelper.AsciiFrequency[i]; } @@ -101,7 +99,7 @@ private readonly int IndexOfAnyCore(ReadOnly int offset = IndexOfAnyAsciiSearcher.IndexOfAnyVectorized( ref Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), i)), remainingLength, - ref Unsafe.AsRef(in _startingCharsAsciiBitmap)); + ref Unsafe.AsRef(in _startingAsciiChars)); if (offset < 0) { @@ -210,7 +208,7 @@ private readonly int IndexOfAnyCaseInsensitiveUnicode(ReadOnly int offset = IndexOfAnyAsciiSearcher.IndexOfAnyVectorized( ref Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), i)), remainingLength, - ref Unsafe.AsRef(in _startingCharsAsciiBitmap)); + ref Unsafe.AsRef(in _startingAsciiChars)); if (offset < 0) { diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickBuilder.cs index 686525e19e466..ce91f45c2447d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickBuilder.cs @@ -17,7 +17,7 @@ internal ref struct AhoCorasickBuilder private readonly bool _ignoreCase; private ValueListBuilder _nodes; private ValueListBuilder _parents; - private Vector256 _startingCharsAsciiBitmap; + private IndexOfAnyAsciiSearcher.AsciiState _startingAsciiChars; public AhoCorasickBuilder(ReadOnlySpan values, bool ignoreCase, ref HashSet? unreachableValues) { @@ -53,7 +53,7 @@ public AhoCorasick Build() GenerateStartingAsciiCharsBitmap(); } - return new AhoCorasick(_nodes.AsSpan().ToArray(), _startingCharsAsciiBitmap); + return new AhoCorasick(_nodes.AsSpan().ToArray(), _startingAsciiChars); } public void Dispose() @@ -215,7 +215,7 @@ private void GenerateStartingAsciiCharsBitmap() if (Ascii.IsValid(startingChars.AsSpan())) { - IndexOfAnyAsciiSearcher.ComputeBitmap(startingChars.AsSpan(), out _startingCharsAsciiBitmap, out _); + IndexOfAnyAsciiSearcher.ComputeAsciiState(startingChars.AsSpan(), out _startingAsciiChars); } startingChars.Dispose();