Хочется для enum реализовать простенькие функции для битовых операций, но это работает в десятки раз медленнее, чем нужно.
Нету никаких способов чтобы это ускорить?
Жаль, что в C# даже нету простеньких препроцессорных текстовых макросов.
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static bool HasAnyFlag<T>(T en1, T en2) where T : IConvertible
{
return (en1.ToInt32(null) & en2.ToInt32(null)) != 0;
}
//...
HasAnyFlag((int)f, (int)(SomeFlags.F1 | SomeFlags.F2)); //Быстро.
HasAnyFlag(f, SomeFlags.F1 | SomeFlags.F2); //В десятки раз медленнее!
Здравствуйте, Silver_S, Вы писали:
S_S>Хочется для enum реализовать простенькие функции для битовых операций, но это работает в десятки раз медленнее, чем нужно.
S_S>Нету никаких способов чтобы это ускорить?
S_S>Жаль, что в C# даже нету простеньких препроцессорных текстовых макросов.
Ну вообще то есть
Генераторы источников
Можешь нагенерить что хочешь/
Roles обещали, но так их и нет
http://rsdn.org/forum/dotnet/7749568.flatАвтор: varenikAA
Дата: 08.06.20
Здравствуйте, Silver_S, Вы писали:
S_S>Хочется для enum реализовать простенькие функции для битовых операций, но это работает в десятки раз медленнее, чем нужно.
S_S>Нету никаких способов чтобы это ускорить?
Если используешь .NET 5.0 и выше, с включенным Tieried JIT, то есть способ сделать это быстро и эффективно
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe bool IsAnyFlagMatch<T>(this T value, T flag) where T : unmanaged, Enum
{
if (TypeHelper<T>.TypeCode == TypeCode.Byte)
{
var v = (int)Unsafe.As<T, byte>(ref value);
var f = (int)Unsafe.As<T, byte>(ref flag);
return (v & f) != 0 ? true : false;
}
if (TypeHelper<T>.TypeCode == TypeCode.SByte)
{
var v = (int)Unsafe.As<T, sbyte>(ref value);
var f = (int)Unsafe.As<T, sbyte>(ref flag);
return (v & f) != 0 ? true : false;
}
if (TypeHelper<T>.TypeCode == TypeCode.Int16)
{
var v = (int)Unsafe.As<T, short>(ref value);
var f = (int)Unsafe.As<T, short>(ref flag);
return (v & f) != 0 ? true : false;
}
if (TypeHelper<T>.TypeCode == TypeCode.UInt16)
{
var v = (int)Unsafe.As<T, ushort>(ref value);
var f = (int)Unsafe.As<T, ushort>(ref flag);
return (v & f) != 0 ? true : false;
}
if (sizeof(T) == 4)
{
var v = Unsafe.As<T, int>(ref value);
var f = Unsafe.As<T, int>(ref flag);
return (v & f) != 0 ? true : false;
}
if (sizeof(T) == 8)
{
var f = Unsafe.As<T, long>(ref flag);
return (Unsafe.As<T, long>(ref value) & f) != 0 ? true : false;
}
return false;
}
Где
TypeHelper<T>.TypeCode это:
public static class TypeHelper<T>
{
public static readonly TypeCode TypeCode = Type.GetTypeCode(GetUnderlyingType());
private static Type GetUnderlyingType()
{
var type = typeof(T);
if (IsNullable(type))
type = type.GetGenericArguments()[0];
return type.IsEnum
? type.GetEnumUnderlyingType()
: type;
}
private static bool IsNullable(Type type) =>
type.IsGenericType && !type.IsGenericTypeDefinition && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
Можно спросить, почему
sizeof(T) ну или
Unsafe.SizeOf<T> было недостаточно, то на типах, размерностью менее
int имеет значение знаковость типа, и если не угадать, то JIT для манипуляции с ними задействует стек и менее эффективный код.
Tired compilation нужен, чтобы вот это
TypeHelper<T>.TypeCode устранялось и счиаталось за константу.
PS. Ну и не забываем, что Enum.HasFlag с .NET6 теперь считается интринсиком и разворачивается джитом в эффективный код, если на момент компиляции известен тип
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Здравствуйте, Silver_S, Вы писали:
S_S>Хочется для enum реализовать простенькие функции для битовых операций, но это работает в десятки раз медленнее, чем нужно.
S_S>Нету никаких способов чтобы это ускорить?
https://github.com/rsdn/CodeJam/blob/master/CodeJam.Main/EnumHelper.cs... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Здравствуйте, Serginio1, Вы писали:
S>Roles обещали, но так их и нет http://rsdn.org/forum/dotnet/7749568.flatАвтор: varenikAA
Дата: 08.06.20
Это уже почти есть, при активации preview. Если глянуть декомпиляцию для "int" там уже есть наследование от кучи интерфейсов со статическими методами, в том числе и от IBitwiseOperators<int, int, int>.
Только вот у enum нету никаких подобных интерфейсов.
Здравствуйте, Silver_S, Вы писали:
S_S>Только вот у enum нету никаких подобных интерфейсов.
enum без каких либо последствий для перфоманса кастится в свой underlying тип.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Обход религиозных запретов с помощью черной магии
public static class HackEnumConvert<TEnumType> where TEnumType : struct, Enum
{
private static readonly Func<TEnumType, int> Wrapper;
public static int ToInt(TEnumType enu) {
return Wrapper(enu);
}
static HackEnumConvert() {
var p = Expression.Parameter(typeof(TEnumType), null);
var c = Expression.ConvertChecked(p, typeof(int));
Wrapper = Expression.Lambda<Func<TEnumType, int>>(c, p).Compile();
}
}
HackEnumConvert<EMyEnum>.ToInt(value);