diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs index 8ff89d5bc8e21b..3d0fa0939f04d8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs @@ -40,7 +40,8 @@ public static int IndexOf(ref char searchSpace, int searchSpaceLength, ref char while (remainingSearchSpaceLength > 0) { // Do a quick search for the first element of "value". - int relativeIndex = IndexOfChar(ref Unsafe.Add(ref searchSpace, offset), valueHead, remainingSearchSpaceLength); + // Using the non-packed variant as the input is short and would not benefit from the packed implementation. + int relativeIndex = NonPackedIndexOfChar(ref Unsafe.Add(ref searchSpace, offset), valueHead, remainingSearchSpaceLength); if (relativeIndex < 0) break; diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs index 3347348ee187a1..fdac45288f96b9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs @@ -24,11 +24,14 @@ internal static partial class PackedSpanHelpers // Not all values can benefit from packing the searchSpace. See comments in PackSources below. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe bool CanUsePackedIndexOf(T value) => - PackedIndexOfIsSupported && - RuntimeHelpers.IsBitwiseEquatable() && - sizeof(T) == sizeof(ushort) && - *(ushort*)&value - 1u < 254u; + public static unsafe bool CanUsePackedIndexOf(T value) + { + Debug.Assert(PackedIndexOfIsSupported); + Debug.Assert(RuntimeHelpers.IsBitwiseEquatable()); + Debug.Assert(sizeof(T) == sizeof(ushort)); + + return *(ushort*)&value - 1u < 254u; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int IndexOf(ref char searchSpace, char value, int length) => diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs index 9e0fc123ffc8c7..e45c796e611d2b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs @@ -1306,7 +1306,7 @@ public static int SequenceCompareTo(ref T first, int firstLength, ref T secon [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static unsafe bool ContainsValueType(ref T searchSpace, T value, int length) where T : struct, INumber { - if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value)) + if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(T) == typeof(short) && PackedSpanHelpers.CanUsePackedIndexOf(value)) { return PackedSpanHelpers.Contains(ref Unsafe.As(ref searchSpace), *(short*)&value, length); } @@ -1435,6 +1435,10 @@ internal static bool NonPackedContainsValueType(ref T searchSpace, T value, i internal static int IndexOfChar(ref char searchSpace, char value, int length) => IndexOfValueType(ref Unsafe.As(ref searchSpace), (short)value, length); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static int NonPackedIndexOfChar(ref char searchSpace, char value, int length) => + NonPackedIndexOfValueType>(ref Unsafe.As(ref searchSpace), (short)value, length); + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int IndexOfValueType(ref T searchSpace, T value, int length) where T : struct, INumber => IndexOfValueType>(ref searchSpace, value, length); @@ -1448,7 +1452,7 @@ private static unsafe int IndexOfValueType(ref TValue searchSp where TValue : struct, INumber where TNegator : struct, INegator { - if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value)) + if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(TValue) == typeof(short) && PackedSpanHelpers.CanUsePackedIndexOf(value)) { return typeof(TNegator) == typeof(DontNegate) ? PackedSpanHelpers.IndexOf(ref Unsafe.As(ref searchSpace), *(char*)&value, length) @@ -1605,7 +1609,7 @@ private static unsafe int IndexOfAnyValueType(ref TValue searc where TValue : struct, INumber where TNegator : struct, INegator { - if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1)) + if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(TValue) == typeof(short) && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1)) { return typeof(TNegator) == typeof(DontNegate) ? PackedSpanHelpers.IndexOfAny(ref Unsafe.As(ref searchSpace), *(char*)&value0, *(char*)&value1, length) @@ -1782,7 +1786,7 @@ private static unsafe int IndexOfAnyValueType(ref TValue searc where TValue : struct, INumber where TNegator : struct, INegator { - if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1) && PackedSpanHelpers.CanUsePackedIndexOf(value2)) + if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(TValue) == typeof(short) && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1) && PackedSpanHelpers.CanUsePackedIndexOf(value2)) { return typeof(TNegator) == typeof(DontNegate) ? PackedSpanHelpers.IndexOfAny(ref Unsafe.As(ref searchSpace), *(char*)&value0, *(char*)&value1, *(char*)&value2, length) @@ -3085,7 +3089,7 @@ private static unsafe int IndexOfAnyInRangeUnsignedNumber(ref T sea where T : struct, IUnsignedNumber, IComparisonOperators where TNegator : struct, INegator { - if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(lowInclusive) && PackedSpanHelpers.CanUsePackedIndexOf(highInclusive) && highInclusive >= lowInclusive) + if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(T) == typeof(ushort) && PackedSpanHelpers.CanUsePackedIndexOf(lowInclusive) && PackedSpanHelpers.CanUsePackedIndexOf(highInclusive) && highInclusive >= lowInclusive) { ref char charSearchSpace = ref Unsafe.As(ref searchSpace); char charLowInclusive = *(char*)&lowInclusive; diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs index 5fad371ac5e73e..61aa3bf6b42793 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -1074,15 +1074,32 @@ public string Replace(string oldValue, string? newValue) // Find all occurrences of the oldValue character. char c = oldValue[0]; int i = 0; - while (true) + + if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(c)) { - int pos = SpanHelpers.IndexOfChar(ref Unsafe.Add(ref _firstChar, i), c, Length - i); - if (pos < 0) + while (true) { - break; + int pos = PackedSpanHelpers.IndexOf(ref Unsafe.Add(ref _firstChar, i), c, Length - i); + if (pos < 0) + { + break; + } + replacementIndices.Append(i + pos); + i += pos + 1; + } + } + else + { + while (true) + { + int pos = SpanHelpers.NonPackedIndexOfChar(ref Unsafe.Add(ref _firstChar, i), c, Length - i); + if (pos < 0) + { + break; + } + replacementIndices.Append(i + pos); + i += pos + 1; } - replacementIndices.Append(i + pos); - i += pos + 1; } } else