Skip to content

Commit

Permalink
Merge pull request #39 from xin9le/feature/refactor-StringHelper
Browse files Browse the repository at this point in the history
Refactor `StringHelper` type
  • Loading branch information
xin9le authored Sep 6, 2024
2 parents 4d82386 + ec06bdc commit fa9d4f3
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 61 deletions.
27 changes: 1 addition & 26 deletions src/libs/FastEnum.Core/FastEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ public static bool TryParse<T>(ReadOnlySpan<char> value, bool ignoreCase, out T
return false;
}

if (isNumeric(value.At(0)))
if (StringHelper.IsNumeric(value.At(0)))
return UnderlyingOperation<T>.TryParseValue(value, out result);

if (ignoreCase)
Expand All @@ -248,31 +248,6 @@ public static bool TryParse<T>(ReadOnlySpan<char> value, bool ignoreCase, out T


#region Local Functions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool isNumeric(char x)
{
// note:
// - In this case, there is no change in speed with or without sequential numbering.

return x switch
{
'+' => true, // 43
'-' => true, // 45
'0' => true, // 48
'1' => true,
'2' => true,
'3' => true,
'4' => true,
'5' => true,
'6' => true,
'7' => true,
'8' => true,
'9' => true,
_ => false,
};
}


[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool tryParseNameCaseSensitive(ReadOnlySpan<char> name, out T result)
{
Expand Down
16 changes: 8 additions & 8 deletions src/libs/FastEnum.Core/Internals/SpecializedDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ static int calculateCapacity(int collectionSize, float loadFactor)

static bool tryAdd(Entry[] buckets, Entry entry, int indexFor)
{
var hash = CaseSensitiveStringHelper.GetHashCode(entry.Key);
var hash = StringHelper.CaseSensitive.GetHashCode(entry.Key);
var index = hash & indexFor;
var target = buckets.At(index);
if (target is null)
Expand All @@ -235,7 +235,7 @@ static bool tryAdd(Entry[] buckets, Entry entry, int indexFor)
while (true)
{
//--- Check duplicate
if (CaseSensitiveStringHelper.Equals(target.Key, entry.Key))
if (StringHelper.CaseSensitive.Equals(target.Key, entry.Key))
return false;

//--- Append entry
Expand Down Expand Up @@ -266,12 +266,12 @@ public bool ContainsKey(ReadOnlySpan<char> key)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetValue(ReadOnlySpan<char> key, [MaybeNullWhen(false)] out TValue value)
{
var hash = CaseSensitiveStringHelper.GetHashCode(key);
var hash = StringHelper.CaseSensitive.GetHashCode(key);
var index = hash & this._indexFor;
var entry = this._buckets.At(index);
while (entry is not null)
{
if (CaseSensitiveStringHelper.Equals(key, entry.Key))
if (StringHelper.CaseSensitive.Equals(key, entry.Key))
{
value = entry.Value;
return true;
Expand Down Expand Up @@ -362,7 +362,7 @@ static int calculateCapacity(int collectionSize, float loadFactor)

static bool tryAdd(Entry[] buckets, Entry entry, int indexFor)
{
var hash = CaseInsensitiveStringHelper.GetHashCode(entry.Key);
var hash = StringHelper.CaseInsensitive.GetHashCode(entry.Key);
var index = hash & indexFor;
var target = buckets.At(index);
if (target is null)
Expand All @@ -375,7 +375,7 @@ static bool tryAdd(Entry[] buckets, Entry entry, int indexFor)
while (true)
{
//--- Check duplicate
if (CaseInsensitiveStringHelper.Equals(target.Key, entry.Key))
if (StringHelper.CaseInsensitive.Equals(target.Key, entry.Key))
return false;

//--- Append entry
Expand Down Expand Up @@ -406,12 +406,12 @@ public bool ContainsKey(ReadOnlySpan<char> key)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetValue(ReadOnlySpan<char> key, [MaybeNullWhen(false)] out TValue value)
{
var hash = CaseInsensitiveStringHelper.GetHashCode(key);
var hash = StringHelper.CaseInsensitive.GetHashCode(key);
var index = hash & this._indexFor;
var entry = this._buckets.At(index);
while (entry is not null)
{
if (CaseInsensitiveStringHelper.Equals(entry.Key, key))
if (StringHelper.CaseInsensitive.Equals(entry.Key, key))
{
value = entry.Value;
return true;
Expand Down
84 changes: 57 additions & 27 deletions src/libs/FastEnum.Core/Internals/StringHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,79 @@ namespace FastEnumUtility.Internals;



internal static class CaseSensitiveStringHelper
internal static class StringHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetHashCode(ReadOnlySpan<char> value)
public static bool IsNumeric(char x)
{
// note:
// - Suppress CA1307 : Specify StringComparison for clarity
// - Overload that specify StringComparison is slow because of internal branching by switch statements.
// - In this case, there is no change in speed with or without sequential numbering.

return x switch
{
'+' => true, // 43
'-' => true, // 45
'0' => true, // 48
'1' => true,
'2' => true,
'3' => true,
'4' => true,
'5' => true,
'6' => true,
'7' => true,
'8' => true,
'9' => true,
_ => false,
};
}


#region Nested Types
public static class CaseSensitive
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetHashCode(ReadOnlySpan<char> value)
{
// note:
// - Suppress CA1307 : Specify StringComparison for clarity
// - Overload that specify StringComparison is slow because of internal branching by switch statements.

#pragma warning disable CA1307
return string.GetHashCode(value);
return string.GetHashCode(value);
#pragma warning restore CA1307
}
}


[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Equals(ReadOnlySpan<char> x, ReadOnlySpan<char> y)
=> MemoryExtensions.SequenceEqual(x, y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Equals(ReadOnlySpan<char> x, ReadOnlySpan<char> y)
=> MemoryExtensions.SequenceEqual(x, y);
}



internal static class CaseInsensitiveStringHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetHashCode(ReadOnlySpan<char> value)
public static class CaseInsensitive
{
// note:
// - Overload that specify StringComparison is slow because of internal branching by switch statements.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetHashCode(ReadOnlySpan<char> value)
{
// note:
// - Overload that specify StringComparison is slow because of internal branching by switch statements.

return string_GetHashCodeOrdinalIgnoreCase(self: null, value);
return string_GetHashCodeOrdinalIgnoreCase(self: null, value);


#region Local Functions
// note:
// - UnsafeAccessor can't be defined within a Generic type.
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetHashCodeOrdinalIgnoreCase")]
static extern int string_GetHashCodeOrdinalIgnoreCase(string? self, ReadOnlySpan<char> value);
#endregion
}
#region Local Functions
// note:
// - UnsafeAccessor can't be defined within a Generic type.
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetHashCodeOrdinalIgnoreCase")]
static extern int string_GetHashCodeOrdinalIgnoreCase(string? self, ReadOnlySpan<char> value);
#endregion
}


[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Equals(ReadOnlySpan<char> x, ReadOnlySpan<char> y)
=> MemoryExtensions.Equals(x, y, StringComparison.OrdinalIgnoreCase);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Equals(ReadOnlySpan<char> x, ReadOnlySpan<char> y)
=> MemoryExtensions.Equals(x, y, StringComparison.OrdinalIgnoreCase);
}
#endregion
}

0 comments on commit fa9d4f3

Please sign in to comment.