Created
June 20, 2024 06:37
-
-
Save Alxandr/e94484d01c935fe52217d2ff64080cc1 to your computer and use it in GitHub Desktop.
EnumExtensions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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."); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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