Здравствуйте, 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>>