Skip to content

Commit 5b648d1

Browse files
committed
Tweak scalar paths
1 parent 6548ed3 commit 5b648d1

10 files changed

+131
-164
lines changed

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,8 +431,8 @@
431431
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValues.cs" />
432432
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValues.T.cs" />
433433
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValuesDebugView.cs" />
434-
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfEmptyValues.cs" />
435434
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValuesInRange.cs" />
435+
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfEmptyValues.cs" />
436436
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\ProbabilisticMap.cs" />
437437
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOutOfRangeException.cs" />
438438
<Compile Include="$(MSBuildThisFileDirectory)System\InsufficientExecutionStackException.cs" />

src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/BitVector256.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,20 @@ public void Set(int c)
2121

2222
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2323
public readonly bool Contains128(char c) =>
24-
c < 128 && Contains((byte)c);
24+
c < 128 && ContainsUnchecked(c);
2525

2626
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2727
public readonly bool Contains256(char c) =>
28-
c < 256 && Contains((byte)c);
28+
c < 256 && ContainsUnchecked(c);
2929

3030
[MethodImpl(MethodImplOptions.AggressiveInlining)]
31-
public readonly bool Contains(byte b)
31+
public readonly bool Contains(byte b) =>
32+
ContainsUnchecked(b);
33+
34+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
35+
private readonly bool ContainsUnchecked(int b)
3236
{
37+
Debug.Assert(b < 256);
3338
uint offset = (uint)(b >> 5);
3439
uint significantBit = 1u << (b & 31);
3540
return (_values[offset] & significantBit) != 0;
@@ -40,7 +45,7 @@ public readonly char[] GetCharValues()
4045
var chars = new List<char>();
4146
for (int i = 0; i < 256; i++)
4247
{
43-
if (Contains((byte)i))
48+
if (ContainsUnchecked(i))
4449
{
4550
chars.Add((char)i);
4651
}
@@ -53,7 +58,7 @@ public readonly byte[] GetByteValues()
5358
var bytes = new List<byte>();
5459
for (int i = 0; i < 256; i++)
5560
{
56-
if (Contains((byte)i))
61+
if (ContainsUnchecked(i))
5762
{
5863
bytes.Add((byte)i);
5964
}

src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiByteValues.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,18 @@ private int LastIndexOfAny<TNegator>(ref byte searchSpace, int searchSpaceLength
5858
private int IndexOfAnyScalar<TNegator>(ref byte searchSpace, int searchSpaceLength)
5959
where TNegator : struct, IndexOfAnyAsciiSearcher.INegator
6060
{
61-
for (int i = 0; i < searchSpaceLength; i++)
61+
ref byte searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength);
62+
ref byte cur = ref searchSpace;
63+
64+
while (!Unsafe.AreSame(ref cur, ref searchSpaceEnd))
6265
{
63-
if (TNegator.NegateIfNeeded(_lookup.Contains(Unsafe.Add(ref searchSpace, i))))
66+
byte b = cur;
67+
if (TNegator.NegateIfNeeded(_lookup.Contains(b)))
6468
{
65-
return i;
69+
return (int)Unsafe.ByteOffset(ref searchSpace, ref cur);
6670
}
71+
72+
cur = ref Unsafe.Add(ref cur, 1);
6773
}
6874

6975
return -1;
@@ -74,7 +80,8 @@ private int LastIndexOfAnyScalar<TNegator>(ref byte searchSpace, int searchSpace
7480
{
7581
for (int i = searchSpaceLength - 1; i >= 0; i--)
7682
{
77-
if (TNegator.NegateIfNeeded(_lookup.Contains(Unsafe.Add(ref searchSpace, i))))
83+
byte b = Unsafe.Add(ref searchSpace, i);
84+
if (TNegator.NegateIfNeeded(_lookup.Contains(b)))
7885
{
7986
return i;
8087
}

src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiCharValues.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,18 @@ private int LastIndexOfAny<TNegator>(ref char searchSpace, int searchSpaceLength
5858
private int IndexOfAnyScalar<TNegator>(ref char searchSpace, int searchSpaceLength)
5959
where TNegator : struct, IndexOfAnyAsciiSearcher.INegator
6060
{
61-
for (int i = 0; i < searchSpaceLength; i++)
61+
ref char searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength);
62+
ref char cur = ref searchSpace;
63+
64+
while (!Unsafe.AreSame(ref cur, ref searchSpaceEnd))
6265
{
63-
if (TNegator.NegateIfNeeded(_lookup.Contains128(Unsafe.Add(ref searchSpace, i))))
66+
char c = cur;
67+
if (TNegator.NegateIfNeeded(_lookup.Contains128(c)))
6468
{
65-
return i;
69+
return (int)(Unsafe.ByteOffset(ref searchSpace, ref cur) / sizeof(char));
6670
}
71+
72+
cur = ref Unsafe.Add(ref cur, 1);
6773
}
6874

6975
return -1;
@@ -74,7 +80,8 @@ private int LastIndexOfAnyScalar<TNegator>(ref char searchSpace, int searchSpace
7480
{
7581
for (int i = searchSpaceLength - 1; i >= 0; i--)
7682
{
77-
if (TNegator.NegateIfNeeded(_lookup.Contains128(Unsafe.Add(ref searchSpace, i))))
83+
char c = Unsafe.Add(ref searchSpace, i);
84+
if (TNegator.NegateIfNeeded(_lookup.Contains128(c)))
7885
{
7986
return i;
8087
}

src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyByteValues.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,18 @@ private int LastIndexOfAny<TNegator>(ref byte searchSpace, int searchSpaceLength
5555
private int IndexOfAnyScalar<TNegator>(ref byte searchSpace, int searchSpaceLength)
5656
where TNegator : struct, IndexOfAnyAsciiSearcher.INegator
5757
{
58-
for (int i = 0; i < searchSpaceLength; i++)
58+
ref byte searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength);
59+
ref byte cur = ref searchSpace;
60+
61+
while (!Unsafe.AreSame(ref cur, ref searchSpaceEnd))
5962
{
60-
if (TNegator.NegateIfNeeded(_lookup.Contains(Unsafe.Add(ref searchSpace, i))))
63+
byte b = cur;
64+
if (TNegator.NegateIfNeeded(_lookup.Contains(b)))
6165
{
62-
return i;
66+
return (int)(Unsafe.ByteOffset(ref searchSpace, ref cur));
6367
}
68+
69+
cur = ref Unsafe.Add(ref cur, 1);
6470
}
6571

6672
return -1;
@@ -71,7 +77,8 @@ private int LastIndexOfAnyScalar<TNegator>(ref byte searchSpace, int searchSpace
7177
{
7278
for (int i = searchSpaceLength - 1; i >= 0; i--)
7379
{
74-
if (TNegator.NegateIfNeeded(_lookup.Contains(Unsafe.Add(ref searchSpace, i))))
80+
byte b = Unsafe.Add(ref searchSpace, i);
81+
if (TNegator.NegateIfNeeded(_lookup.Contains(b)))
7582
{
7683
return i;
7784
}

src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyCharValuesProbabilistic.cs

Lines changed: 9 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,15 @@
66

77
namespace System.Buffers
88
{
9-
internal sealed class IndexOfAnyCharValuesProbabilistic<TContains> : IndexOfAnyValues<char>
10-
where TContains : struct, IndexOfAnyValues.IStringContains
9+
internal sealed class IndexOfAnyCharValuesProbabilistic : IndexOfAnyValues<char>
1110
{
12-
private readonly ProbabilisticMap _map;
11+
private ProbabilisticMap _map;
1312
private readonly string _values;
1413

1514
public unsafe IndexOfAnyCharValuesProbabilistic(ReadOnlySpan<char> values)
1615
{
1716
_values = new string(values);
18-
19-
ProbabilisticMap map = default;
20-
ProbabilisticMap.Initialize((uint*)&map, _values);
21-
_map = map;
17+
_map = new ProbabilisticMap(_values);
2218
}
2319

2420
internal override char[] GetValues() => _values.ToCharArray();
@@ -39,44 +35,14 @@ internal override int LastIndexOfAny(ReadOnlySpan<char> span) =>
3935
internal override int LastIndexOfAnyExcept(ReadOnlySpan<char> span) =>
4036
LastIndexOfAny<IndexOfAnyAsciiSearcher.Negate>(ref MemoryMarshal.GetReference(span), span.Length);
4137

38+
[MethodImpl(MethodImplOptions.NoInlining)]
4239
private int IndexOfAny<TNegator>(ref char searchSpace, int searchSpaceLength)
43-
where TNegator : struct, IndexOfAnyAsciiSearcher.INegator
44-
{
45-
string values = _values;
46-
47-
for (int i = 0; i < searchSpaceLength; i++)
48-
{
49-
int ch = Unsafe.Add(ref searchSpace, i);
50-
if (TNegator.NegateIfNeeded(
51-
_map.IsCharBitSet((byte)ch) &&
52-
_map.IsCharBitSet((byte)(ch >> 8)) &&
53-
TContains.Contains(values, (char)ch)))
54-
{
55-
return i;
56-
}
57-
}
58-
59-
return -1;
60-
}
40+
where TNegator : struct, IndexOfAnyAsciiSearcher.INegator =>
41+
ProbabilisticMap.IndexOfAny<TNegator>(ref Unsafe.As<ProbabilisticMap, uint>(ref _map), ref searchSpace, searchSpaceLength, _values);
6142

43+
[MethodImpl(MethodImplOptions.NoInlining)]
6244
private int LastIndexOfAny<TNegator>(ref char searchSpace, int searchSpaceLength)
63-
where TNegator : struct, IndexOfAnyAsciiSearcher.INegator
64-
{
65-
string values = _values;
66-
67-
for (int i = searchSpaceLength - 1; i >= 0; i--)
68-
{
69-
int ch = Unsafe.Add(ref searchSpace, i);
70-
if (TNegator.NegateIfNeeded(
71-
_map.IsCharBitSet((byte)ch) &&
72-
_map.IsCharBitSet((byte)(ch >> 8)) &&
73-
TContains.Contains(values, (char)ch)))
74-
{
75-
return i;
76-
}
77-
}
78-
79-
return -1;
80-
}
45+
where TNegator : struct, IndexOfAnyAsciiSearcher.INegator =>
46+
ProbabilisticMap.LastIndexOfAny<TNegator>(ref Unsafe.As<ProbabilisticMap, uint>(ref _map), ref searchSpace, searchSpaceLength, _values);
8147
}
8248
}

src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyLatin1CharValues.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,18 @@ internal override int LastIndexOfAnyExcept(ReadOnlySpan<char> span) =>
4545
private int IndexOfAny<TNegator>(ref char searchSpace, int searchSpaceLength)
4646
where TNegator : struct, IndexOfAnyAsciiSearcher.INegator
4747
{
48-
for (int i = 0; i < searchSpaceLength; i++)
48+
ref char searchSpaceEnd = ref Unsafe.Add(ref searchSpace, searchSpaceLength);
49+
ref char cur = ref searchSpace;
50+
51+
while (!Unsafe.AreSame(ref cur, ref searchSpaceEnd))
4952
{
50-
if (TNegator.NegateIfNeeded(_lookup.Contains256(Unsafe.Add(ref searchSpace, i))))
53+
char c = cur;
54+
if (TNegator.NegateIfNeeded(_lookup.Contains256(c)))
5155
{
52-
return i;
56+
return (int)(Unsafe.ByteOffset(ref searchSpace, ref cur) / sizeof(char));
5357
}
58+
59+
cur = ref Unsafe.Add(ref cur, 1);
5460
}
5561

5662
return -1;
@@ -61,7 +67,8 @@ private int LastIndexOfAny<TNegator>(ref char searchSpace, int searchSpaceLength
6167
{
6268
for (int i = searchSpaceLength - 1; i >= 0; i--)
6369
{
64-
if (TNegator.NegateIfNeeded(_lookup.Contains256(Unsafe.Add(ref searchSpace, i))))
70+
char c = Unsafe.Add(ref searchSpace, i);
71+
if (TNegator.NegateIfNeeded(_lookup.Contains256(c)))
6572
{
6673
return i;
6774
}

src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyValues.cs

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,7 @@ ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(values)),
127127
return new IndexOfAnyLatin1CharValues(values);
128128
}
129129

130-
return values.Length < Vector128<short>.Count
131-
? new IndexOfAnyCharValuesProbabilistic<ShortLoopContains>(values)
132-
: new IndexOfAnyCharValuesProbabilistic<StringContains>(values);
130+
return new IndexOfAnyCharValuesProbabilistic(values);
133131
}
134132

135133
private static IndexOfAnyValues<T>? TryGetSingleRange<T>(ReadOnlySpan<T> values, out T maxInclusive)
@@ -169,32 +167,5 @@ ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(values)),
169167

170168
return (IndexOfAnyValues<T>)(object)new IndexOfAnyValuesInRange<T>(min, max);
171169
}
172-
173-
internal interface IStringContains
174-
{
175-
public static abstract bool Contains(string s, char value);
176-
}
177-
178-
private readonly struct StringContains : IStringContains
179-
{
180-
public static bool Contains(string s, char value) => s.Contains(value);
181-
}
182-
183-
private readonly struct ShortLoopContains : IStringContains
184-
{
185-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
186-
public static bool Contains(string s, char value)
187-
{
188-
foreach (char c in s)
189-
{
190-
if (value == c)
191-
{
192-
return true;
193-
}
194-
}
195-
196-
return false;
197-
}
198-
}
199170
}
200171
}

0 commit comments

Comments
 (0)