Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Double IndexOf throughput for chars #78861

Merged
merged 4 commits into from Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -421,21 +421,25 @@
<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\IndexOfAny3Values.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\IndexOfAny3ByteValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\IndexOfAny3CharValues.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\IndexOfAnyByteValuesInRange.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\IndexOfEmptyValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOfAnyValues\ProbabilisticMap.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IndexOutOfRangeException.cs" />
Expand Down Expand Up @@ -1029,6 +1033,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Byte.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Char.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Packed.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.T.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SR.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\StackOverflowException.cs" />
Expand Down
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) :
PackedSpanHelpers.PackedIndexOfIsSupported
? PackedSpanHelpers.IndexOfAny(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
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);
}
}
@@ -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
? PackedSpanHelpers.IndexOf(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
? PackedSpanHelpers.IndexOfAnyExcept(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);
}
}
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);
}
}
@@ -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, _e1 };
MihaZupan marked this conversation as resolved.
Show resolved Hide resolved

[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
? PackedSpanHelpers.IndexOfAny(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
? PackedSpanHelpers.IndexOfAnyExcept(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);
}
}
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 IndexOfAny3Values<T> : IndexOfAnyValues<T>
where T : struct, INumber<T>
internal sealed class IndexOfAny3ByteValues : IndexOfAnyValues<byte>
{
private readonly T _e0, _e1, _e2;
private readonly byte _e0, _e1, _e2;

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

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

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

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

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

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

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int LastIndexOfAnyExcept(ReadOnlySpan<T> span) =>
internal override int LastIndexOfAnyExcept(ReadOnlySpan<byte> span) =>
span.LastIndexOfAnyExcept(_e0, _e1, _e2);
}
}
@@ -0,0 +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.Runtime.CompilerServices;
using System.Runtime.InteropServices;

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

public IndexOfAny3CharValue(char value0, char value1, char value2) =>
(_e0, _e1, _e2) = (value0, value1, value2);

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

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

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
? PackedSpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), _e0, _e1, _e2, 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),
Unsafe.As<char, short>(ref _e2),
span.Length);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
? PackedSpanHelpers.IndexOfAnyExcept(ref MemoryMarshal.GetReference(span), _e0, _e1, _e2, 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),
Unsafe.As<char, short>(ref _e2),
span.Length);

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

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