perf: Adding contrains for enum methods, faster HasFlag/s checks

This commit is contained in:
Chris Cameron
2018-07-26 10:56:08 -04:00
parent 1a87ce9f00
commit 668994be18
5 changed files with 71 additions and 66 deletions

View File

@@ -30,6 +30,7 @@ namespace ICD.Common.Utils
/// </summary>
/// <returns></returns>
public static bool IsEnumType<T>()
where T : struct, IConvertible
{
return IsEnumType(typeof(T));
}
@@ -55,9 +56,9 @@ namespace ICD.Common.Utils
/// </summary>
/// <returns></returns>
public static bool IsEnum<T>(T value)
where T : struct, IConvertible
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
return value != null && IsEnumType(value.GetType());
return IsEnumType(value.GetType());
}
/// <summary>
@@ -67,6 +68,7 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static bool IsDefined<T>(T value)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new InvalidOperationException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -94,6 +96,7 @@ namespace ICD.Common.Utils
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetValues<T>()
where T : struct, IConvertible
{
Type type = typeof(T);
@@ -122,6 +125,7 @@ namespace ICD.Common.Utils
/// </summary>
/// <returns></returns>
private static IEnumerable<T> GetValuesUncached<T>()
where T : struct, IConvertible
{
return GetValuesUncached(typeof(T)).Cast<T>();
}
@@ -151,6 +155,7 @@ namespace ICD.Common.Utils
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetValuesExceptNone<T>()
where T : struct, IConvertible
{
return GetFlagsExceptNone<T>();
}
@@ -174,6 +179,7 @@ namespace ICD.Common.Utils
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static bool IsFlagsEnum<T>()
where T : struct, IConvertible
{
return IsFlagsEnum(typeof(T));
}
@@ -198,6 +204,7 @@ namespace ICD.Common.Utils
/// <param name="values"></param>
/// <returns></returns>
public static T GetFlagsIntersection<T>(params T[] values)
where T : struct, IConvertible
{
if (values.Length == 0)
return default(T);
@@ -217,6 +224,7 @@ namespace ICD.Common.Utils
/// <param name="b"></param>
/// <returns></returns>
public static T GetFlagsIntersection<T>(T a, T b)
where T : struct, IConvertible
{
int aInt = (int)(object)a;
int bInt = (int)(object)b;
@@ -231,10 +239,10 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlags<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
throw new ArgumentException(string.Format("{0} is not an enum", value.GetType().Name), "value");
Type type = typeof(T);
int valueInt = (int)(object)value;
@@ -262,6 +270,7 @@ namespace ICD.Common.Utils
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetFlagsExceptNone<T>()
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -277,10 +286,10 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlagsExceptNone<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
throw new ArgumentException(string.Format("{0} is not an enum", value.GetType().Name), "value");
return GetFlags(value).Except(default(T));
}
@@ -295,10 +304,10 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetAllFlagCombinationsExceptNone<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
throw new ArgumentException(string.Format("{0} is not an enum", value.GetType().Name), "value");
int maxEnumValue = (GetValues<T>().Max(v => (int)(object)v) * 2) -1;
return Enumerable.Range(1, maxEnumValue).Select(i => (T)(object)i ).Where(v => HasFlags(value, v));
@@ -310,6 +319,7 @@ namespace ICD.Common.Utils
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetFlagsAllValue<T>()
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -326,16 +336,15 @@ namespace ICD.Common.Utils
/// <param name="flag"></param>
/// <returns></returns>
public static bool HasFlag<T>(T value, T flag)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
throw new ArgumentException(string.Format("{0} is not an enum", value.GetType().Name), "value");
if (!IsEnum(flag))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", flag == null ? "NULL" : flag.GetType().Name), "flag");
throw new ArgumentException(string.Format("{0} is not an enum", flag.GetType().Name), "flag");
return ToEnum(value).HasFlag(ToEnum(flag));
return HasFlags(value, flag);
}
/// <summary>
@@ -346,16 +355,18 @@ namespace ICD.Common.Utils
/// <param name="flags"></param>
/// <returns></returns>
public static bool HasFlags<T>(T value, T flags)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
throw new ArgumentException(string.Format("{0} is not an enum", value.GetType().Name), "value");
if (!IsEnum(flags))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", flags == null ? "NULL" : flags.GetType().Name), "flags");
throw new ArgumentException(string.Format("{0} is not an enum", flags.GetType().Name), "flags");
return ToEnum(value).HasFlags(ToEnum(flags));
int a = (int)(object)value;
int b = (int)(object)flags;
return (a & b) == b;
}
/// <summary>
@@ -365,10 +376,10 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static bool HasSingleFlag<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
throw new ArgumentException(string.Format("{0} is not an enum", value.GetType().Name), "value");
return HasAnyFlags(value) && !HasMultipleFlags(value);
}
@@ -379,10 +390,10 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static bool HasMultipleFlags<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
throw new ArgumentException(string.Format("{0} is not an enum", value.GetType().Name), "value");
return HasMultipleFlags((int)(object)value);
}
@@ -405,6 +416,7 @@ namespace ICD.Common.Utils
/// <returns></returns>
[PublicAPI]
public static bool HasAnyFlags<T>(T value)
where T : struct, IConvertible
{
return HasAnyFlags((int)(object)value);
}
@@ -428,6 +440,7 @@ namespace ICD.Common.Utils
/// <returns></returns>
[PublicAPI]
public static bool HasAnyFlags<T>(T value, T other)
where T : struct, IConvertible
{
T intersection = GetFlagsIntersection(value, other);
return HasAnyFlags(intersection);
@@ -445,6 +458,7 @@ namespace ICD.Common.Utils
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static T Parse<T>(string data, bool ignoreCase)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -466,6 +480,7 @@ namespace ICD.Common.Utils
/// <param name="result"></param>
/// <returns></returns>
public static bool TryParse<T>(string data, bool ignoreCase, out T result)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -492,6 +507,7 @@ namespace ICD.Common.Utils
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static T ParseStrict<T>(string data, bool ignoreCase)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -524,6 +540,7 @@ namespace ICD.Common.Utils
/// <param name="result"></param>
/// <returns></returns>
public static bool TryParseStrict<T>(string data, bool ignoreCase, out T result)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -541,21 +558,6 @@ namespace ICD.Common.Utils
}
}
/// <summary>
/// Converts the given enum value to an Enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static Enum ToEnum<T>(T value)
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
return (Enum)(object)value;
}
#endregion
}
}

View File

@@ -12,51 +12,49 @@ namespace ICD.Common.Utils.Extensions
/// <param name="value">Flag to check for</param>
/// <returns></returns>
[PublicAPI]
public static bool HasFlag(this Enum extends, Enum value)
public static bool HasFlag<T>(this T extends, T value)
where T : struct, IConvertible
{
if (extends == null)
throw new ArgumentNullException("extends");
if (!EnumUtils.IsEnum(extends))
throw new ArgumentException(string.Format("{0} is not an enum", extends.GetType().Name), "extends");
if (value == null)
throw new ArgumentNullException("value");
if (!EnumUtils.IsEnum(value))
throw new ArgumentException(string.Format("{0} is not an enum", value.GetType().Name), "value");
if (EnumUtils.HasMultipleFlags(value))
throw new ArgumentException("Value has multiple flags", "value");
return extends.HasFlags(value);
return EnumUtils.HasFlag(extends, value);
}
/// <summary>
/// Check to see if a flags enumeration has all of the given flags set.
/// </summary>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <param name="values"></param>
/// <returns></returns>
[PublicAPI]
public static bool HasFlags(this Enum extends, Enum value)
public static bool HasFlags<T>(this T extends, T values)
where T : struct, IConvertible
{
if (extends == null)
throw new ArgumentNullException("extends");
if (!EnumUtils.IsEnum(extends))
throw new ArgumentException(string.Format("{0} is not an enum", extends.GetType().Name), "extends");
if (value == null)
throw new ArgumentNullException("value");
if (!EnumUtils.IsEnum(values))
throw new ArgumentException(string.Format("{0} is not an enum", values.GetType().Name), "values");
// Not as good as the .NET 4 version of this function, but should be good enough
if (extends.GetType() != value.GetType())
{
string message = string.Format("Enumeration type mismatch. The flag is of type '{0}', was expecting '{1}'.",
value.GetType(), extends.GetType());
throw new ArgumentException(message);
}
int num = (int)(object)value;
return ((int)(object)extends & num) == num;
return EnumUtils.HasFlags(extends, values);
}
public static ushort ToUShort(this Enum extends)
/// <summary>
/// Returns the enum value as a
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI("S+")]
public static ushort ToUShort<T>(this T extends)
where T : struct, IConvertible
{
if (extends == null)
throw new ArgumentNullException("extends");
if (!EnumUtils.IsEnum(extends))
throw new ArgumentException(string.Format("{0} is not an enum", extends.GetType().Name), "extends");
return (ushort)(object)extends;
}

View File

@@ -155,6 +155,7 @@ namespace ICD.Common.Utils.Extensions
/// <returns></returns>
[PublicAPI]
public static T GetValueAsEnum<T>(this JsonReader extends)
where T : struct, IConvertible
{
if (extends == null)
throw new ArgumentNullException("extends");

View File

@@ -392,6 +392,7 @@ namespace ICD.Common.Utils.Xml
/// <returns></returns>
[PublicAPI]
public static T ReadElementContentAsEnum<T>(this IcdXmlReader extends, bool ignoreCase)
where T : struct, IConvertible
{
if (extends == null)
throw new ArgumentNullException("extends");

View File

@@ -422,6 +422,7 @@ namespace ICD.Common.Utils.Xml
/// <returns></returns>
[PublicAPI]
public static T ReadChildElementContentAsEnum<T>(string xml, string childElement, bool ignoreCase)
where T : struct, IConvertible
{
if (!EnumUtils.IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -608,7 +609,7 @@ namespace ICD.Common.Utils.Xml
/// <returns></returns>
[PublicAPI]
public static T? TryReadChildElementContentAsEnum<T>(string xml, string childElement, bool ignoreCase)
where T : struct
where T : struct, IConvertible
{
if (!EnumUtils.IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -628,6 +629,7 @@ namespace ICD.Common.Utils.Xml
/// <returns></returns>
[PublicAPI]
public static bool TryReadChildElementContentAsEnum<T>(string xml, string childElement, bool ignoreCase, out T output)
where T : struct, IConvertible
{
if (!EnumUtils.IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
@@ -731,6 +733,7 @@ namespace ICD.Common.Utils.Xml
/// <returns></returns>
[PublicAPI]
public static T ReadElementContentAsEnum<T>(string xml, bool ignoreCase)
where T : struct, IConvertible
{
if (!EnumUtils.IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));