Skip to content

Instantly share code, notes, and snippets.

@cybermaxs
Last active August 29, 2015 14:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cybermaxs/99f5acbb05b978893727 to your computer and use it in GitHub Desktop.
Save cybermaxs/99f5acbb05b978893727 to your computer and use it in GitHub Desktop.
Yet another fast Enum.ToString() Implementation. Read explanations http://cybermaxs.wordpress.com/2014/10/03/the-importance-of-useless-micro-optimization/
using Ideafixxxer.Generics;
using System;
using System.Diagnostics;
using System.Text;
namespace EnumBenchmarks
{
public enum MyEnum
{
Undefined = 0,
One,
Two,
Three
}
class Benchmark
{
const int ITERATIONS = 50000;
static class Methods
{
public static string BasicMethod()
{
return MyEnum.One.ToString() + "|" + MyEnum.Two + "|" + MyEnum.Three;
}
public static string BasicMethodWithJoin()
{
return string.Join("|", MyEnum.One, MyEnum.Two, MyEnum.Three);
}
public static string ExtMethodWithJoin()
{
return string.Join("|", MyEnum.One.AsString(), MyEnum.Two.AsString(), MyEnum.Three.AsString());
}
public static string IdeafixxxerWithJoin()
{
return string.Join("|", Enum<MyEnum>.ToString(MyEnum.One), Enum<MyEnum>.ToString(MyEnum.Two), Enum<MyEnum>.ToString(MyEnum.Three));
}
public static string ExtMethodWithStringBuilder()
{
var sb = new StringBuilder();
sb.Append(MyEnum.One.AsString());
sb.Append("|");
sb.Append(MyEnum.Two.AsString());
sb.Append("|");
sb.Append(MyEnum.Three.AsString());
return sb.ToString();
}
}
static void Main(string[] args)
{
Console.WriteLine("=== START ===");
BenchIt(Methods.BasicMethod, "BasicMethod");
BenchIt(Methods.BasicMethodWithJoin, "BasicMethodWithJoin");
BenchIt(Methods.ExtMethodWithJoin, "ExtMethodWithJoin");
BenchIt(Methods.IdeafixxxerWithJoin, "IdeafixxxerWithJoin");
BenchIt(Methods.ExtMethodWithStringBuilder, "ExtMethodWithStringBuilder");
Console.WriteLine("========");
#if DEBUG
Console.ReadKey();
#endif
}
private static void BenchIt(Func<string> func, string name, int iterations = ITERATIONS)
{
// warm up
func();
var watch = new Stopwatch();
// clean up
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
watch.Start();
for (int i = 0; i < iterations; i++)
{
func();
}
watch.Stop();
Console.Write(name + " => ");
Console.WriteLine("{0:0.00} ms ({1:N0} ticks) (over {2:N0} iterations), {3:N0} ops/millisecond", watch.ElapsedMilliseconds, watch.ElapsedTicks, iterations, (double)iterations / watch.ElapsedMilliseconds);
}
}
}
//source : http://www.codeproject.com/Articles/278820/Optimized-Enum-ToString
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ideafixxxer.Generics
{
#region Enum
/// <summary>
/// Helper class for enum types
/// </summary>
/// <typeparam name="T">Must be enum type (declared using <c>enum</c> keyword)</typeparam>
public static class Enum<T> where T : struct, IConvertible
{
private static readonly EnumConverter Converter;
#region Nested types
abstract class EnumConverter
{
public abstract string ToStringInternal(int value);
public abstract int ParseInternal(string value, bool ignoreCase, bool parseNumber);
public abstract bool TryParseInternal(string value, bool ignoreCase, bool parseNumber, out int result);
}
class ArrayEnumConverter : EnumConverter
{
private readonly string[] _names = Enum.GetNames(typeof(T));
public ArrayEnumConverter(string[] names)
{
_names = names;
}
public override string ToStringInternal(int value)
{
return value >= 0 && value < _names.Length ? _names[value] : value.ToString();
}
public override int ParseInternal(string value, bool ignoreCase, bool parseNumber)
{
if (value == null) throw new ArgumentNullException("value");
if (value.Length == 0) throw new ArgumentException("Value is empty", "value");
char f = value[0];
if (parseNumber && (Char.IsDigit(f) || f == '+' || f == '-'))
return Int32.Parse(value);
StringComparison stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
for (int i = 0; i < _names.Length; i++)
if (_names[i].Equals(value, stringComparison))
return i;
throw new ArgumentException("Enum value wasn't found", "value");
}
public override bool TryParseInternal(string value, bool ignoreCase, bool parseNumber, out int result)
{
result = 0;
if (String.IsNullOrEmpty(value)) return false;
char f = value[0];
if (parseNumber && (Char.IsDigit(f) || f == '+' || f == '-'))
{
int i;
if (Int32.TryParse(value, out i))
{
result = i;
return true;
}
return false;
}
StringComparison stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
for (int i = 0; i < _names.Length; i++)
if (_names[i].Equals(value, stringComparison))
{
result = i;
return true;
}
return false;
}
}
class DictionaryEnumConverter : EnumConverter
{
protected readonly Dictionary<int, string> _dic;
public DictionaryEnumConverter(string[] names, T[] values)
{
_dic = new Dictionary<int, string>(names.Length);
for (int j = 0; j < names.Length; j++)
_dic.Add(Convert.ToInt32(values[j], null), names[j]);
}
public override string ToStringInternal(int value)
{
string n;
return _dic.TryGetValue(value, out n) ? n : value.ToString();
}
public override int ParseInternal(string value, bool ignoreCase, bool parseNumber)
{
if (value == null) throw new ArgumentNullException("value");
if (value.Length == 0) throw new ArgumentException("Value is empty", "value");
char f = value[0];
if (parseNumber && (Char.IsDigit(f) || f == '+' || f == '-'))
return Int32.Parse(value);
StringComparison stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
foreach (KeyValuePair<int, string> pair in _dic)
{
if (pair.Value.Equals(value, stringComparison))
return pair.Key;
}
throw new ArgumentException("Enum value wasn't found", "value");
}
public override bool TryParseInternal(string value, bool ignoreCase, bool parseNumber, out int result)
{
result = 0;
if (String.IsNullOrEmpty(value)) return false;
char f = value[0];
if (parseNumber && (Char.IsDigit(f) || f == '+' || f == '-'))
{
int i;
if (Int32.TryParse(value, out i))
{
result = i;
return true;
}
return false;
}
StringComparison stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
foreach (KeyValuePair<int, string> pair in _dic)
{
if (pair.Value.Equals(value, stringComparison))
{
result = pair.Key;
return true;
}
}
return false;
}
}
class FlagsEnumConverter : DictionaryEnumConverter
{
private readonly uint[] _values;
private static readonly string[] Seps = new[] { "," };
public FlagsEnumConverter(string[] names, T[] values)
: base(names, values)
{
_values = new uint[values.Length];
for (int i = 0; i < values.Length; i++)
_values[i] = values[i].ToUInt32(null);
}
public override string ToStringInternal(int value)
{
string n;
if (_dic.TryGetValue(value, out n)) return n;
var sb = new StringBuilder();
const string sep = ", ";
uint uval;
unchecked
{
uval = (uint)value;
for (int i = _values.Length - 1; i >= 0; i--)
{
uint v = _values[i];
if (v == 0) continue;
if ((v & uval) == v)
{
uval &= ~v;
sb.Insert(0, sep).Insert(0, _dic[(int)v]);
}
}
}
return uval == 0 && sb.Length > sep.Length ? sb.ToString(0, sb.Length - sep.Length) : value.ToString();
}
public override int ParseInternal(string value, bool ignoreCase, bool parseNumber)
{
string[] parts = value.Split(Seps, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 1) return base.ParseInternal(value, ignoreCase, parseNumber);
int val = 0;
for (int i = 0; i < parts.Length; i++)
{
string part = parts[i];
int t = base.ParseInternal(part.Trim(), ignoreCase, parseNumber);
val |= t;
}
return val;
}
public override bool TryParseInternal(string value, bool ignoreCase, bool parseNumber, out int result)
{
string[] parts = value.Split(Seps, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 1) return base.TryParseInternal(value, ignoreCase, parseNumber, out result);
int val = 0;
for (int i = 0; i < parts.Length; i++)
{
string part = parts[i];
int t;
if (!base.TryParseInternal(part.Trim(), ignoreCase, parseNumber, out t))
{
result = 0;
return false;
}
val |= t;
}
result = val;
return true;
}
}
#endregion
static Enum()
{
Type type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException("Generic Enum type works only with enums");
string[] names = Enum.GetNames(type);
var values = (T[])Enum.GetValues(type);
if (type.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0)
{
Converter = new FlagsEnumConverter(names, values);
}
else
{
if (values.Where((t, i) => Convert.ToInt32(t) != i).Any())
{
Converter = new DictionaryEnumConverter(names, values);
}
if (Converter == null)
Converter = new ArrayEnumConverter(names);
}
}
/// <summary>
/// Converts enum value to string
/// </summary>
/// <param name="value">Enum value converted to int</param>
/// <returns>If <paramref name="value"/> is defined, the enum member name; otherwise the string representation of the <paramref name="value"/>.
/// If <see cref="FlagsAttribute"/> is applied, can return comma-separated list of values</returns>
public static string ToString(int value)
{
return Converter.ToStringInternal(value);
}
/// <summary>
/// Converts enum value to string
/// </summary>
/// <param name="value">Enum value</param>
/// <returns>If <paramref name="value"/> is defined, the enum member name; otherwise the string representation of the <paramref name="value"/>.
/// If <see cref="FlagsAttribute"/> is applied, can return comma-separated list of values</returns>
public static string ToString(T value)
{
return Converter.ToStringInternal(value.ToInt32(null));
}
public static T Parse(string value, bool ignoreCase = false, bool parseNumeric = true)
{
return (T)Enum.ToObject(typeof(T), Converter.ParseInternal(value, ignoreCase, parseNumeric));
}
public static bool TryParse(string value, bool ignoreCase, bool parseNumeric, out T result)
{
int ir;
bool b = Converter.TryParseInternal(value, ignoreCase, parseNumeric, out ir);
result = (T)Enum.ToObject(typeof(T), ir);
return b;
}
public static bool TryParse(string value, bool ignoreCase, out T result)
{
int ir;
bool b = Converter.TryParseInternal(value, ignoreCase, true, out ir);
result = (T)Enum.ToObject(typeof(T), ir);
return b;
}
public static bool TryParse(string value, out T result)
{
int ir;
bool b = Converter.TryParseInternal(value, false, true, out ir);
result = (T)Enum.ToObject(typeof(T), ir);
return b;
}
}
#endregion
}
using System;
using System.Collections.Generic;
namespace EnumBenchmarks
{
public static class EnumExtensions
{
public static class EnumCache<TEnum>
{
public static Dictionary<TEnum, string> Values = new Dictionary<TEnum, string>();
static EnumCache()
{
var t = typeof(TEnum);
var values = (TEnum[])Enum.GetValues(t);
var names = Enum.GetNames(t);
for (var i = 0; i < values.Length; i++)
{
Values.Add(values[i], names[i]);
}
}
public static string Get(TEnum enm)
{
return Values[enm];
}
}
public static string AsString<TEnum>(this TEnum enm) where TEnum : struct, IConvertible
{
return EnumCache<TEnum>.Values[enm];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment