Skip to content

Commit

Permalink
Add PackedIndexOf for chars
Browse files Browse the repository at this point in the history
  • Loading branch information
MihaZupan committed Nov 30, 2022
1 parent b85e152 commit 34ee7e0
Show file tree
Hide file tree
Showing 13 changed files with 884 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -421,21 +421,24 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IFormattable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Index.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\BitVector256.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny1Value.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny2Values.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny1CharValue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny1ByteValue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny2ByteValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny2CharValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny3Values.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny4Values.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny5Values.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyAsciiByteValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyAsciiCharValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyAsciiSearcher.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyByteValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyCharValuesInRange.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyCharValuesProbabilistic.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyLatin1CharValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValues.T.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValuesDebugView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyValuesInRange.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAnyByteValuesInRange.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfEmptyValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\ProbabilisticMap.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOutOfRangeException.cs" />
Expand Down Expand Up @@ -1028,6 +1031,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.BinarySearch.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Byte.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Char.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Char.Packed.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.T.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SR.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,9 @@ internal static int IndexOfOrdinalIgnoreCase(ReadOnlySpan<char> source, ReadOnly
{
// Do a quick search for the first element of "value".
int relativeIndex = isLetter ?
SpanHelpers.IndexOfAnyChar(ref Unsafe.Add(ref searchSpace, offset), valueCharU, valueCharL, searchSpaceLength) :
SpanHelpers.PackedIndexOfIsSupported
? SpanHelpers.PackedIndexOfAny(ref Unsafe.Add(ref searchSpace, offset), valueCharU, valueCharL, searchSpaceLength)
: SpanHelpers.IndexOfAnyChar(ref Unsafe.Add(ref searchSpace, offset), valueCharU, valueCharL, searchSpaceLength) :
SpanHelpers.IndexOfChar(ref Unsafe.Add(ref searchSpace, offset), valueChar, searchSpaceLength);
if (relativeIndex < 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,40 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;

namespace System.Buffers
{
internal sealed class IndexOfAny1Value<T> : IndexOfAnyValues<T>
where T : struct, INumber<T>
internal sealed class IndexOfAny1ByteValue : IndexOfAnyValues<byte>
{
private readonly T _e0;
private readonly byte _e0;

public IndexOfAny1Value(ReadOnlySpan<T> values)
public IndexOfAny1ByteValue(ReadOnlySpan<byte> values)
{
Debug.Assert(values.Length == 1);
_e0 = values[0];
}

internal override T[] GetValues() => new[] { _e0 };
internal override byte[] GetValues() => new[] { _e0 };

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override bool ContainsCore(T value) =>
internal override bool ContainsCore(byte value) =>
value == _e0;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<T> span) =>
internal override int IndexOfAny(ReadOnlySpan<byte> span) =>
span.IndexOf(_e0);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<T> span) =>
internal override int IndexOfAnyExcept(ReadOnlySpan<byte> span) =>
span.IndexOfAnyExcept(_e0);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAny(ReadOnlySpan<T> span) =>
internal override int LastIndexOfAny(ReadOnlySpan<byte> span) =>
span.LastIndexOf(_e0);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAnyExcept(ReadOnlySpan<T> span) =>
internal override int LastIndexOfAnyExcept(ReadOnlySpan<byte> span) =>
span.LastIndexOfAnyExcept(_e0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Buffers
{
internal sealed class IndexOfAny1CharValue<TShouldUsePacked> : IndexOfAnyValues<char>
where TShouldUsePacked : struct, IndexOfAnyValues.IRuntimeConst
{
private char _e0;

public IndexOfAny1CharValue(char value) =>
_e0 = value;

internal override char[] GetValues() => new[] { _e0 };

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override bool ContainsCore(char value) =>
value == _e0;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
? SpanHelpers.PackedIndexOf(ref MemoryMarshal.GetReference(span), _e0, span.Length)
: SpanHelpers.NonPackedIndexOfValueType<short, SpanHelpers.DontNegate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<char, short>(ref _e0),
span.Length);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
? SpanHelpers.PackedIndexOfAnyExcept(ref MemoryMarshal.GetReference(span), _e0, span.Length)
: SpanHelpers.NonPackedIndexOfValueType<short, SpanHelpers.Negate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<char, short>(ref _e0),
span.Length);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAny(ReadOnlySpan<char> span) =>
span.LastIndexOf(_e0);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAnyExcept(ReadOnlySpan<char> span) =>
span.LastIndexOfAnyExcept(_e0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,40 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;

namespace System.Buffers
{
internal sealed class IndexOfAny2Values<T> : IndexOfAnyValues<T>
where T : struct, INumber<T>
internal sealed class IndexOfAny2ByteValues : IndexOfAnyValues<byte>
{
private readonly T _e0, _e1;
private readonly byte _e0, _e1;

public IndexOfAny2Values(ReadOnlySpan<T> values)
public IndexOfAny2ByteValues(ReadOnlySpan<byte> values)
{
Debug.Assert(values.Length == 2);
(_e0, _e1) = (values[0], values[1]);
}

internal override T[] GetValues() => new[] { _e0, _e1 };
internal override byte[] GetValues() => new[] { _e0, _e1 };

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override bool ContainsCore(T value) =>
internal override bool ContainsCore(byte value) =>
value == _e0 || value == _e1;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<T> span) =>
internal override int IndexOfAny(ReadOnlySpan<byte> span) =>
span.IndexOfAny(_e0, _e1);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<T> span) =>
internal override int IndexOfAnyExcept(ReadOnlySpan<byte> span) =>
span.IndexOfAnyExcept(_e0, _e1);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAny(ReadOnlySpan<T> span) =>
internal override int LastIndexOfAny(ReadOnlySpan<byte> span) =>
span.LastIndexOfAny(_e0, _e1);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAnyExcept(ReadOnlySpan<T> span) =>
internal override int LastIndexOfAnyExcept(ReadOnlySpan<byte> span) =>
span.LastIndexOfAnyExcept(_e0, _e1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Buffers
{
internal sealed class IndexOfAny2CharValue<TShouldUsePacked> : IndexOfAnyValues<char>
where TShouldUsePacked : struct, IndexOfAnyValues.IRuntimeConst
{
private char _e0, _e1;

public IndexOfAny2CharValue(char value0, char value1) =>
(_e0, _e1) = (value0, value1);

internal override char[] GetValues() => new[] { _e0 };

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override bool ContainsCore(char value) =>
value == _e0 || value == _e1;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
? SpanHelpers.PackedIndexOfAny(ref MemoryMarshal.GetReference(span), _e0, _e1, span.Length)
: SpanHelpers.NonPackedIndexOfAnyValueType<short, SpanHelpers.DontNegate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<char, short>(ref _e0),
Unsafe.As<char, short>(ref _e1),
span.Length);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
? SpanHelpers.PackedIndexOfAnyExcept(ref MemoryMarshal.GetReference(span), _e0, _e1, span.Length)
: SpanHelpers.NonPackedIndexOfAnyValueType<short, SpanHelpers.Negate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<char, short>(ref _e0),
Unsafe.As<char, short>(ref _e1),
span.Length);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAny(ReadOnlySpan<char> span) =>
span.LastIndexOfAny(_e0, _e1);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAnyExcept(ReadOnlySpan<char> span) =>
span.LastIndexOfAnyExcept(_e0, _e1);
}
}
Original file line number Diff line number Diff line change
@@ -1,58 +1,53 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;

namespace System.Buffers
{
internal sealed class IndexOfAnyValuesInRange<T> : IndexOfAnyValues<T>
where T : struct, INumber<T>
internal sealed class IndexOfAnyByteValuesInRange : IndexOfAnyValues<byte>
{
private readonly T _lowInclusive, _highInclusive;
private readonly byte _lowInclusive, _highInclusive;
private readonly uint _lowUint, _highMinusLow;

public IndexOfAnyValuesInRange(T lowInclusive, T highInclusive)
public IndexOfAnyByteValuesInRange(byte lowInclusive, byte highInclusive)
{
Debug.Assert(lowInclusive is byte or char);
(_lowInclusive, _highInclusive) = (lowInclusive, highInclusive);
_lowUint = uint.CreateChecked(lowInclusive);
_highMinusLow = uint.CreateChecked(highInclusive - lowInclusive);
_lowUint = lowInclusive;
_highMinusLow = (uint)(highInclusive - lowInclusive);
}

internal override T[] GetValues()
internal override byte[] GetValues()
{
T[] values = new T[_highMinusLow + 1];
byte[] values = new byte[_highMinusLow + 1];

T element = _lowInclusive;
int low = _lowInclusive;
for (int i = 0; i < values.Length; i++)
{
values[i] = element;
element += T.One;
values[i] = (byte)(low + i);
}

return values;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override bool ContainsCore(T value) =>
uint.CreateChecked(value) - _lowUint <= _highMinusLow;
internal override bool ContainsCore(byte value) =>
value - _lowUint <= _highMinusLow;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<T> span) =>
internal override int IndexOfAny(ReadOnlySpan<byte> span) =>
span.IndexOfAnyInRange(_lowInclusive, _highInclusive);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<T> span) =>
internal override int IndexOfAnyExcept(ReadOnlySpan<byte> span) =>
span.IndexOfAnyExceptInRange(_lowInclusive, _highInclusive);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAny(ReadOnlySpan<T> span) =>
internal override int LastIndexOfAny(ReadOnlySpan<byte> span) =>
span.LastIndexOfAnyInRange(_lowInclusive, _highInclusive);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAnyExcept(ReadOnlySpan<T> span) =>
internal override int LastIndexOfAnyExcept(ReadOnlySpan<byte> span) =>
span.LastIndexOfAnyExceptInRange(_lowInclusive, _highInclusive);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Buffers
{
internal sealed class IndexOfAnyCharValuesInRange<TShouldUsePacked> : IndexOfAnyValues<char>
where TShouldUsePacked : struct, IndexOfAnyValues.IRuntimeConst
{
private char _lowInclusive, _rangeInclusive, _highInclusive;
private readonly uint _lowUint, _highMinusLow;

public IndexOfAnyCharValuesInRange(char lowInclusive, char highInclusive)
{
(_lowInclusive, _rangeInclusive, _highInclusive) = (lowInclusive, (char)(highInclusive - lowInclusive), highInclusive);
_lowUint = lowInclusive;
_highMinusLow = (uint)(highInclusive - lowInclusive);
}

internal override char[] GetValues()
{
char[] values = new char[_rangeInclusive + 1];

int low = _lowInclusive;
for (int i = 0; i < values.Length; i++)
{
values[i] = (char)(low + i);
}

return values;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override bool ContainsCore(char value) =>
value - _lowUint <= _highMinusLow;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
? SpanHelpers.PackedIndexOfAnyInRange(ref MemoryMarshal.GetReference(span), _lowInclusive, _rangeInclusive, span.Length)
: SpanHelpers.NonPackedIndexOfAnyInRangeUnsignedNumber<ushort, SpanHelpers.DontNegate<ushort>>(
ref Unsafe.As<char, ushort>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<char, ushort>(ref _lowInclusive),
Unsafe.As<char, ushort>(ref _highInclusive),
span.Length);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
? SpanHelpers.PackedIndexOfAnyExceptInRange(ref MemoryMarshal.GetReference(span), _lowInclusive, _rangeInclusive, span.Length)
: SpanHelpers.NonPackedIndexOfAnyInRangeUnsignedNumber<ushort, SpanHelpers.Negate<ushort>>(
ref Unsafe.As<char, ushort>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<char, ushort>(ref _lowInclusive),
Unsafe.As<char, ushort>(ref _highInclusive),
span.Length);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAny(ReadOnlySpan<char> span) =>
span.LastIndexOfAnyInRange(_lowInclusive, _highInclusive);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAnyExcept(ReadOnlySpan<char> span) =>
span.LastIndexOfAnyExceptInRange(_lowInclusive, _highInclusive);
}
}
Loading

0 comments on commit 34ee7e0

Please sign in to comment.