Skip to content

Instantly share code, notes, and snippets.

@Alxandr
Created June 20, 2024 06:37
Show Gist options
  • Save Alxandr/e94484d01c935fe52217d2ff64080cc1 to your computer and use it in GitHub Desktop.
Save Alxandr/e94484d01c935fe52217d2ff64080cc1 to your computer and use it in GitHub Desktop.
EnumExtensions
using CommunityToolkit.Diagnostics;
using System.Runtime.CompilerServices;
namespace Namespace;
internal static class EnumExtensions
{
/// <summary>
/// Returns a value indicating whether the specified value has any of the specified flags set.
/// </summary>
/// <typeparam name="T">The enum kind.</typeparam>
/// <param name="value">The enum value to check if contains any flags.</param>
/// <param name="flags">The flags to check.</param>
/// <returns>
/// <see langword="true"/> if <paramref name="value"/> contains any of the flags set in <paramref name="flags"/>,
/// otherwise <see langword="false"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasAnyOf<T>(this T value, T flags)
where T : struct, Enum
{
var underlyingType = Enum.GetUnderlyingType(typeof(T));
if (underlyingType == typeof(byte) || underlyingType == typeof(sbyte))
{
ref byte selfValue = ref Unsafe.As<T, byte>(ref value);
ref byte flagsValue = ref Unsafe.As<T, byte>(ref flags);
return flagsValue == 0 | (selfValue & flagsValue) != 0;
}
if (underlyingType == typeof(short) || underlyingType == typeof(ushort))
{
ref short selfValue = ref Unsafe.As<T, short>(ref value);
ref short flagsValue = ref Unsafe.As<T, short>(ref flags);
return flagsValue == 0 | (selfValue & flagsValue) != 0;
}
if (underlyingType == typeof(int) || underlyingType == typeof(uint))
{
ref int selfValue = ref Unsafe.As<T, int>(ref value);
ref int flagsValue = ref Unsafe.As<T, int>(ref flags);
return flagsValue == 0 | (selfValue & flagsValue) != 0;
}
if (underlyingType == typeof(long) || underlyingType == typeof(ulong))
{
ref long selfValue = ref Unsafe.As<T, long>(ref value);
ref long flagsValue = ref Unsafe.As<T, long>(ref flags);
return flagsValue == 0 | (selfValue & flagsValue) != 0;
}
return ThrowHelper.ThrowArgumentException<bool>("Invalid enum type.");
}
}
namespace Namespace.Tests;
public class EnumExtensionsTests
{
public class ByteEnumTests()
: EnumTests<EByte>(EByte.None, EByte.A, EByte.B, EByte.C, EByte.A | EByte.B, EByte.B | EByte.C, EByte.A | EByte.B | EByte.C)
{
}
public class SByteEnumTests()
: EnumTests<ESByte>(ESByte.None, ESByte.A, ESByte.B, ESByte.C, ESByte.A | ESByte.B, ESByte.B | ESByte.C, ESByte.A | ESByte.B | ESByte.C)
{
}
public class ShortEnumTests()
: EnumTests<EShort>(EShort.None, EShort.A, EShort.B, EShort.C, EShort.A | EShort.B, EShort.B | EShort.C, EShort.A | EShort.B | EShort.C)
{
}
public class UShortEnumTests()
: EnumTests<EUShort>(EUShort.None, EUShort.A, EUShort.B, EUShort.C, EUShort.A | EUShort.B, EUShort.B | EUShort.C, EUShort.A | EUShort.B | EUShort.C)
{
}
public class IntEnumTests()
: EnumTests<EInt>(EInt.None, EInt.A, EInt.B, EInt.C, EInt.A | EInt.B, EInt.B | EInt.C, EInt.A | EInt.B | EInt.C)
{
}
public class UIntEnumTests()
: EnumTests<EUInt>(EUInt.None, EUInt.A, EUInt.B, EUInt.C, EUInt.A | EUInt.B, EUInt.B | EUInt.C, EUInt.A | EUInt.B | EUInt.C)
{
}
public class LongEnumTests()
: EnumTests<ELong>(ELong.None, ELong.A, ELong.B, ELong.C, ELong.A | ELong.B, ELong.B | ELong.C, ELong.A | ELong.B | ELong.C)
{
}
public class ULongEnumTests()
: EnumTests<EULong>(EULong.None, EULong.A, EULong.B, EULong.C, EULong.A | EULong.B, EULong.B | EULong.C, EULong.A | EULong.B | EULong.C)
{
}
public abstract class EnumTests<T>
where T : struct, Enum
{
protected EnumTests(
T none,
T a,
T b,
T c,
T ab,
T bc,
T abc)
{
None = none;
A = a;
B = b;
C = c;
Ab = ab;
Bc = bc;
Abc = abc;
}
public T None { get; }
public T A { get; }
public T B { get; }
public T C { get; }
public T Ab { get; }
public T Bc { get; }
public T Abc { get; }
[Fact]
public void HasAnyOf_All_HasNone()
{
None.HasAnyOf(None).Should().BeTrue();
A.HasAnyOf(None).Should().BeTrue();
B.HasAnyOf(None).Should().BeTrue();
C.HasAnyOf(None).Should().BeTrue();
Ab.HasAnyOf(None).Should().BeTrue();
Bc.HasAnyOf(None).Should().BeTrue();
Abc.HasAnyOf(None).Should().BeTrue();
}
[Fact]
public void HasAnyOf_None_HasNothing()
{
None.HasAnyOf(A).Should().BeFalse();
None.HasAnyOf(B).Should().BeFalse();
None.HasAnyOf(C).Should().BeFalse();
None.HasAnyOf(Ab).Should().BeFalse();
None.HasAnyOf(Bc).Should().BeFalse();
None.HasAnyOf(Abc).Should().BeFalse();
}
[Fact]
public void HasAnyOf_All_HasSelf()
{
None.HasAnyOf(None).Should().BeTrue();
A.HasAnyOf(A).Should().BeTrue();
B.HasAnyOf(B).Should().BeTrue();
C.HasAnyOf(C).Should().BeTrue();
Ab.HasAnyOf(Ab).Should().BeTrue();
Bc.HasAnyOf(Bc).Should().BeTrue();
Abc.HasAnyOf(Abc).Should().BeTrue();
}
[Fact]
public void HasAnyOf_Single_DoesNotHaveOther()
{
A.HasAnyOf(B).Should().BeFalse();
A.HasAnyOf(C).Should().BeFalse();
B.HasAnyOf(A).Should().BeFalse();
B.HasAnyOf(C).Should().BeFalse();
C.HasAnyOf(A).Should().BeFalse();
C.HasAnyOf(B).Should().BeFalse();
}
[Fact]
public void HasAnyOf_Multiple_HasAnyOfOne()
{
Ab.HasAnyOf(A).Should().BeTrue();
Ab.HasAnyOf(B).Should().BeTrue();
Bc.HasAnyOf(B).Should().BeTrue();
Bc.HasAnyOf(C).Should().BeTrue();
Abc.HasAnyOf(A).Should().BeTrue();
Abc.HasAnyOf(B).Should().BeTrue();
Abc.HasAnyOf(C).Should().BeTrue();
}
[Fact]
public void HasAnyOf_Multiple_DoesNotHaveOther()
{
Ab.HasAnyOf(C).Should().BeFalse();
Bc.HasAnyOf(A).Should().BeFalse();
}
[Fact]
public void HasAnyOf_PartialOverlap_ReturnsTrue()
{
Ab.HasAnyOf(Bc).Should().BeTrue();
Bc.HasAnyOf(Ab).Should().BeTrue();
}
[Fact]
public void HasAnyOf_Superset_ReturnsTrue()
{
A.HasAnyOf(Ab).Should().BeTrue();
B.HasAnyOf(Ab).Should().BeTrue();
B.HasAnyOf(Bc).Should().BeTrue();
C.HasAnyOf(Bc).Should().BeTrue();
A.HasAnyOf(Abc).Should().BeTrue();
B.HasAnyOf(Abc).Should().BeTrue();
C.HasAnyOf(Abc).Should().BeTrue();
}
[Fact]
public void HasAnyOf_Subset_ReturnsTrue()
{
Ab.HasAnyOf(A).Should().BeTrue();
Ab.HasAnyOf(B).Should().BeTrue();
Bc.HasAnyOf(B).Should().BeTrue();
Bc.HasAnyOf(C).Should().BeTrue();
Abc.HasAnyOf(A).Should().BeTrue();
Abc.HasAnyOf(B).Should().BeTrue();
Abc.HasAnyOf(C).Should().BeTrue();
Abc.HasAnyOf(Ab).Should().BeTrue();
Abc.HasAnyOf(Bc).Should().BeTrue();
}
}
[Flags]
public enum EByte : byte
{
None = 0,
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
}
[Flags]
public enum ESByte : sbyte
{
None = 0,
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
}
[Flags]
public enum EShort : short
{
None = 0,
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
}
[Flags]
public enum EUShort : ushort
{
None = 0,
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
}
[Flags]
public enum EInt : int
{
None = 0,
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
}
[Flags]
public enum EUInt : uint
{
None = 0,
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
}
[Flags]
public enum ELong : long
{
None = 0,
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
}
[Flags]
public enum EULong : ulong
{
None = 0,
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment