Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update EnumExtensions.cs #31

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 30 additions & 73 deletions Assets/EasyButtons/Editor/Utils/EnumExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,83 +1,40 @@
namespace EasyButtons.Editor.Utils
namespace EasyButtons.Editor.Utils
{
using System;

public static class EnumExtensions
{
/// <summary>
/// Allocation-less version of <see cref="Enum.HasFlag"/> that still runs very fast.
/// </summary>
/// <param name="thisEnum">The enum to check for flags.</param>
/// <param name="flag">The flag to search for in <paramref name="thisEnum"/>.</param>
/// <typeparam name="TEnum">The type of enum.</typeparam>
/// <returns>Whether <paramref name="thisEnum"/> contains the specified <paramref name="flag"/>.</returns>
/// <exception cref="Exception">If it was not possible to determine the underlying type of the enum.</exception>
/// <remarks>
/// Taken from here https://forum.unity.com/threads/c-hasaflag-method-extension-how-to-not-create-garbage-allocation.616924/#post-4420699
/// </remarks>
public static bool ContainsFlag<TEnum>(this TEnum thisEnum, TEnum flag) where TEnum :
#if CSHARP_7_3_OR_NEWER
unmanaged, Enum
#else
struct
#endif
public static bool ContainsFlag<TEnum>(this TEnum thisEnum, TEnum flag) where TEnum : struct, Enum
{
unsafe
Type enumType = typeof(TEnum);
if (!enumType.IsEnum)
{
#if CSHARP_7_3_OR_NEWER
switch (sizeof(TEnum))
{
case 1:
return (*(byte*)&thisEnum & *(byte*)&flag) > 0;
case 2:
return (*(ushort*)&thisEnum & *(ushort*)&flag) > 0;
case 4:
return (*(uint*)&thisEnum & *(uint*)&flag) > 0;
case 8:
return (*(ulong*)&thisEnum & *(ulong*)&flag) > 0;
default:
throw new Exception("Size does not match a known Enum backing type.");
}
#else
switch (UnsafeUtility.SizeOf<TEnum>())
{
case 1:
{
byte valLhs = 0;
UnsafeUtility.CopyStructureToPtr(ref lhs, &valLhs);
byte valRhs = 0;
UnsafeUtility.CopyStructureToPtr(ref rhs, &valRhs);
return (valLhs & valRhs) > 0;
}
case 2:
{
ushort valLhs = 0;
UnsafeUtility.CopyStructureToPtr(ref lhs, &valLhs);
ushort valRhs = 0;
UnsafeUtility.CopyStructureToPtr(ref rhs, &valRhs);
return (valLhs & valRhs) > 0;
}
case 4:
{
uint valLhs = 0;
UnsafeUtility.CopyStructureToPtr(ref lhs, &valLhs);
uint valRhs = 0;
UnsafeUtility.CopyStructureToPtr(ref rhs, &valRhs);
return (valLhs & valRhs) > 0;
}
case 8:
{
ulong valLhs = 0;
UnsafeUtility.CopyStructureToPtr(ref lhs, &valLhs);
ulong valRhs = 0;
UnsafeUtility.CopyStructureToPtr(ref rhs, &valRhs);
return (valLhs & valRhs) > 0;
}
default:
throw new Exception("Size does not match a known Enum backing type.");
}
#endif
throw new ArgumentException("TEnum must be an enumerated type.");
}

Type underlyingType = Enum.GetUnderlyingType(enumType);

switch (Type.GetTypeCode(underlyingType))
{
case TypeCode.Byte:
return (((byte)(object)thisEnum & (byte)(object)flag) > 0);
case TypeCode.SByte:
return (((sbyte)(object)thisEnum & (sbyte)(object)flag) > 0);
case TypeCode.Int16:
return (((short)(object)thisEnum & (short)(object)flag) > 0);
case TypeCode.UInt16:
return (((ushort)(object)thisEnum & (ushort)(object)flag) > 0);
case TypeCode.Int32:
return (((int)(object)thisEnum & (int)(object)flag) > 0);
case TypeCode.UInt32:
return (((uint)(object)thisEnum & (uint)(object)flag) > 0);
case TypeCode.Int64:
return (((long)(object)thisEnum & (long)(object)flag) > 0);
case TypeCode.UInt64:
return (((ulong)(object)thisEnum & (ulong)(object)flag) > 0);
default:
throw new Exception("Underlying type of the enum is not supported.");
}
}
}
}
}