-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use trait-based classes to get everything inlined
This will cost one extra `HashSet<string>` and one extra `SubstringComparer` to be allocated, but might make the code run faster. Use the GSW strategy for virtual flattening
- Loading branch information
1 parent
c1dd5d9
commit 7060c23
Showing
5 changed files
with
254 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
...ns.Immutable/src/System/Collections/Frozen/String/SubstringComparers/SubstringComparer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// 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; | ||
|
||
namespace System.Collections.Frozen.String.SubstringComparers | ||
{ | ||
internal sealed class LeftSubstringOrdinalComparer : SubstringComparerBase<LeftSubstringOrdinalComparer.GSW> | ||
{ | ||
internal struct GSW : IGenericSpecializedWrapper | ||
{ | ||
private LeftSubstringOrdinalComparer _this; | ||
public void Store(ISubstringComparer @this) => _this = (LeftSubstringOrdinalComparer)@this; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public ReadOnlySpan<char> Slice(string s) => s.AsSpan(_this.Index, _this.Count); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public bool Equals(string? x, string? y) => Slice(x!).SequenceEqual(Slice(y!)); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public int GetHashCode(string s) => Hashing.GetHashCodeOrdinal(Slice(s)); | ||
} | ||
} | ||
|
||
internal sealed class RightSubstringOrdinalComparer : SubstringComparerBase<RightSubstringOrdinalComparer.GSW> | ||
{ | ||
internal struct GSW : IGenericSpecializedWrapper | ||
{ | ||
private RightSubstringOrdinalComparer _this; | ||
public void Store(ISubstringComparer @this) => _this = (RightSubstringOrdinalComparer)@this; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public ReadOnlySpan<char> Slice(string s) => s.AsSpan(s.Length + _this.Index, _this.Count); | ||
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public bool Equals(string? x, string? y) => Slice(x!).SequenceEqual(Slice(y!)); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public int GetHashCode(string s) => Hashing.GetHashCodeOrdinal(Slice(s)); | ||
} | ||
} | ||
|
||
internal sealed class LeftSubstringCaseInsensitiveComparer : SubstringComparerBase<LeftSubstringCaseInsensitiveComparer.GSW> | ||
{ | ||
internal struct GSW : IGenericSpecializedWrapper | ||
{ | ||
private LeftSubstringCaseInsensitiveComparer _this; | ||
public void Store(ISubstringComparer @this) => _this = (LeftSubstringCaseInsensitiveComparer)@this; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public ReadOnlySpan<char> Slice(string s) => s.AsSpan(_this.Index, _this.Count); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public bool Equals(string? x, string? y) => Slice(x!).Equals(Slice(y!), StringComparison.OrdinalIgnoreCase); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public int GetHashCode(string s) => Hashing.GetHashCodeOrdinalIgnoreCase(Slice(s)); | ||
} | ||
} | ||
|
||
internal sealed class RightSubstringCaseInsensitiveComparer : SubstringComparerBase<RightSubstringCaseInsensitiveComparer.GSW> | ||
{ | ||
internal struct GSW : IGenericSpecializedWrapper | ||
{ | ||
private RightSubstringCaseInsensitiveComparer _this; | ||
public void Store(ISubstringComparer @this) => _this = (RightSubstringCaseInsensitiveComparer)@this; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public ReadOnlySpan<char> Slice(string s) => s.AsSpan(s.Length + _this.Index, _this.Count); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public bool Equals(string? x, string? y) => Slice(x!).Equals(Slice(y!), StringComparison.OrdinalIgnoreCase); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public int GetHashCode(string s) => Hashing.GetHashCodeOrdinalIgnoreCase(Slice(s)); | ||
} | ||
} | ||
|
||
internal sealed class FullStringComparer : SubstringComparerBase<FullStringComparer.GSW> | ||
{ | ||
internal struct GSW : IGenericSpecializedWrapper | ||
{ | ||
private FullStringComparer _this; | ||
public void Store(ISubstringComparer @this) => _this = (FullStringComparer)@this; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public ReadOnlySpan<char> Slice(string s) => s.AsSpan(); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public bool Equals(string? x, string? y) => Slice(x!).Equals(Slice(y!), StringComparison.OrdinalIgnoreCase); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public int GetHashCode(string s) => Hashing.GetHashCodeOrdinalIgnoreCase(Slice(s)); | ||
} | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
...mmutable/src/System/Collections/Frozen/String/SubstringComparers/SubstringComparerBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Collections.Generic; | ||
using System.Runtime.CompilerServices; | ||
|
||
namespace System.Collections.Frozen.String.SubstringComparers | ||
{ | ||
internal interface ISubstringComparer : IEqualityComparer<string> | ||
{ | ||
public int Index { get; set; } // offset from left side (if positive) or right side (if negative) of the string | ||
public int Count { get; set; } // number of characters in the span | ||
|
||
public abstract ReadOnlySpan<char> Slice(string s); | ||
} | ||
|
||
internal abstract class SubstringComparerBase<TThisWrapper> : ISubstringComparer | ||
where TThisWrapper : struct, SubstringComparerBase<TThisWrapper>.IGenericSpecializedWrapper | ||
{ | ||
/// <summary>A wrapper around this that enables access to important members without making virtual calls.</summary> | ||
private readonly TThisWrapper _this; | ||
|
||
protected SubstringComparerBase() | ||
{ | ||
_this = default; | ||
_this.Store(this); | ||
} | ||
|
||
public int Index { get; set; } | ||
public int Count { get; set; } | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public ReadOnlySpan<char> Slice(string s) => _this.Slice(s); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public bool Equals(string? x, string? y) => _this.Equals(x, y); | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public int GetHashCode(string s) => _this.GetHashCode(s); | ||
|
||
/// <summary>Used to enable generic specialization with reference types.</summary> | ||
/// <remarks> | ||
/// To avoid each of those incurring virtual dispatch to the derived type, the derived | ||
/// type hands down a struct wrapper through which all calls are performed. This base | ||
/// class uses that generic struct wrapper to specialize and devirtualize. | ||
/// </remarks> | ||
internal interface IGenericSpecializedWrapper | ||
{ | ||
void Store(ISubstringComparer @this); | ||
public ReadOnlySpan<char> Slice(string s); | ||
public bool Equals(string? x, string? y); | ||
public int GetHashCode(string s); | ||
} | ||
} | ||
} |
Oops, something went wrong.