Skip to content

Commit

Permalink
Avoid repeat allocations in Enum.TryParse
Browse files Browse the repository at this point in the history
  • Loading branch information
sharwell committed Aug 22, 2024
1 parent d97bdbe commit 88caa25
Showing 1 changed file with 25 additions and 4 deletions.
29 changes: 25 additions & 4 deletions StyleCop.Analyzers/StyleCop.Analyzers/Settings/JsonHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace StyleCop.Analyzers
{
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using LightJson;

/// <summary>
Expand Down Expand Up @@ -82,15 +83,15 @@ internal static string ToStringValue(this JsonValue jsonValue, string elementNam
/// <param name="jsonValue">The key value pair identifying the JSON value.</param>
/// <returns>The enum value contained within the JSON value.</returns>
internal static TEnum ToEnumValue<TEnum>(this KeyValuePair<string, JsonValue> jsonValue)
where TEnum : struct
where TEnum : struct, Enum
{
if (!jsonValue.Value.IsString)
{
throw new InvalidSettingsException($"{jsonValue.Key} must contain an enum (string) value");
}

TEnum result;
if (!Enum.TryParse(jsonValue.Value.AsString, true, out result))
if (!EnumHelper<TEnum>.TryParse(jsonValue.Value.AsString, out result))
{
throw new InvalidSettingsException($"{jsonValue.Key} cannot contain enum value '{jsonValue.Value.AsString}'");
}
Expand All @@ -106,15 +107,15 @@ internal static TEnum ToEnumValue<TEnum>(this KeyValuePair<string, JsonValue> js
/// <param name="elementName">The element name to report in exceptions.</param>
/// <returns>The enum value contained within the JSON value.</returns>
internal static TEnum ToEnumValue<TEnum>(this JsonValue jsonValue, string elementName)
where TEnum : struct
where TEnum : struct, Enum
{
if (!jsonValue.IsString)
{
throw new InvalidSettingsException($"{elementName} must contain an enum (string) value");
}

TEnum result;
if (!Enum.TryParse(jsonValue.AsString, true, out result))
if (!EnumHelper<TEnum>.TryParse(jsonValue.AsString, out result))
{
throw new InvalidSettingsException($"{elementName} cannot contain enum value '{jsonValue.AsString}'");
}
Expand Down Expand Up @@ -145,5 +146,25 @@ internal static void AssertIsObject(this KeyValuePair<string, JsonValue> jsonVal
throw new InvalidSettingsException($"{jsonValue.Key} must contain an object");
}
}

private static class EnumHelper<TEnum>
where TEnum : struct, Enum
{
private static ImmutableDictionary<string, KeyValuePair<bool, TEnum>> values = ImmutableDictionary<string, KeyValuePair<bool, TEnum>>.Empty;

public static bool TryParse(string value, out TEnum result)
{
var successAndResult = ImmutableInterlocked.GetOrAdd(
ref values,
value,
static value =>
{
bool success = Enum.TryParse(value, true, out TEnum result);
return new KeyValuePair<bool, TEnum>(success, result);
});
result = successAndResult.Value;
return successAndResult.Key;
}
}
}
}

0 comments on commit 88caa25

Please # to comment.