Skip to content

Commit 34ee7e0

Browse files
committed
Add PackedIndexOf for chars
1 parent b85e152 commit 34ee7e0

13 files changed

+884
-89
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,21 +421,24 @@
421421
<Compile Include="$(MSBuildThisFileDirectory)System\IFormattable.cs" />
422422
<Compile Include="$(MSBuildThisFileDirectory)System\Index.cs" />
423423
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\BitVector256.cs" />
424-
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny1Value.cs" />
425-
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny2Values.cs" />
424+
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny1CharValue.cs" />
425+
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny1ByteValue.cs" />
426+
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny2ByteValues.cs" />
427+
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny2CharValues.cs" />
426428
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny3Values.cs" />
427429
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny4Values.cs" />
428430
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny5Values.cs" />
429431
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyAsciiByteValues.cs" />
430432
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyAsciiCharValues.cs" />
431433
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyAsciiSearcher.cs" />
432434
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyByteValues.cs" />
435+
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyCharValuesInRange.cs" />
433436
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyCharValuesProbabilistic.cs" />
434437
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyLatin1CharValues.cs" />
435438
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValues.cs" />
436439
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValues.T.cs" />
437440
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValuesDebugView.cs" />
438-
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValuesInRange.cs" />
441+
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyByteValuesInRange.cs" />
439442
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfEmptyValues.cs" />
440443
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\ProbabilisticMap.cs" />
441444
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOutOfRangeException.cs" />
@@ -1028,6 +1031,7 @@
10281031
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.BinarySearch.cs" />
10291032
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Byte.cs" />
10301033
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Char.cs" />
1034+
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Char.Packed.cs" />
10311035
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.cs" />
10321036
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.T.cs" />
10331037
<Compile Include="$(MSBuildThisFileDirectory)System\SR.cs" />

src/libraries/System.Private.CoreLib/src/System/Globalization/Ordinal.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ internal static int IndexOfOrdinalIgnoreCase(ReadOnlySpan<char> source, ReadOnly
339339
{
340340
// Do a quick search for the first element of "value".
341341
int relativeIndex = isLetter ?
342-
SpanHelpers.IndexOfAnyChar(ref Unsafe.Add(ref searchSpace, offset), valueCharU, valueCharL, searchSpaceLength) :
342+
SpanHelpers.PackedIndexOfIsSupported
343+
? SpanHelpers.PackedIndexOfAny(ref Unsafe.Add(ref searchSpace, offset), valueCharU, valueCharL, searchSpaceLength)
344+
: SpanHelpers.IndexOfAnyChar(ref Unsafe.Add(ref searchSpace, offset), valueCharU, valueCharL, searchSpaceLength) :
343345
SpanHelpers.IndexOfChar(ref Unsafe.Add(ref searchSpace, offset), valueChar, searchSpaceLength);
344346
if (relativeIndex < 0)
345347
{

src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAny1Value.cs renamed to src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAny1ByteValue.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,40 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics;
5-
using System.Numerics;
65
using System.Runtime.CompilerServices;
76

87
namespace System.Buffers
98
{
10-
internal sealed class IndexOfAny1Value<T> : IndexOfAnyValues<T>
11-
where T : struct, INumber<T>
9+
internal sealed class IndexOfAny1ByteValue : IndexOfAnyValues<byte>
1210
{
13-
private readonly T _e0;
11+
private readonly byte _e0;
1412

15-
public IndexOfAny1Value(ReadOnlySpan<T> values)
13+
public IndexOfAny1ByteValue(ReadOnlySpan<byte> values)
1614
{
1715
Debug.Assert(values.Length == 1);
1816
_e0 = values[0];
1917
}
2018

21-
internal override T[] GetValues() => new[] { _e0 };
19+
internal override byte[] GetValues() => new[] { _e0 };
2220

2321
[MethodImpl(MethodImplOptions.AggressiveInlining)]
24-
internal override bool ContainsCore(T value) =>
22+
internal override bool ContainsCore(byte value) =>
2523
value == _e0;
2624

2725
[MethodImpl(MethodImplOptions.AggressiveInlining)]
28-
internal override int IndexOfAny(ReadOnlySpan<T> span) =>
26+
internal override int IndexOfAny(ReadOnlySpan<byte> span) =>
2927
span.IndexOf(_e0);
3028

3129
[MethodImpl(MethodImplOptions.AggressiveInlining)]
32-
internal override int IndexOfAnyExcept(ReadOnlySpan<T> span) =>
30+
internal override int IndexOfAnyExcept(ReadOnlySpan<byte> span) =>
3331
span.IndexOfAnyExcept(_e0);
3432

3533
[MethodImpl(MethodImplOptions.AggressiveInlining)]
36-
internal override int LastIndexOfAny(ReadOnlySpan<T> span) =>
34+
internal override int LastIndexOfAny(ReadOnlySpan<byte> span) =>
3735
span.LastIndexOf(_e0);
3836

3937
[MethodImpl(MethodImplOptions.AggressiveInlining)]
40-
internal override int LastIndexOfAnyExcept(ReadOnlySpan<T> span) =>
38+
internal override int LastIndexOfAnyExcept(ReadOnlySpan<byte> span) =>
4139
span.LastIndexOfAnyExcept(_e0);
4240
}
4341
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
6+
7+
namespace System.Buffers
8+
{
9+
internal sealed class IndexOfAny1CharValue<TShouldUsePacked> : IndexOfAnyValues<char>
10+
where TShouldUsePacked : struct, IndexOfAnyValues.IRuntimeConst
11+
{
12+
private char _e0;
13+
14+
public IndexOfAny1CharValue(char value) =>
15+
_e0 = value;
16+
17+
internal override char[] GetValues() => new[] { _e0 };
18+
19+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
20+
internal override bool ContainsCore(char value) =>
21+
value == _e0;
22+
23+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
24+
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
25+
TShouldUsePacked.Value
26+
? SpanHelpers.PackedIndexOf(ref MemoryMarshal.GetReference(span), _e0, span.Length)
27+
: SpanHelpers.NonPackedIndexOfValueType<short, SpanHelpers.DontNegate<short>>(
28+
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
29+
Unsafe.As<char, short>(ref _e0),
30+
span.Length);
31+
32+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
33+
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
34+
TShouldUsePacked.Value
35+
? SpanHelpers.PackedIndexOfAnyExcept(ref MemoryMarshal.GetReference(span), _e0, span.Length)
36+
: SpanHelpers.NonPackedIndexOfValueType<short, SpanHelpers.Negate<short>>(
37+
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
38+
Unsafe.As<char, short>(ref _e0),
39+
span.Length);
40+
41+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
42+
internal override int LastIndexOfAny(ReadOnlySpan<char> span) =>
43+
span.LastIndexOf(_e0);
44+
45+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
46+
internal override int LastIndexOfAnyExcept(ReadOnlySpan<char> span) =>
47+
span.LastIndexOfAnyExcept(_e0);
48+
}
49+
}

src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAny2Values.cs renamed to src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAny2ByteValues.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,40 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics;
5-
using System.Numerics;
65
using System.Runtime.CompilerServices;
76

87
namespace System.Buffers
98
{
10-
internal sealed class IndexOfAny2Values<T> : IndexOfAnyValues<T>
11-
where T : struct, INumber<T>
9+
internal sealed class IndexOfAny2ByteValues : IndexOfAnyValues<byte>
1210
{
13-
private readonly T _e0, _e1;
11+
private readonly byte _e0, _e1;
1412

15-
public IndexOfAny2Values(ReadOnlySpan<T> values)
13+
public IndexOfAny2ByteValues(ReadOnlySpan<byte> values)
1614
{
1715
Debug.Assert(values.Length == 2);
1816
(_e0, _e1) = (values[0], values[1]);
1917
}
2018

21-
internal override T[] GetValues() => new[] { _e0, _e1 };
19+
internal override byte[] GetValues() => new[] { _e0, _e1 };
2220

2321
[MethodImpl(MethodImplOptions.AggressiveInlining)]
24-
internal override bool ContainsCore(T value) =>
22+
internal override bool ContainsCore(byte value) =>
2523
value == _e0 || value == _e1;
2624

2725
[MethodImpl(MethodImplOptions.AggressiveInlining)]
28-
internal override int IndexOfAny(ReadOnlySpan<T> span) =>
26+
internal override int IndexOfAny(ReadOnlySpan<byte> span) =>
2927
span.IndexOfAny(_e0, _e1);
3028

3129
[MethodImpl(MethodImplOptions.AggressiveInlining)]
32-
internal override int IndexOfAnyExcept(ReadOnlySpan<T> span) =>
30+
internal override int IndexOfAnyExcept(ReadOnlySpan<byte> span) =>
3331
span.IndexOfAnyExcept(_e0, _e1);
3432

3533
[MethodImpl(MethodImplOptions.AggressiveInlining)]
36-
internal override int LastIndexOfAny(ReadOnlySpan<T> span) =>
34+
internal override int LastIndexOfAny(ReadOnlySpan<byte> span) =>
3735
span.LastIndexOfAny(_e0, _e1);
3836

3937
[MethodImpl(MethodImplOptions.AggressiveInlining)]
40-
internal override int LastIndexOfAnyExcept(ReadOnlySpan<T> span) =>
38+
internal override int LastIndexOfAnyExcept(ReadOnlySpan<byte> span) =>
4139
span.LastIndexOfAnyExcept(_e0, _e1);
4240
}
4341
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
6+
7+
namespace System.Buffers
8+
{
9+
internal sealed class IndexOfAny2CharValue<TShouldUsePacked> : IndexOfAnyValues<char>
10+
where TShouldUsePacked : struct, IndexOfAnyValues.IRuntimeConst
11+
{
12+
private char _e0, _e1;
13+
14+
public IndexOfAny2CharValue(char value0, char value1) =>
15+
(_e0, _e1) = (value0, value1);
16+
17+
internal override char[] GetValues() => new[] { _e0 };
18+
19+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
20+
internal override bool ContainsCore(char value) =>
21+
value == _e0 || value == _e1;
22+
23+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
24+
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
25+
TShouldUsePacked.Value
26+
? SpanHelpers.PackedIndexOfAny(ref MemoryMarshal.GetReference(span), _e0, _e1, span.Length)
27+
: SpanHelpers.NonPackedIndexOfAnyValueType<short, SpanHelpers.DontNegate<short>>(
28+
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
29+
Unsafe.As<char, short>(ref _e0),
30+
Unsafe.As<char, short>(ref _e1),
31+
span.Length);
32+
33+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
34+
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
35+
TShouldUsePacked.Value
36+
? SpanHelpers.PackedIndexOfAnyExcept(ref MemoryMarshal.GetReference(span), _e0, _e1, span.Length)
37+
: SpanHelpers.NonPackedIndexOfAnyValueType<short, SpanHelpers.Negate<short>>(
38+
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
39+
Unsafe.As<char, short>(ref _e0),
40+
Unsafe.As<char, short>(ref _e1),
41+
span.Length);
42+
43+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
44+
internal override int LastIndexOfAny(ReadOnlySpan<char> span) =>
45+
span.LastIndexOfAny(_e0, _e1);
46+
47+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
48+
internal override int LastIndexOfAnyExcept(ReadOnlySpan<char> span) =>
49+
span.LastIndexOfAnyExcept(_e0, _e1);
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,53 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Diagnostics;
5-
using System.Numerics;
64
using System.Runtime.CompilerServices;
75

86
namespace System.Buffers
97
{
10-
internal sealed class IndexOfAnyValuesInRange<T> : IndexOfAnyValues<T>
11-
where T : struct, INumber<T>
8+
internal sealed class IndexOfAnyByteValuesInRange : IndexOfAnyValues<byte>
129
{
13-
private readonly T _lowInclusive, _highInclusive;
10+
private readonly byte _lowInclusive, _highInclusive;
1411
private readonly uint _lowUint, _highMinusLow;
1512

16-
public IndexOfAnyValuesInRange(T lowInclusive, T highInclusive)
13+
public IndexOfAnyByteValuesInRange(byte lowInclusive, byte highInclusive)
1714
{
18-
Debug.Assert(lowInclusive is byte or char);
1915
(_lowInclusive, _highInclusive) = (lowInclusive, highInclusive);
20-
_lowUint = uint.CreateChecked(lowInclusive);
21-
_highMinusLow = uint.CreateChecked(highInclusive - lowInclusive);
16+
_lowUint = lowInclusive;
17+
_highMinusLow = (uint)(highInclusive - lowInclusive);
2218
}
2319

24-
internal override T[] GetValues()
20+
internal override byte[] GetValues()
2521
{
26-
T[] values = new T[_highMinusLow + 1];
22+
byte[] values = new byte[_highMinusLow + 1];
2723

28-
T element = _lowInclusive;
24+
int low = _lowInclusive;
2925
for (int i = 0; i < values.Length; i++)
3026
{
31-
values[i] = element;
32-
element += T.One;
27+
values[i] = (byte)(low + i);
3328
}
3429

3530
return values;
3631
}
3732

3833
[MethodImpl(MethodImplOptions.AggressiveInlining)]
39-
internal override bool ContainsCore(T value) =>
40-
uint.CreateChecked(value) - _lowUint <= _highMinusLow;
34+
internal override bool ContainsCore(byte value) =>
35+
value - _lowUint <= _highMinusLow;
4136

4237
[MethodImpl(MethodImplOptions.AggressiveInlining)]
43-
internal override int IndexOfAny(ReadOnlySpan<T> span) =>
38+
internal override int IndexOfAny(ReadOnlySpan<byte> span) =>
4439
span.IndexOfAnyInRange(_lowInclusive, _highInclusive);
4540

4641
[MethodImpl(MethodImplOptions.AggressiveInlining)]
47-
internal override int IndexOfAnyExcept(ReadOnlySpan<T> span) =>
42+
internal override int IndexOfAnyExcept(ReadOnlySpan<byte> span) =>
4843
span.IndexOfAnyExceptInRange(_lowInclusive, _highInclusive);
4944

5045
[MethodImpl(MethodImplOptions.AggressiveInlining)]
51-
internal override int LastIndexOfAny(ReadOnlySpan<T> span) =>
46+
internal override int LastIndexOfAny(ReadOnlySpan<byte> span) =>
5247
span.LastIndexOfAnyInRange(_lowInclusive, _highInclusive);
5348

5449
[MethodImpl(MethodImplOptions.AggressiveInlining)]
55-
internal override int LastIndexOfAnyExcept(ReadOnlySpan<T> span) =>
50+
internal override int LastIndexOfAnyExcept(ReadOnlySpan<byte> span) =>
5651
span.LastIndexOfAnyExceptInRange(_lowInclusive, _highInclusive);
5752
}
5853
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
6+
7+
namespace System.Buffers
8+
{
9+
internal sealed class IndexOfAnyCharValuesInRange<TShouldUsePacked> : IndexOfAnyValues<char>
10+
where TShouldUsePacked : struct, IndexOfAnyValues.IRuntimeConst
11+
{
12+
private char _lowInclusive, _rangeInclusive, _highInclusive;
13+
private readonly uint _lowUint, _highMinusLow;
14+
15+
public IndexOfAnyCharValuesInRange(char lowInclusive, char highInclusive)
16+
{
17+
(_lowInclusive, _rangeInclusive, _highInclusive) = (lowInclusive, (char)(highInclusive - lowInclusive), highInclusive);
18+
_lowUint = lowInclusive;
19+
_highMinusLow = (uint)(highInclusive - lowInclusive);
20+
}
21+
22+
internal override char[] GetValues()
23+
{
24+
char[] values = new char[_rangeInclusive + 1];
25+
26+
int low = _lowInclusive;
27+
for (int i = 0; i < values.Length; i++)
28+
{
29+
values[i] = (char)(low + i);
30+
}
31+
32+
return values;
33+
}
34+
35+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
36+
internal override bool ContainsCore(char value) =>
37+
value - _lowUint <= _highMinusLow;
38+
39+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
40+
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
41+
TShouldUsePacked.Value
42+
? SpanHelpers.PackedIndexOfAnyInRange(ref MemoryMarshal.GetReference(span), _lowInclusive, _rangeInclusive, span.Length)
43+
: SpanHelpers.NonPackedIndexOfAnyInRangeUnsignedNumber<ushort, SpanHelpers.DontNegate<ushort>>(
44+
ref Unsafe.As<char, ushort>(ref MemoryMarshal.GetReference(span)),
45+
Unsafe.As<char, ushort>(ref _lowInclusive),
46+
Unsafe.As<char, ushort>(ref _highInclusive),
47+
span.Length);
48+
49+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
50+
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
51+
TShouldUsePacked.Value
52+
? SpanHelpers.PackedIndexOfAnyExceptInRange(ref MemoryMarshal.GetReference(span), _lowInclusive, _rangeInclusive, span.Length)
53+
: SpanHelpers.NonPackedIndexOfAnyInRangeUnsignedNumber<ushort, SpanHelpers.Negate<ushort>>(
54+
ref Unsafe.As<char, ushort>(ref MemoryMarshal.GetReference(span)),
55+
Unsafe.As<char, ushort>(ref _lowInclusive),
56+
Unsafe.As<char, ushort>(ref _highInclusive),
57+
span.Length);
58+
59+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
60+
internal override int LastIndexOfAny(ReadOnlySpan<char> span) =>
61+
span.LastIndexOfAnyInRange(_lowInclusive, _highInclusive);
62+
63+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
64+
internal override int LastIndexOfAnyExcept(ReadOnlySpan<char> span) =>
65+
span.LastIndexOfAnyExceptInRange(_lowInclusive, _highInclusive);
66+
}
67+
}

0 commit comments

Comments
 (0)