From a6f8ec0fdeb47d2a6d218dd09f32e17af342298d Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Thu, 1 May 2025 00:05:41 +0200 Subject: [PATCH 01/15] feat(.net): adapted the API to match the js API --- .../.idea/codeStyles/codeStyleConfig.xml | 5 + dotnet/Multiflag.sln.DotSettings | 3 + dotnet/Multiflag/Base64BitflagSet.cs | 53 +++---- dotnet/Multiflag/Base64Format/Base64Codec.cs | 34 ++++- .../Bitflags/BigintBitManipulator.cs | 33 ++++- dotnet/Multiflag/Bitflags/BitManipulator.cs | 75 +++++----- dotnet/Multiflag/Bitflags/IBitManipulator.cs | 27 ++++ .../Multiflag/Bitflags/U16BitManipulator.cs | 20 ++- .../Multiflag/Bitflags/U32BitManipulator.cs | 20 ++- .../Multiflag/Bitflags/U64BitManipulator.cs | 20 ++- dotnet/Multiflag/Bitflags/U8BitManipulator.cs | 20 ++- dotnet/Multiflag/CollectionFlagSet.cs | 55 ++++++++ dotnet/Multiflag/DynamicBitflagSet.cs | 26 +++- dotnet/Multiflag/EnumBitflagSet.cs | 54 +++++-- .../Enumerators/Base64FlagEnumerator.cs | 93 ++++++++++++ .../Enumerators/EnumFlagEnumerator.cs | 70 +++++++++ .../Enumerators/NumericFlagEnumerator.cs | 70 +++++++++ dotnet/Multiflag/Flag.cs | 67 ++++----- dotnet/Multiflag/FlagSet.cs | 133 +++++++++++++----- dotnet/Multiflag/HashedFlagSet.cs | 68 --------- dotnet/Multiflag/ISetOperations.cs | 30 ++++ dotnet/Multiflag/ReusedFlagValueException.cs | 2 +- dotnet/Multiflag/U16BitflagSet.cs | 26 +++- dotnet/Multiflag/U32BitflagSet.cs | 26 +++- dotnet/Multiflag/U64BitflagSet.cs | 26 +++- dotnet/Multiflag/U8BitflagSet.cs | 26 +++- dotnet/Multiflag/ValueFlag.cs | 37 +++++ dotnet/Tests/Base64BitflagSetTests.cs | 93 ++++++++++-- ...gSetTests.cs => CollectionFlagSetTests.cs} | 10 +- 29 files changed, 928 insertions(+), 294 deletions(-) create mode 100644 dotnet/.idea/.idea.Multiflag/.idea/codeStyles/codeStyleConfig.xml create mode 100644 dotnet/Multiflag.sln.DotSettings create mode 100644 dotnet/Multiflag/Bitflags/IBitManipulator.cs create mode 100644 dotnet/Multiflag/CollectionFlagSet.cs create mode 100644 dotnet/Multiflag/Enumerators/Base64FlagEnumerator.cs create mode 100644 dotnet/Multiflag/Enumerators/EnumFlagEnumerator.cs create mode 100644 dotnet/Multiflag/Enumerators/NumericFlagEnumerator.cs delete mode 100644 dotnet/Multiflag/HashedFlagSet.cs create mode 100644 dotnet/Multiflag/ISetOperations.cs create mode 100644 dotnet/Multiflag/ValueFlag.cs rename dotnet/Tests/{HashedFlagSetTests.cs => CollectionFlagSetTests.cs} (88%) diff --git a/dotnet/.idea/.idea.Multiflag/.idea/codeStyles/codeStyleConfig.xml b/dotnet/.idea/.idea.Multiflag/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/dotnet/.idea/.idea.Multiflag/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/dotnet/Multiflag.sln.DotSettings b/dotnet/Multiflag.sln.DotSettings new file mode 100644 index 0000000..fb4ecac --- /dev/null +++ b/dotnet/Multiflag.sln.DotSettings @@ -0,0 +1,3 @@ + + <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="True" Prefix="" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="True" Prefix="" Suffix="" Style="aaBb" /></Policy> \ No newline at end of file diff --git a/dotnet/Multiflag/Base64BitflagSet.cs b/dotnet/Multiflag/Base64BitflagSet.cs index 028ad4f..73d322a 100644 --- a/dotnet/Multiflag/Base64BitflagSet.cs +++ b/dotnet/Multiflag/Base64BitflagSet.cs @@ -1,5 +1,9 @@ using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; using Multiflag.Base64Format; +using Multiflag.Enumerators; namespace Multiflag { @@ -9,41 +13,20 @@ namespace Multiflag ///
/// This format is compact, easily serializable and allows for an unlimited /// number of flags, but is specific to Multiflag. - /// Use instead if you need the data to be + /// Use instead if you need the data to be /// easily understandable by other systems. /// - public class Base64BitflagSet : FlagSet + public class Base64BitflagSet : FlagSet { - /// - /// Creates a flag from an index. - /// The value of the flag will be 2 to the power of . - /// - /// The index of the flag. It must be greater than or equal to one. - /// Other flags required for this flag to be set. - /// A flag bound to this set. - /// - /// If one of the parents doesn't belong to the same . - /// - /// - /// If another flag has already been created with the same index. - /// - public Flag Flag(int index, params Flag[] parents) - { - if (index < 1) - { - throw new ArgumentOutOfRangeException(nameof(index), "Indices should be greater than or equal to 1."); - } - - return this.Flag(Base64Codec.EncodeSingleFlag(index), parents); - } - /// - protected override sealed void CheckValue(string value) + protected override sealed string WrapValue(int value) { - if (!Base64Codec.DecodesToSingleFlag(value)) + if (value < 1) { - throw new InvalidBitflagValueException(); + throw new ArgumentOutOfRangeException(nameof(value), "Indices should be greater than or equal to 1."); } + + return Base64Codec.EncodeSingleFlag(value); } /// @@ -53,15 +36,15 @@ public override sealed string Empty() } /// - public override sealed bool IsEmpty(string flags) + public override sealed string Union(string first, string second) { - return Base64Codec.DecodesToZero(flags); + return Base64Codec.BitwiseOr(first, second); } /// - public override sealed string Union(string first, string second) + public override sealed string Intersection(string first, string second) { - return Base64Codec.BitwiseOr(first, second); + return Base64Codec.BitwiseAnd(first, second); } /// @@ -75,5 +58,11 @@ public override sealed bool IsSupersetOf(string first, string second) { return Base64Codec.BitwiseAndEquals(first, second); } + + /// + public override sealed IEnumerable Iterate(string flags) + { + return new Base64FlagEnumerator(flags); + } } } \ No newline at end of file diff --git a/dotnet/Multiflag/Base64Format/Base64Codec.cs b/dotnet/Multiflag/Base64Format/Base64Codec.cs index d00de6c..ddb44e8 100644 --- a/dotnet/Multiflag/Base64Format/Base64Codec.cs +++ b/dotnet/Multiflag/Base64Format/Base64Codec.cs @@ -5,11 +5,11 @@ namespace Multiflag.Base64Format { internal static class Base64Codec { - private const char ZERO = 'A'; - private const char TWENTY_SIX = 'a'; - private const char FIFTY_TWO = '0'; - private const char SIXTY_TWO = '-'; - private const char SIXTY_THREE = '_'; + public const char ZERO = 'A'; + public const char TWENTY_SIX = 'a'; + public const char FIFTY_TWO = '0'; + public const char SIXTY_TWO = '-'; + public const char SIXTY_THREE = '_'; private static readonly string zero = ZERO.ToString(); @@ -133,6 +133,30 @@ public static string BitwiseOr(string a, string b) return result.ToString(); } + public static string BitwiseAnd(string first, string second) + { + var result = new StringBuilder(); + + int shorterLength = Math.Min(first.Length, second.Length); + var i = 0; + // AND the bytes one by one + for (; i < shorterLength; i++) + { + int value = DecodeByte(first[i]) & DecodeByte(second[i]); + result.Append(EncodeByte(value)); + } + + // if one string is longer then the other, don't add anything (x & 0 = 0) + // but make sure there is always one digit in the string + // empty strings are considered equal to zero, but we always try to normalise the output + if (i < 1) + { + result.Append(ZERO); + } + + return result.ToString(); + } + public static string BitwiseAndNot(string first, string second) { var result = new StringBuilder(); diff --git a/dotnet/Multiflag/Bitflags/BigintBitManipulator.cs b/dotnet/Multiflag/Bitflags/BigintBitManipulator.cs index 2d38487..b2714c3 100644 --- a/dotnet/Multiflag/Bitflags/BigintBitManipulator.cs +++ b/dotnet/Multiflag/Bitflags/BigintBitManipulator.cs @@ -1,3 +1,4 @@ +using System; using System.Numerics; namespace Multiflag.Bitflags @@ -12,16 +13,23 @@ private BigintBitManipulator() public static BigintBitManipulator Current => current ??= new BigintBitManipulator(); - public override BigInteger Zero => 0; + public override BigInteger Zero => BigInteger.Zero; + + public override BigInteger One => BigInteger.One; - protected override bool IsPowerOfTwo(BigInteger value) + public override bool IsZero(BigInteger value) { - return value.IsPowerOfTwo; + return value.IsZero; + } + + public override bool IsEven(BigInteger value) + { + return value.IsEven; } - public override bool IsZero(BigInteger flags) + protected override bool IsPowerOfTwo(BigInteger value) { - return flags == 0; + return value.IsPowerOfTwo; } public override BigInteger BitwiseOr(BigInteger first, BigInteger second) @@ -29,6 +37,11 @@ public override BigInteger BitwiseOr(BigInteger first, BigInteger second) return first | second; } + public override BigInteger BitwiseAnd(BigInteger first, BigInteger second) + { + return first & second; + } + public override BigInteger BitwiseAndNot(BigInteger first, BigInteger second) { return first & ~second; @@ -38,5 +51,15 @@ public override bool BitwiseAndEquals(BigInteger first, BigInteger second) { return (first & second) == second; } + + public override BigInteger ShiftLeft(BigInteger value) + { + return value << 1; + } + + public override BigInteger ShiftRight(BigInteger value) + { + return value >> 1; + } } } \ No newline at end of file diff --git a/dotnet/Multiflag/Bitflags/BitManipulator.cs b/dotnet/Multiflag/Bitflags/BitManipulator.cs index 5f87ce4..f96c8ea 100644 --- a/dotnet/Multiflag/Bitflags/BitManipulator.cs +++ b/dotnet/Multiflag/Bitflags/BitManipulator.cs @@ -1,31 +1,18 @@ +using System.Numerics; + namespace Multiflag.Bitflags { - internal abstract class BitManipulator - { - public abstract object ZeroObject { get; } - public abstract void CheckPowerOfTwo(object value); - - public abstract bool IsZero(object flags); - - public abstract object BitwiseOr(object first, object second); - - public abstract object BitwiseAndNot(object first, object second); - - public abstract bool BitwiseAndEquals(object first, object second); - } - - internal abstract class BitManipulator : BitManipulator + internal abstract class BitManipulator : IBitManipulator where T : notnull { - public override object ZeroObject => this.Zero; - public abstract T Zero { get; } - public override void CheckPowerOfTwo(object value) - { - this.CheckPowerOfTwo((T)value); - } + object IBitManipulator.Zero => this.Zero; + + public abstract T One { get; } + object IBitManipulator.One => this.One; + public void CheckPowerOfTwo(T value) { if (!this.IsPowerOfTwo(value)) @@ -34,34 +21,40 @@ public void CheckPowerOfTwo(T value) } } - protected abstract bool IsPowerOfTwo(T value); + public void CheckPowerOfTwo(object value) => this.CheckPowerOfTwo((T)value); + + public abstract bool IsZero(T value); - public override bool IsZero(object flags) - { - return this.IsZero((T)flags); - } + public bool IsZero(object value) => this.IsZero((T)value); - public abstract bool IsZero(T flags); + public abstract bool IsEven(T value); + + public bool IsEven(object value) => this.IsEven((T)value); - public override object BitwiseOr(object first, object second) - { - return this.BitwiseOr((T)first, (T)second); - } + protected abstract bool IsPowerOfTwo(T value); - public abstract T BitwiseOr(T first, T second); + public abstract T ShiftLeft(T value); + + public object ShiftLeft(object value) => this.ShiftLeft((T) value); - public override object BitwiseAndNot(object first, object second) - { - return this.BitwiseAndNot((T)first, (T)second); - } + public abstract T ShiftRight(T value); + + public object ShiftRight(object value) => this.ShiftRight((T) value); - public abstract T BitwiseAndNot(T first, T second); + public abstract T BitwiseOr(T first, T second); + + public object BitwiseOr(object first, object second) => this.BitwiseOr((T)first, (T)second); + + public abstract T BitwiseAnd(T first, T second); + + public object BitwiseAnd(object first, object second) => this.BitwiseAnd((T)first, (T)second); - public override bool BitwiseAndEquals(object first, object second) - { - return this.BitwiseAndEquals((T)first, (T)second); - } + public abstract T BitwiseAndNot(T first, T second); + + public object BitwiseAndNot(object first, object second) => this.BitwiseAndNot((T)first, (T)second); public abstract bool BitwiseAndEquals(T first, T second); + + public bool BitwiseAndEquals(object first, object second) => this.BitwiseAndEquals((T)first, (T)second); } } \ No newline at end of file diff --git a/dotnet/Multiflag/Bitflags/IBitManipulator.cs b/dotnet/Multiflag/Bitflags/IBitManipulator.cs new file mode 100644 index 0000000..1308f70 --- /dev/null +++ b/dotnet/Multiflag/Bitflags/IBitManipulator.cs @@ -0,0 +1,27 @@ +namespace Multiflag.Bitflags +{ + internal interface IBitManipulator + { + public object Zero { get; } + + public object One { get; } + + public void CheckPowerOfTwo(object value); + + public bool IsZero(object value); + + public bool IsEven(object value); + + public object ShiftLeft(object value); + + public object ShiftRight(object value); + + public object BitwiseOr(object first, object second); + + public object BitwiseAnd(object first, object second); + + public object BitwiseAndNot(object first, object second); + + public bool BitwiseAndEquals(object first, object second); + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/Bitflags/U16BitManipulator.cs b/dotnet/Multiflag/Bitflags/U16BitManipulator.cs index 409f551..cefa12a 100644 --- a/dotnet/Multiflag/Bitflags/U16BitManipulator.cs +++ b/dotnet/Multiflag/Bitflags/U16BitManipulator.cs @@ -12,14 +12,25 @@ private U16BitManipulator() public override ushort Zero => 0; + public override ushort One => 1; + + public override bool IsZero(ushort value) => value == 0; + + public override bool IsEven(ushort value) => (value & 1) == 0; + protected override bool IsPowerOfTwo(ushort value) { return value != 0 && (value & value - 1) == 0; } + + public override ushort ShiftLeft(ushort value) + { + return (ushort)(value << 1); + } - public override bool IsZero(ushort flags) + public override ushort ShiftRight(ushort value) { - return flags == 0; + return (ushort)(value >> 1); } public override ushort BitwiseOr(ushort first, ushort second) @@ -27,6 +38,11 @@ public override ushort BitwiseOr(ushort first, ushort second) return (ushort)(first | second); } + public override ushort BitwiseAnd(ushort first, ushort second) + { + return (ushort)(first & second); + } + public override ushort BitwiseAndNot(ushort first, ushort second) { return (ushort)(first & ~second); diff --git a/dotnet/Multiflag/Bitflags/U32BitManipulator.cs b/dotnet/Multiflag/Bitflags/U32BitManipulator.cs index 114b500..edf92dc 100644 --- a/dotnet/Multiflag/Bitflags/U32BitManipulator.cs +++ b/dotnet/Multiflag/Bitflags/U32BitManipulator.cs @@ -12,14 +12,25 @@ private U32BitManipulator() public override uint Zero => 0; + public override uint One => 1; + + public override bool IsZero(uint value) => value == 0; + + public override bool IsEven(uint value) => (value & 1) == 0; + protected override bool IsPowerOfTwo(uint value) { return value != 0 && (value & value - 1) == 0; } + + public override uint ShiftLeft(uint value) + { + return value << 1; + } - public override bool IsZero(uint flags) + public override uint ShiftRight(uint value) { - return flags == 0; + return value >> 1; } public override uint BitwiseOr(uint first, uint second) @@ -27,6 +38,11 @@ public override uint BitwiseOr(uint first, uint second) return first | second; } + public override uint BitwiseAnd(uint first, uint second) + { + return first & second; + } + public override uint BitwiseAndNot(uint first, uint second) { return first & ~second; diff --git a/dotnet/Multiflag/Bitflags/U64BitManipulator.cs b/dotnet/Multiflag/Bitflags/U64BitManipulator.cs index ed9905c..949a3aa 100644 --- a/dotnet/Multiflag/Bitflags/U64BitManipulator.cs +++ b/dotnet/Multiflag/Bitflags/U64BitManipulator.cs @@ -12,14 +12,25 @@ private U64BitManipulator() public override ulong Zero => 0; + public override ulong One => 1; + + public override bool IsZero(ulong value) => value == 0; + + public override bool IsEven(ulong value) => (value & 1) == 0; + protected override bool IsPowerOfTwo(ulong value) { return value != 0 && (value & value - 1) == 0; } + + public override ulong ShiftLeft(ulong value) + { + return value << 1; + } - public override bool IsZero(ulong flags) + public override ulong ShiftRight(ulong value) { - return flags == 0; + return value >> 1; } public override ulong BitwiseOr(ulong first, ulong second) @@ -27,6 +38,11 @@ public override ulong BitwiseOr(ulong first, ulong second) return first | second; } + public override ulong BitwiseAnd(ulong first, ulong second) + { + return first & second; + } + public override ulong BitwiseAndNot(ulong first, ulong second) { return first & ~second; diff --git a/dotnet/Multiflag/Bitflags/U8BitManipulator.cs b/dotnet/Multiflag/Bitflags/U8BitManipulator.cs index 14c5cd1..5ec9f6c 100644 --- a/dotnet/Multiflag/Bitflags/U8BitManipulator.cs +++ b/dotnet/Multiflag/Bitflags/U8BitManipulator.cs @@ -12,14 +12,25 @@ private U8BitManipulator() public override byte Zero => 0; + public override byte One => 1; + + public override bool IsZero(byte value) => value == 0; + + public override bool IsEven(byte value) => (value & 1) == 0; + protected override bool IsPowerOfTwo(byte value) { return value != 0 && (value & value - 1) == 0; } + + public override byte ShiftLeft(byte value) + { + return (byte)(value << 1); + } - public override bool IsZero(byte flags) + public override byte ShiftRight(byte value) { - return flags == 0; + return (byte)(value >> 1); } public override byte BitwiseOr(byte first, byte second) @@ -27,6 +38,11 @@ public override byte BitwiseOr(byte first, byte second) return (byte)(first | second); } + public override byte BitwiseAnd(byte first, byte second) + { + return (byte)(first & second); + } + public override byte BitwiseAndNot(byte first, byte second) { return (byte)(first & ~second); diff --git a/dotnet/Multiflag/CollectionFlagSet.cs b/dotnet/Multiflag/CollectionFlagSet.cs new file mode 100644 index 0000000..e27ef3d --- /dev/null +++ b/dotnet/Multiflag/CollectionFlagSet.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace Multiflag +{ + /// + /// Provides flags that work on HashSets. The flags can have values of any type and there is no limit to the number + /// of different flags, and sets can easily be serialized (as a JSON array for example). + /// + public class CollectionFlagSet : FlagSet> + where T : notnull + { + /// + protected override sealed IImmutableSet WrapValue(T value) + { + return ImmutableHashSet.Create(value); + } + + /// + public override sealed IImmutableSet Empty() + { + return ImmutableHashSet.Empty; + } + + /// + public override sealed IImmutableSet Union(IImmutableSet first, IImmutableSet second) + { + return first.Union(second); + } + + /// + public override sealed IImmutableSet Intersection(IImmutableSet first, IImmutableSet second) + { + return first.Intersect(second); + } + + /// + public override sealed IImmutableSet Difference(IImmutableSet first, IImmutableSet second) + { + return first.Except(second); + } + + /// + public override sealed bool IsSupersetOf(IImmutableSet first, IImmutableSet second) + { + return first.IsSupersetOf(second); + } + + /// + public override IEnumerable Iterate(IImmutableSet flags) + { + return flags; + } + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/DynamicBitflagSet.cs b/dotnet/Multiflag/DynamicBitflagSet.cs index 25f6dfd..320a73c 100644 --- a/dotnet/Multiflag/DynamicBitflagSet.cs +++ b/dotnet/Multiflag/DynamicBitflagSet.cs @@ -1,17 +1,20 @@ -using System.Numerics; +using System.Collections.Generic; +using System.Numerics; using Multiflag.Bitflags; +using Multiflag.Enumerators; namespace Multiflag { /// /// Provides bitflags based on dynamic integers (thus allowing any number of flags). /// - public class DynamicBitflagSet : FlagSet + public class DynamicBitflagSet : FlagSet { /// - protected override sealed void CheckValue(BigInteger value) + protected override sealed BigInteger WrapValue(BigInteger value) { BigintBitManipulator.Current.CheckPowerOfTwo(value); + return value; } /// @@ -21,15 +24,15 @@ public override sealed BigInteger Empty() } /// - public override sealed bool IsEmpty(BigInteger flags) + public override sealed BigInteger Union(BigInteger first, BigInteger second) { - return BigintBitManipulator.Current.IsZero(flags); + return BigintBitManipulator.Current.BitwiseOr(first, second); } /// - public override sealed BigInteger Union(BigInteger first, BigInteger second) + public override sealed BigInteger Intersection(BigInteger first, BigInteger second) { - return BigintBitManipulator.Current.BitwiseOr(first, second); + return BigintBitManipulator.Current.BitwiseAnd(first, second); } /// @@ -43,5 +46,14 @@ public override sealed bool IsSupersetOf(BigInteger first, BigInteger second) { return BigintBitManipulator.Current.BitwiseAndEquals(first, second); } + + /// + public override IEnumerable Iterate(BigInteger flags) + { + return new NumericFlagEnumerator( + BigintBitManipulator.Current, + flags + ); + } } } \ No newline at end of file diff --git a/dotnet/Multiflag/EnumBitflagSet.cs b/dotnet/Multiflag/EnumBitflagSet.cs index 9c40751..d28c0a2 100644 --- a/dotnet/Multiflag/EnumBitflagSet.cs +++ b/dotnet/Multiflag/EnumBitflagSet.cs @@ -1,15 +1,18 @@ using System; +using System.Collections.Generic; +using System.Numerics; using Multiflag.Bitflags; +using Multiflag.Enumerators; namespace Multiflag { /// /// Provides bitflags based on dynamic integers (thus allowing any number of flags). /// - public class EnumBitflagSet : FlagSet + public class EnumBitflagSet : FlagSet where T : Enum { - private readonly BitManipulator bitManipulator; + private readonly IBitManipulator bitManipulator; private readonly Type enumType; private readonly Type underlyingType; @@ -27,7 +30,7 @@ public EnumBitflagSet() this.bitManipulator = FindBitManipulator(this.underlyingType); } - private static BitManipulator FindBitManipulator(Type underlyingType) + private static IBitManipulator FindBitManipulator(Type underlyingType) { if (underlyingType == typeof(sbyte)) { @@ -78,7 +81,7 @@ private T IntToEnum(object value) } /// - protected override sealed void CheckValue(T value) + protected override sealed T WrapValue(T value) { this.bitManipulator.CheckPowerOfTwo(this.EnumToInt(value)); @@ -86,36 +89,65 @@ protected override sealed void CheckValue(T value) { throw new UndefinedEnumValueException(value); } + + return value; } /// public override sealed T Empty() { - return this.IntToEnum(this.bitManipulator.ZeroObject); + return this.IntToEnum(this.bitManipulator.Zero); } /// - public override sealed bool IsEmpty(T flags) + public override sealed T Union(T first, T second) { - return this.bitManipulator.IsZero(this.EnumToInt(flags)); + return this.IntToEnum( + this.bitManipulator.BitwiseOr( + this.EnumToInt(first), + this.EnumToInt(second) + ) + ); } /// - public override sealed T Union(T first, T second) + public override sealed T Intersection(T first, T second) { - return this.IntToEnum(this.bitManipulator.BitwiseOr(this.EnumToInt(first), this.EnumToInt(second))); + return this.IntToEnum( + this.bitManipulator.BitwiseAnd( + this.EnumToInt(first), + this.EnumToInt(second) + ) + ); } /// public override sealed T Difference(T first, T second) { - return this.IntToEnum(this.bitManipulator.BitwiseAndNot(this.EnumToInt(first), this.EnumToInt(second))); + return this.IntToEnum( + this.bitManipulator.BitwiseAndNot( + this.EnumToInt(first), + this.EnumToInt(second) + ) + ); } /// public override sealed bool IsSupersetOf(T first, T second) { - return this.bitManipulator.BitwiseAndEquals(this.EnumToInt(first), this.EnumToInt(second)); + return this.bitManipulator.BitwiseAndEquals( + this.EnumToInt(first), + this.EnumToInt(second) + ); + } + + /// + public override IEnumerable Iterate(T flags) + { + return new EnumFlagEnumerator( + this.bitManipulator, + flags + ); } } } \ No newline at end of file diff --git a/dotnet/Multiflag/Enumerators/Base64FlagEnumerator.cs b/dotnet/Multiflag/Enumerators/Base64FlagEnumerator.cs new file mode 100644 index 0000000..b4ad546 --- /dev/null +++ b/dotnet/Multiflag/Enumerators/Base64FlagEnumerator.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Multiflag.Base64Format; + +namespace Multiflag.Enumerators +{ + internal class Base64FlagEnumerator : IEnumerable, IEnumerator + { + private readonly string value; + private int currentByte; + private int currentBit; + + public Base64FlagEnumerator(string value) + { + this.value = value; + this.currentByte = 0; + this.currentBit = 0; + } + + public IEnumerator GetEnumerator() + { + return new Base64FlagEnumerator(this.value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + public void Dispose() + { + } + + private bool MoveNextByte() { + // next multiple of 6 + var index = (int)Math.Ceiling(this.currentBit / 6.0); + + // skip bytes equal to zero + while ( + index < this.value.Length + && this.value[index] == Base64Codec.ZERO) + { + index++; + } + + if (index < this.value.Length) + { + // found a non-zero byte + this.currentByte = Base64Codec.DecodeByte(this.value[index]); + this.currentBit = index * 6; + return true; + } + else + { + // reached the end of the string + return false; + } + } + + public bool MoveNext() + { + if (this.currentByte == 0) + { + if (!this.MoveNextByte()) + { + return false; + } + } + + while ((this.currentByte & 1) == 0) + { + this.currentByte >>= 1; + this.currentBit += 1; + } + + this.currentByte >>= 1; + this.currentBit += 1; + + return true; + } + + public void Reset() + { + this.currentByte = 0; + this.currentBit = 0; + } + + public int Current => this.currentBit; + + object IEnumerator.Current => this.Current; + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/Enumerators/EnumFlagEnumerator.cs b/dotnet/Multiflag/Enumerators/EnumFlagEnumerator.cs new file mode 100644 index 0000000..f10acfb --- /dev/null +++ b/dotnet/Multiflag/Enumerators/EnumFlagEnumerator.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Multiflag.Bitflags; + +namespace Multiflag.Enumerators +{ + internal class EnumFlagEnumerator : IEnumerable, IEnumerator + { + private readonly object value; + private readonly IBitManipulator bitManipulator; + private object remaining; + private object current; + + public EnumFlagEnumerator(IBitManipulator bitManipulator, object value) + { + this.value = value; + this.bitManipulator = bitManipulator; + this.remaining = value; + this.current = this.bitManipulator.One; + } + + public IEnumerator GetEnumerator() + { + return new EnumFlagEnumerator(this.bitManipulator, this.value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + public bool MoveNext() + { + if (this.bitManipulator.IsZero(this.remaining)) + { + return false; + } + + // move to the next bit + while (this.bitManipulator.IsEven(this.remaining)) + { + this.remaining = this.bitManipulator.ShiftRight(this.remaining); + this.current = this.bitManipulator.ShiftLeft(this.remaining); + } + + // discard this bit + this.remaining = this.bitManipulator.BitwiseAndNot( + this.remaining, + this.bitManipulator.One + ); + + return true; + } + + public void Reset() + { + this.remaining = this.value; + this.current = this.bitManipulator.One; + } + + T IEnumerator.Current => (T)this.Current; + + public object Current => Enum.ToObject(typeof(T), this.current); + + public void Dispose() + { + } + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/Enumerators/NumericFlagEnumerator.cs b/dotnet/Multiflag/Enumerators/NumericFlagEnumerator.cs new file mode 100644 index 0000000..f122ceb --- /dev/null +++ b/dotnet/Multiflag/Enumerators/NumericFlagEnumerator.cs @@ -0,0 +1,70 @@ +using System.Collections; +using System.Collections.Generic; +using Multiflag.Bitflags; + +namespace Multiflag.Enumerators +{ + internal class NumericFlagEnumerator : IEnumerable, IEnumerator + where T : notnull + { + private readonly T value; + private readonly BitManipulator bitManipulator; + private T remaining; + private T current; + + public NumericFlagEnumerator(BitManipulator bitManipulator, T value) + { + this.value = value; + this.bitManipulator = bitManipulator; + this.remaining = value; + this.current = this.bitManipulator.One; + } + + public IEnumerator GetEnumerator() + { + return new NumericFlagEnumerator(this.bitManipulator, this.value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + public bool MoveNext() + { + if (this.bitManipulator.IsZero(this.remaining)) + { + return false; + } + + // move to the next bit + while (this.bitManipulator.IsEven(this.remaining)) + { + this.remaining = this.bitManipulator.ShiftRight(this.remaining); + this.current = this.bitManipulator.ShiftLeft(this.remaining); + } + + // discard this bit + this.remaining = this.bitManipulator.BitwiseAndNot( + this.remaining, + this.bitManipulator.One + ); + + return true; + } + + public void Reset() + { + this.remaining = this.value; + this.current = this.bitManipulator.One; + } + + public T Current => this.current; + + object IEnumerator.Current => this.Current; + + public void Dispose() + { + } + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/Flag.cs b/dotnet/Multiflag/Flag.cs index 4c61278..b03b38c 100644 --- a/dotnet/Multiflag/Flag.cs +++ b/dotnet/Multiflag/Flag.cs @@ -1,42 +1,33 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; namespace Multiflag { /// /// A represents some element of - /// that can be added or removed from the set. + /// that can be added or removed from the set. /// When a flag is added to the set, all of its parents are added along /// with it, and when it is removed all of its children are removed too. /// - /// - public class Flag - where T : notnull + /// + public class Flag { - private readonly List> children; - private readonly List> parents; - private readonly FlagSet set; - private readonly T value; + private readonly ISetOperations operations; + private readonly List> parents; + private readonly List> children; /// /// Creates a new flag. /// - /// The set this flag belongs to. - /// The value of the flag. - /// The parent flags. - /// - /// If one of the parents doesn't belong to the same . - /// - internal Flag(FlagSet set, T value, IEnumerable> parents) + internal Flag(ISetOperations operations, IEnumerable> parents) { - this.set = set; - this.value = value; + this.operations = operations; this.parents = parents.ToList(); - this.children = new List>(); + this.children = new List>(); foreach (var parent in this.parents) { - if (!parent.BelongsTo(this.set)) + if (!parent.BelongsTo(this.operations)) { throw new ForeignFlagException(); } @@ -44,37 +35,36 @@ internal Flag(FlagSet set, T value, IEnumerable> parents) parent.children.Add(this); } } + + internal ISetOperations Operations => this.operations; /// /// when this flag has no value on its own. /// - public bool IsAbstract => this.set.IsEmpty(this.value); + public virtual bool IsAbstract => true; - private bool BelongsTo(FlagSet flagSet) + private bool BelongsTo(ISetOperations flagSet) { - return this.set == flagSet; + return this.operations == flagSet; } /// /// Add a flag if it is not already present. /// /// The flags to add it to. - /// The modified flags. - /// - /// If is reference type, the flags passed to the function may be modified in-place. - /// - public T AddTo(T flags) + /// A copy of the flags with this flag added. + public virtual TSet AddTo(TSet flags) { return this.parents.Aggregate( - this.set.Union(flags, this.value), + flags, (current, parent) => parent.AddTo(current) ); } /// - /// See . + /// See . /// - public static T operator +(T value, Flag flag) + public static TSet operator +(TSet value, Flag flag) { return flag.AddTo(value); } @@ -85,20 +75,20 @@ public T AddTo(T flags) /// The flags to remove it from. /// The modified flags. /// - /// If is reference type, the flags passed to the function may be modified in-place. + /// If is reference type, the flags passed to the function may be modified in-place. /// - public T RemoveFrom(T flags) + public virtual TSet RemoveFrom(TSet flags) { return this.children.Aggregate( - this.set.Difference(flags, this.value), + flags, (current, child) => child.RemoveFrom(current) ); } /// - /// See + /// See /// - public static T operator -(T value, Flag flag) + public static TSet operator -(TSet value, Flag flag) { return flag.RemoveFrom(value); } @@ -111,10 +101,9 @@ public T RemoveFrom(T flags) /// if this flag belongs to the set of /// , otherwise . /// - public bool IsIn(T flags) + public virtual bool IsIn(TSet flags) { - return this.set.IsSupersetOf(flags, this.value) - && this.parents.All(parent => parent.IsIn(flags)); + return this.parents.All(parent => parent.IsIn(flags)); } } } \ No newline at end of file diff --git a/dotnet/Multiflag/FlagSet.cs b/dotnet/Multiflag/FlagSet.cs index 0e1d2f2..c22f899 100644 --- a/dotnet/Multiflag/FlagSet.cs +++ b/dotnet/Multiflag/FlagSet.cs @@ -1,107 +1,172 @@ +using System; using System.Collections.Generic; namespace Multiflag { /// /// Represent a group of flags, and provide methods to use - /// as a set. Built-in implementations exist for - /// unsigned integers, enums and . + /// as a set. + /// Built-in implementations exist for unsigned integers, enums, + /// hash sets and lists. /// - /// The type to be used as a set of flags. - public abstract class FlagSet - where T : notnull + /// The type of the flag values. + /// The type of the sets of flags. + public abstract class FlagSet : ISetOperations + where TValue : notnull { - private readonly Dictionary> concreteFlags; + private readonly Dictionary> valueFlags; /// /// Creates a new empty flag set. /// protected FlagSet() { - this.concreteFlags = new Dictionary>(); + this.valueFlags = new Dictionary>(); } /// /// Creates a flag without a value. /// - /// Other flags required for this flag to be set. + /// + /// Other flags required for this flag to be set. + /// /// A flag bound to this set. /// - /// If one of the parents doesn't belong to the same . + /// If one of the parents doesn't belong to the same + /// . /// - public Flag Flag(params Flag[] parents) + public Flag Flag(params Flag[] parents) { - return new Flag(this, this.Empty(), parents); + return new Flag(this, parents); } /// /// Creates a flag with a value. /// /// The value of the flag. - /// Other flags required for this flag to be set. + /// + /// Other flags required for this flag to be set. + /// /// A flag bound to this set. /// - /// If one of the parents doesn't belong to the same . + /// If one of the parents doesn't belong to the same + /// . /// /// /// If another flag has already been created with the same value. /// - public Flag Flag(T value, params Flag[] parents) + public Flag Flag(TValue value, params Flag[] parents) { - this.CheckValue(value); - - if (this.concreteFlags.ContainsKey(value)) + if (this.valueFlags.ContainsKey(value)) { throw new ReusedFlagValueException(value); } - var flag = new Flag(this, value, parents); - this.concreteFlags.Add(value, flag); + var flag = new ValueFlag(this, parents, this.WrapValue(value)); + this.valueFlags.Add(value, flag); return flag; } /// - /// This method will be called when a new flag is about to be created - /// with that value. The default implementation does nothing, but it - /// may be overriden to throw an exception on invalid values. + /// Transforms a value into a set containing only that value. + /// This method may throw an exception if the value is not valid. /// /// The value that will be used for the flag. - protected virtual void CheckValue(T value) + protected abstract TSet WrapValue(TValue value); + + /// + /// Filters a flag set so that it only contains the flags that were + /// declared with the Flag method. If a flags is missing some + /// of its parents, it will not be included in the result. + /// + /// The set of flags to filter. + /// A new set of flags. + /// + public TSet Minimum(TSet flags) { + TSet result = this.Empty(); + foreach (var value in this.Iterate(flags)) + { + if (this.valueFlags.TryGetValue(value, out var flag) && flag.IsIn(flags)) + { + result = flag.AddTo(result); + } + } + + return result; } /// - /// Creates an empty set of flags. + /// Creates a copy of a flag set that will contain all the flags + /// that were declared with the Flag method. If a flag is + /// missing some of its parents in the original set, they will be + /// added to the result. /// - public abstract T Empty(); + /// The set of flags to filter. + /// A new set of flags. + /// + public TSet Maximum(TSet flags) + { + TSet result = this.Empty(); + foreach (var value in this.Iterate(flags)) { + if (this.valueFlags.TryGetValue(value, out var flag)) + { + result = flag.AddTo(result); + } + } + + return result; + } /// - /// Checks if a set of flags is the empty set. + /// Creates an empty set of flags. /// - /// The set of flags to test. - public abstract bool IsEmpty(T flags); + public abstract TSet Empty(); /// /// Computes the union of two sets of flags. /// /// The first set of flags. /// The second set of flags. - /// A new set that contains the flags of both sets. - public abstract T Union(T first, T second); + /// + /// A new set that contains the flags that appear in any of the sets. + /// + public abstract TSet Union(TSet first, TSet second); + + /// + /// Computes the intersection of two sets of flags. + /// + /// The first set of flags. + /// The second set of flags. + /// + /// A new set that contains the flags that appear in both sets. + /// + public abstract TSet Intersection(TSet first, TSet second); /// /// Computes the difference of two set of flags. /// /// The first set of flags. - /// The second set of flags (that will be subtracted from the first). - /// A new set that contains the flags of the first set that do not appear in the second. - public abstract T Difference(T first, T second); + /// + /// The second set of flags (that will be subtracted from the first). + /// + /// + /// A new set that contains the flags of the first set that do not + /// appear in the second. + /// + public abstract TSet Difference(TSet first, TSet second); /// /// Checks whether the first set of flags is a superset of the second. /// /// The first set of flags. /// The second set of flags. - public abstract bool IsSupersetOf(T first, T second); + public abstract bool IsSupersetOf(TSet first, TSet second); + + /// + /// Returns an iterable over the elements of a set. + /// + /// A set of flags + public abstract IEnumerable Iterate(TSet flags); } } \ No newline at end of file diff --git a/dotnet/Multiflag/HashedFlagSet.cs b/dotnet/Multiflag/HashedFlagSet.cs deleted file mode 100644 index 290cd0a..0000000 --- a/dotnet/Multiflag/HashedFlagSet.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Collections.Immutable; - -namespace Multiflag -{ - /// - /// Provides flags that work on HashSets. The flags can have values of any type and there is no limit to the number - /// of different flags, and sets can easily be serialized (as a JSON array for example). - /// - public class HashedFlagSet : FlagSet> - where T : notnull - { - /// - /// Creates a flag with a value. - /// - /// The value of the flag. - /// Other flags required for this flag to be set. - /// A flag bound to this set. - /// - /// If one of the parents doesn't belong to the same . - /// - /// - /// If another flag has already been created with the same value. - /// - public Flag> Flag(T value, params Flag>[] parents) - { - return this.Flag(ImmutableHashSet.Create(value), parents); - } - - /// - protected override sealed void CheckValue(IImmutableSet value) - { - if (value.Count != 1) - { - throw new InvalidHashSetValueException(); - } - } - - /// - public override sealed IImmutableSet Empty() - { - return ImmutableHashSet.Empty; - } - - /// - public override sealed bool IsEmpty(IImmutableSet flags) - { - return flags.Count == 0; - } - - /// - public override sealed IImmutableSet Union(IImmutableSet first, IImmutableSet second) - { - return first.Union(second); - } - - /// - public override sealed IImmutableSet Difference(IImmutableSet first, IImmutableSet second) - { - return first.Except(second); - } - - /// - public override sealed bool IsSupersetOf(IImmutableSet first, IImmutableSet second) - { - return first.IsSupersetOf(second); - } - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/ISetOperations.cs b/dotnet/Multiflag/ISetOperations.cs new file mode 100644 index 0000000..2bd8d6c --- /dev/null +++ b/dotnet/Multiflag/ISetOperations.cs @@ -0,0 +1,30 @@ +namespace Multiflag +{ + internal interface ISetOperations + { + /// + /// Creates an empty set of flags. + /// + TSet Empty(); + + /// + /// Computes the union of two sets of flags. + /// + public TSet Union(TSet first, TSet second); + + /// + /// Computes the intersection of two sets of flags. + /// + public TSet Intersection(TSet first, TSet second); + + /// + /// Computes the difference of two set of flags. + /// + public TSet Difference(TSet first, TSet second); + + /// + /// Checks whether the first set of flags is a superset of the second. + /// + public bool IsSupersetOf(TSet first, TSet second); + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/ReusedFlagValueException.cs b/dotnet/Multiflag/ReusedFlagValueException.cs index d971d0d..e63725f 100644 --- a/dotnet/Multiflag/ReusedFlagValueException.cs +++ b/dotnet/Multiflag/ReusedFlagValueException.cs @@ -3,7 +3,7 @@ namespace Multiflag { /// - /// Exception thrown if the method is called + /// Exception thrown if the method is called /// with a value that was already used for another flag in the same . /// public class ReusedFlagValueException : ArgumentException diff --git a/dotnet/Multiflag/U16BitflagSet.cs b/dotnet/Multiflag/U16BitflagSet.cs index 1f842d2..3f1a498 100644 --- a/dotnet/Multiflag/U16BitflagSet.cs +++ b/dotnet/Multiflag/U16BitflagSet.cs @@ -1,16 +1,19 @@ -using Multiflag.Bitflags; +using System.Collections.Generic; +using Multiflag.Bitflags; +using Multiflag.Enumerators; namespace Multiflag { /// /// Provides bitflags based on 16-bit unsigned integers (thus allowing 16 different flags). /// - public class U16BitflagSet : FlagSet + public class U16BitflagSet : FlagSet { /// - protected override sealed void CheckValue(ushort value) + protected override sealed ushort WrapValue(ushort value) { U16BitManipulator.Current.CheckPowerOfTwo(value); + return value; } /// @@ -20,15 +23,15 @@ public override sealed ushort Empty() } /// - public override sealed bool IsEmpty(ushort flags) + public override sealed ushort Union(ushort first, ushort second) { - return U16BitManipulator.Current.IsZero(flags); + return U16BitManipulator.Current.BitwiseOr(first, second); } /// - public override sealed ushort Union(ushort first, ushort second) + public override sealed ushort Intersection(ushort first, ushort second) { - return U16BitManipulator.Current.BitwiseOr(first, second); + return U16BitManipulator.Current.BitwiseAnd(first, second); } /// @@ -42,5 +45,14 @@ public override sealed bool IsSupersetOf(ushort first, ushort second) { return U16BitManipulator.Current.BitwiseAndEquals(first, second); } + + /// + public override IEnumerable Iterate(ushort flags) + { + return new NumericFlagEnumerator( + U16BitManipulator.Current, + flags + ); + } } } \ No newline at end of file diff --git a/dotnet/Multiflag/U32BitflagSet.cs b/dotnet/Multiflag/U32BitflagSet.cs index f82bf97..f6833a1 100644 --- a/dotnet/Multiflag/U32BitflagSet.cs +++ b/dotnet/Multiflag/U32BitflagSet.cs @@ -1,16 +1,19 @@ -using Multiflag.Bitflags; +using System.Collections.Generic; +using Multiflag.Bitflags; +using Multiflag.Enumerators; namespace Multiflag { /// /// Provides bitflags based on 32-bit unsigned integers (thus allowing 32 different flags). /// - public class U32BitflagSet : FlagSet + public class U32BitflagSet : FlagSet { /// - protected override sealed void CheckValue(uint value) + protected override sealed uint WrapValue(uint value) { U32BitManipulator.Current.CheckPowerOfTwo(value); + return value; } /// @@ -20,15 +23,15 @@ public override sealed uint Empty() } /// - public override sealed bool IsEmpty(uint flags) + public override sealed uint Union(uint first, uint second) { - return U32BitManipulator.Current.IsZero(flags); + return U32BitManipulator.Current.BitwiseOr(first, second); } /// - public override sealed uint Union(uint first, uint second) + public override sealed uint Intersection(uint first, uint second) { - return U32BitManipulator.Current.BitwiseOr(first, second); + return U32BitManipulator.Current.BitwiseAnd(first, second); } /// @@ -42,5 +45,14 @@ public override sealed bool IsSupersetOf(uint first, uint second) { return U32BitManipulator.Current.BitwiseAndEquals(first, second); } + + /// + public override IEnumerable Iterate(uint flags) + { + return new NumericFlagEnumerator( + U32BitManipulator.Current, + flags + ); + } } } \ No newline at end of file diff --git a/dotnet/Multiflag/U64BitflagSet.cs b/dotnet/Multiflag/U64BitflagSet.cs index 5b7eec1..6013ee1 100644 --- a/dotnet/Multiflag/U64BitflagSet.cs +++ b/dotnet/Multiflag/U64BitflagSet.cs @@ -1,16 +1,19 @@ -using Multiflag.Bitflags; +using System.Collections.Generic; +using Multiflag.Bitflags; +using Multiflag.Enumerators; namespace Multiflag { /// /// Provides bitflags based on 64-bit unsigned integers (thus allowing 64 different flags). /// - public class U64BitflagSet : FlagSet + public class U64BitflagSet : FlagSet { /// - protected override sealed void CheckValue(ulong value) + protected override sealed ulong WrapValue(ulong value) { U64BitManipulator.Current.CheckPowerOfTwo(value); + return value; } /// @@ -20,15 +23,15 @@ public override sealed ulong Empty() } /// - public override sealed bool IsEmpty(ulong flags) + public override sealed ulong Union(ulong first, ulong second) { - return U64BitManipulator.Current.IsZero(flags); + return U64BitManipulator.Current.BitwiseOr(first, second); } /// - public override sealed ulong Union(ulong first, ulong second) + public override sealed ulong Intersection(ulong first, ulong second) { - return U64BitManipulator.Current.BitwiseOr(first, second); + return U64BitManipulator.Current.BitwiseAnd(first, second); } /// @@ -42,5 +45,14 @@ public override sealed bool IsSupersetOf(ulong first, ulong second) { return U64BitManipulator.Current.BitwiseAndEquals(first, second); } + + /// + public override IEnumerable Iterate(ulong flags) + { + return new NumericFlagEnumerator( + U64BitManipulator.Current, + flags + ); + } } } \ No newline at end of file diff --git a/dotnet/Multiflag/U8BitflagSet.cs b/dotnet/Multiflag/U8BitflagSet.cs index 5b2aa15..1b754fb 100644 --- a/dotnet/Multiflag/U8BitflagSet.cs +++ b/dotnet/Multiflag/U8BitflagSet.cs @@ -1,16 +1,19 @@ -using Multiflag.Bitflags; +using System.Collections.Generic; +using Multiflag.Bitflags; +using Multiflag.Enumerators; namespace Multiflag { /// /// Provides bitflags based on 8-bit unsigned integers (thus allowing 8 different flags). /// - public class U8BitflagSet : FlagSet + public class U8BitflagSet : FlagSet { /// - protected override sealed void CheckValue(byte value) + protected override sealed byte WrapValue(byte value) { U8BitManipulator.Current.CheckPowerOfTwo(value); + return value; } /// @@ -20,15 +23,15 @@ public override sealed byte Empty() } /// - public override sealed bool IsEmpty(byte flags) + public override sealed byte Union(byte first, byte second) { - return U8BitManipulator.Current.IsZero(flags); + return U8BitManipulator.Current.BitwiseOr(first, second); } /// - public override sealed byte Union(byte first, byte second) + public override sealed byte Intersection(byte first, byte second) { - return U8BitManipulator.Current.BitwiseOr(first, second); + return U8BitManipulator.Current.BitwiseAnd(first, second); } /// @@ -42,5 +45,14 @@ public override sealed bool IsSupersetOf(byte first, byte second) { return U8BitManipulator.Current.BitwiseAndEquals(first, second); } + + /// + public override IEnumerable Iterate(byte flags) + { + return new NumericFlagEnumerator( + U8BitManipulator.Current, + flags + ); + } } } \ No newline at end of file diff --git a/dotnet/Multiflag/ValueFlag.cs b/dotnet/Multiflag/ValueFlag.cs new file mode 100644 index 0000000..b9b1cca --- /dev/null +++ b/dotnet/Multiflag/ValueFlag.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Multiflag +{ + internal class ValueFlag : Flag + { + private readonly TSet value; + + internal ValueFlag( + ISetOperations operations, + IEnumerable> parents, + TSet value + ) : base(operations, parents) + { + this.value = value; + } + + public override bool IsAbstract => false; + + public override TSet AddTo(TSet flags) + { + return base.AddTo(this.Operations.Union(flags, this.value)); + } + + public override TSet RemoveFrom(TSet flags) + { + return base.RemoveFrom(this.Operations.Difference(flags, this.value)); + } + + public override bool IsIn(TSet flags) + { + return this.Operations.IsSupersetOf(flags, this.value) + && base.IsIn(flags); + } + } +} \ No newline at end of file diff --git a/dotnet/Tests/Base64BitflagSetTests.cs b/dotnet/Tests/Base64BitflagSetTests.cs index ff98ca6..9633ee1 100644 --- a/dotnet/Tests/Base64BitflagSetTests.cs +++ b/dotnet/Tests/Base64BitflagSetTests.cs @@ -3,7 +3,7 @@ namespace Multiflag.Tests; public class Base64BitflagSetTests { [Fact] - public void CreateFromIndex() + public void Create() { var flags = new Base64BitflagSet(); @@ -13,20 +13,93 @@ public void CreateFromIndex() Assert.Throws(() => flags.Flag(0)); Assert.Throws(() => flags.Flag(-2)); } + + [Fact] + public void Union() { + var flags = new Base64BitflagSet(); + + Assert.Equal("A", flags.Union("", "")); + Assert.Equal("A", flags.Union("A", "A")); + Assert.Equal("B", flags.Union("B", "A")); + Assert.Equal("C", flags.Union("A", "C")); + Assert.Equal("D", flags.Union("B", "C")); + Assert.Equal("H", flags.Union("D", "G")); + } + + [Fact] + public void Difference() + { + var flags = new Base64BitflagSet(); + + Assert.Equal("A", flags.Difference("", "")); + Assert.Equal("A", flags.Difference("A", "A")); + Assert.Equal("B", flags.Difference("B", "A")); + Assert.Equal("B", flags.Difference("D", "G")); + Assert.Equal("E", flags.Difference("G", "D")); + Assert.Equal("IB", flags.Difference("IB", "R")); + } + + [Fact] + public void Intersection() + { + var flags = new Base64BitflagSet(); + + Assert.Equal("A", flags.Intersection("", "")); + Assert.Equal("A", flags.Intersection("A", "A")); + Assert.Equal("A", flags.Intersection("B", "A")); + Assert.Equal("A", flags.Intersection("B", "C")); + Assert.Equal("B", flags.Intersection("B", "D")); + Assert.Equal("B", flags.Intersection("L", "F")); + Assert.Equal("D", flags.Intersection("L", "H")); + } [Fact] - public void CreateFromString() + public void Iterate() { var flags = new Base64BitflagSet(); - Assert.Throws(() => flags.Flag("")); - Assert.Throws(() => flags.Flag("A")); - flags.Flag("B"); - flags.Flag("C"); - Assert.Throws(() => flags.Flag("D")); - flags.Flag("E"); - flags.Flag("EAA"); - Assert.Throws(() => flags.Flag("AAD")); + Assert.Equal([], flags.Iterate("A")); + Assert.Equal([1], flags.Iterate("B")); + Assert.Equal([2], flags.Iterate("C")); + Assert.Equal([1, 2], flags.Iterate("D")); + Assert.Equal([1, 2, 4], flags.Iterate("L")); + Assert.Equal([3, 6, 7], flags.Iterate("kB")); + } + + [Fact] + public void Minimum() + { + var flags = new Base64BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag3 = flags.Flag(3, flag1); + var flag4 = flags.Flag(4, flag3); + + Assert.Equal("A", flags.Minimum("A")); + Assert.Equal("B", flags.Minimum("B")); + Assert.Equal("A", flags.Minimum("C")); + Assert.Equal("D", flags.Minimum("D")); + Assert.Equal("D", flags.Minimum("L")); + Assert.Equal("N", flags.Minimum("N")); + Assert.Equal("B", flags.Minimum("R")); + } + + [Fact] + public void Maximum() + { + var flags = new Base64BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag3 = flags.Flag(3, flag1); + var flag4 = flags.Flag(4, flag3); + + Assert.Equal("A", flags.Maximum("A")); + Assert.Equal("B", flags.Maximum("B")); + Assert.Equal("D", flags.Maximum("C")); + Assert.Equal("D", flags.Maximum("D")); + Assert.Equal("P", flags.Maximum("L")); + Assert.Equal("N", flags.Maximum("N")); + Assert.Equal("B", flags.Maximum("R")); } [Fact] diff --git a/dotnet/Tests/HashedFlagSetTests.cs b/dotnet/Tests/CollectionFlagSetTests.cs similarity index 88% rename from dotnet/Tests/HashedFlagSetTests.cs rename to dotnet/Tests/CollectionFlagSetTests.cs index d63f2a9..3484cb1 100644 --- a/dotnet/Tests/HashedFlagSetTests.cs +++ b/dotnet/Tests/CollectionFlagSetTests.cs @@ -2,12 +2,12 @@ namespace Multiflag.Tests; -public class HashedFlagSetTests +public class CollectionFlagSetTests { [Fact] public void Add() { - var flags = new HashedFlagSet(); + var flags = new CollectionFlagSet(); var flagB = flags.Flag("B"); var flagC = flags.Flag("C"); var flagsBAndC = flags.Flag(flagB, flagC); @@ -20,7 +20,7 @@ public void Add() [Fact] public void Remove() { - var flags = new HashedFlagSet(); + var flags = new CollectionFlagSet(); var flagA = flags.Flag("A"); var flagB = flags.Flag("B"); var flagC = flags.Flag("C", flagA); @@ -33,7 +33,7 @@ public void Remove() [Fact] public void IsIn() { - var flags = new HashedFlagSet(); + var flags = new CollectionFlagSet(); var flagA = flags.Flag("A"); var flagB = flags.Flag("B"); var flagC = flags.Flag("C", flagA); @@ -47,7 +47,7 @@ public void IsIn() [Fact] public void IsAbstract() { - var flags = new HashedFlagSet(); + var flags = new CollectionFlagSet(); var flagA = flags.Flag("A"); var flagB = flags.Flag("B"); var flagsAAndB = flags.Flag(flagA, flagB); From dd30503bb34bec937ad65f982f9f0ddc9e2706c7 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Thu, 1 May 2025 10:29:31 +0200 Subject: [PATCH 02/15] test(.net): added tests for `CollectionFlagSet` --- dotnet/Tests/CollectionFlagSetTests.cs | 86 ++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/dotnet/Tests/CollectionFlagSetTests.cs b/dotnet/Tests/CollectionFlagSetTests.cs index 3484cb1..8c83164 100644 --- a/dotnet/Tests/CollectionFlagSetTests.cs +++ b/dotnet/Tests/CollectionFlagSetTests.cs @@ -4,6 +4,92 @@ namespace Multiflag.Tests; public class CollectionFlagSetTests { + [Fact] + public void Union() + { + var flags = new CollectionFlagSet(); + + Assert.Equal([], flags.Union([], [])); + Assert.Equal(["A"], flags.Union(["A"], [])); + Assert.Equal(["B"], flags.Union([], ["B"])); + Assert.Equal(["A", "B"], flags.Union(["A"], ["B"])); + Assert.Equal(["A", "B", "C"], flags.Union(["A", "B"], ["B", "C"])); + } + + [Fact] + public void Difference() + { + var flags = new CollectionFlagSet(); + + Assert.Equal([], flags.Difference([], [])); + Assert.Equal(["A"], flags.Difference(["A"], [])); + Assert.Equal(["A"], flags.Difference(["A", "B"], ["B", "C"])); + Assert.Equal(["C"], flags.Difference(["B", "C"], ["A", "B"])); + Assert.Equal(["D"], flags.Difference(["D"], ["A", "E"])); + } + + + [Fact] + public void Intersection() + { + var flags = new CollectionFlagSet(); + + Assert.Equal([], flags.Intersection([], [])); + Assert.Equal([], flags.Intersection(["A"], [])); + Assert.Equal([], flags.Intersection(["A"], ["B"])); + Assert.Equal(["A"], flags.Intersection(["A"], ["A", "B"])); + Assert.Equal(["A"], flags.Intersection(["A", "B", "D"], ["A", "C"])); + Assert.Equal(["A", "B"], flags.Intersection(["A", "B", "D"], ["A", "B", "C"])); + } + + [Fact] + public void Iterate() + { + var flags = new CollectionFlagSet(); + + Assert.Equal([], flags.Iterate([])); + Assert.Equal(["A"], flags.Iterate(["A"])); + Assert.Contains("A", flags.Iterate(["A", "B", "C"])); + Assert.Contains("B", flags.Iterate(["A", "B", "C"])); + Assert.Contains("C", flags.Iterate(["A", "B", "C"])); + } + + [Fact] + public void Minimum() + { + var flags = new CollectionFlagSet(); + var flagA = flags.Flag("A"); + var flagB = flags.Flag("B", flagA); + var flagC = flags.Flag("C", flagA); + var flagD = flags.Flag("D", flagC); + + Assert.Equal([], flags.Minimum([])); + Assert.Equal(["A"], flags.Minimum(["A"])); + Assert.Equal([], flags.Minimum(["B"])); + Assert.Equal(["A", "B"], flags.Minimum(["A", "B"])); + Assert.Equal(["A", "B"], flags.Minimum(["A", "B", "D"])); + Assert.Equal(["A", "C", "D"], flags.Minimum(["A", "C", "D"])); + Assert.Equal(["A"], flags.Minimum(["A", "E"])); + } + + [Fact] + public void Maximum() + { + var flags = new CollectionFlagSet(); + var flagA = flags.Flag("A"); + var flagB = flags.Flag("B", flagA); + var flagC = flags.Flag("C", flagA); + var flagD = flags.Flag("D", flagC); + + Assert.Equal([], flags.Maximum([])); + Assert.Equal(["A"], flags.Maximum(["A"])); + Assert.Equal(["B", "A"], flags.Maximum(["B"])); + Assert.Equal(["A", "B"], flags.Maximum(["A", "B"])); + Assert.Equal(["A", "B", "D", "C"], flags.Maximum(["A", "B", "D"])); + Assert.Equal(["A", "C", "D"], flags.Maximum(["A", "C", "D"])); + Assert.Equal(["A"], flags.Maximum(["A", "E"])); + } + [Fact] public void Add() { From 3046d657e93709364a7f012665055dde4aabd8b0 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Thu, 1 May 2025 12:27:47 +0200 Subject: [PATCH 03/15] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ad155be..e0e43ad 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Multiflag is a tiny language-agnostic library that makes manipulating bitflags ( especially if you have flags that depend on each other (for example, if you're managing permissions). - [Multiflag .NET](dotnet/README.md) [![Nuget Package](https://img.shields.io/nuget/v/Multiflag)](https://www.nuget.org/packages/Multiflag) -- [Multiflag JavaScript/TypeScript](node/README.md) [![npm](https://img.shields.io/npm/v/multiflag)](https://https://www.npmjs.com/package/multiflag) +- [Multiflag JavaScript/TypeScript](node/README.md) [![npm](https://img.shields.io/npm/v/multiflag)](https://www.npmjs.com/package/multiflag) ## What it does @@ -46,4 +46,4 @@ may come later. ## Licensing -Multiglag is available under the [MIT License](LICENSE). ⓒ 2023-2025 Louis DEVIE. +Multiflag is available under the [MIT License](LICENSE). ⓒ 2023-2025 Louis DEVIE. From 1186aae4d18b7ef25113f169f87b552f0ba43128 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Thu, 1 May 2025 12:28:40 +0200 Subject: [PATCH 04/15] chore: remove dotnet-backup --- dotnet-backup/Multiflag.sln | 37 ---- .../Bitflags/BigintBitManipulator.cs | 28 --- .../Multiflag/Bitflags/BitManipulator.cs | 55 ------ .../Multiflag/Bitflags/U16BitManipulator.cs | 27 --- .../Multiflag/Bitflags/U32BitManipulator.cs | 27 --- .../Multiflag/Bitflags/U64BitManipulator.cs | 27 --- .../Multiflag/Bitflags/U8BitManipulator.cs | 27 --- dotnet-backup/Multiflag/DynamicBitflagSet.cs | 26 --- dotnet-backup/Multiflag/EnumBitflagSet.cs | 90 ---------- dotnet-backup/Multiflag/Flag.cs | 117 ------------- dotnet-backup/Multiflag/FlagSet.cs | 104 ----------- .../Multiflag/ForeignFlagException.cs | 12 -- dotnet-backup/Multiflag/HashedFlagSet.cs | 42 ----- .../Multiflag/InvalidBitflagValueException.cs | 11 -- dotnet-backup/Multiflag/Multiflag.csproj | 35 ---- .../Multiflag/ReusedFlagValueException.cs | 12 -- dotnet-backup/Multiflag/U16BitflagSet.cs | 24 --- dotnet-backup/Multiflag/U32BitflagSet.cs | 23 --- dotnet-backup/Multiflag/U64BitflagSet.cs | 23 --- dotnet-backup/Multiflag/U8BitflagSet.cs | 22 --- .../Multiflag/UndefinedValueException.cs | 12 -- .../Multiflag/UnsupportedEnumTypeException.cs | 17 -- dotnet-backup/README.md | 2 - dotnet-backup/Tests/DynamicBitflagSetTests.cs | 82 --------- dotnet-backup/Tests/EnumBitflagSetTests.cs | 161 ------------------ dotnet-backup/Tests/FlagSetTests.cs | 25 --- dotnet-backup/Tests/FlagTests.cs | 144 ---------------- dotnet-backup/Tests/GlobalUsings.cs | 2 - dotnet-backup/Tests/HashedFlagSetTests.cs | 63 ------- dotnet-backup/Tests/Tests.csproj | 33 ---- dotnet-backup/Tests/U16BitflagSetTests.cs | 70 -------- dotnet-backup/Tests/U32BitflagSetTests.cs | 70 -------- dotnet-backup/Tests/U64BitflagSetTests.cs | 70 -------- dotnet-backup/Tests/U8BitflagSetTests.cs | 70 -------- dotnet-backup/global.json | 7 - 35 files changed, 1597 deletions(-) delete mode 100644 dotnet-backup/Multiflag.sln delete mode 100644 dotnet-backup/Multiflag/Bitflags/BigintBitManipulator.cs delete mode 100644 dotnet-backup/Multiflag/Bitflags/BitManipulator.cs delete mode 100644 dotnet-backup/Multiflag/Bitflags/U16BitManipulator.cs delete mode 100644 dotnet-backup/Multiflag/Bitflags/U32BitManipulator.cs delete mode 100644 dotnet-backup/Multiflag/Bitflags/U64BitManipulator.cs delete mode 100644 dotnet-backup/Multiflag/Bitflags/U8BitManipulator.cs delete mode 100644 dotnet-backup/Multiflag/DynamicBitflagSet.cs delete mode 100644 dotnet-backup/Multiflag/EnumBitflagSet.cs delete mode 100644 dotnet-backup/Multiflag/Flag.cs delete mode 100644 dotnet-backup/Multiflag/FlagSet.cs delete mode 100644 dotnet-backup/Multiflag/ForeignFlagException.cs delete mode 100644 dotnet-backup/Multiflag/HashedFlagSet.cs delete mode 100644 dotnet-backup/Multiflag/InvalidBitflagValueException.cs delete mode 100644 dotnet-backup/Multiflag/Multiflag.csproj delete mode 100644 dotnet-backup/Multiflag/ReusedFlagValueException.cs delete mode 100644 dotnet-backup/Multiflag/U16BitflagSet.cs delete mode 100644 dotnet-backup/Multiflag/U32BitflagSet.cs delete mode 100644 dotnet-backup/Multiflag/U64BitflagSet.cs delete mode 100644 dotnet-backup/Multiflag/U8BitflagSet.cs delete mode 100644 dotnet-backup/Multiflag/UndefinedValueException.cs delete mode 100644 dotnet-backup/Multiflag/UnsupportedEnumTypeException.cs delete mode 100644 dotnet-backup/README.md delete mode 100644 dotnet-backup/Tests/DynamicBitflagSetTests.cs delete mode 100644 dotnet-backup/Tests/EnumBitflagSetTests.cs delete mode 100644 dotnet-backup/Tests/FlagSetTests.cs delete mode 100644 dotnet-backup/Tests/FlagTests.cs delete mode 100644 dotnet-backup/Tests/GlobalUsings.cs delete mode 100644 dotnet-backup/Tests/HashedFlagSetTests.cs delete mode 100644 dotnet-backup/Tests/Tests.csproj delete mode 100644 dotnet-backup/Tests/U16BitflagSetTests.cs delete mode 100644 dotnet-backup/Tests/U32BitflagSetTests.cs delete mode 100644 dotnet-backup/Tests/U64BitflagSetTests.cs delete mode 100644 dotnet-backup/Tests/U8BitflagSetTests.cs delete mode 100644 dotnet-backup/global.json diff --git a/dotnet-backup/Multiflag.sln b/dotnet-backup/Multiflag.sln deleted file mode 100644 index a78a811..0000000 --- a/dotnet-backup/Multiflag.sln +++ /dev/null @@ -1,37 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.7.34031.279 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Multiflag", "Multiflag\Multiflag.csproj", "{130DA599-9D97-454F-8903-58546A81EB33}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{5FA23F97-4AF7-4E50-A00B-8061E40637B8}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Éléments de solution", "Éléments de solution", "{A2326173-037B-4F50-B202-D385541624BE}" - ProjectSection(SolutionItems) = preProject - README.md = README.md - ..\.github\workflows\tests.yml = ..\.github\workflows\tests.yml - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {130DA599-9D97-454F-8903-58546A81EB33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {130DA599-9D97-454F-8903-58546A81EB33}.Debug|Any CPU.Build.0 = Debug|Any CPU - {130DA599-9D97-454F-8903-58546A81EB33}.Release|Any CPU.ActiveCfg = Release|Any CPU - {130DA599-9D97-454F-8903-58546A81EB33}.Release|Any CPU.Build.0 = Release|Any CPU - {5FA23F97-4AF7-4E50-A00B-8061E40637B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5FA23F97-4AF7-4E50-A00B-8061E40637B8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5FA23F97-4AF7-4E50-A00B-8061E40637B8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5FA23F97-4AF7-4E50-A00B-8061E40637B8}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2AB972CF-D52A-4B2E-84FE-367E1E6A5BE8} - EndGlobalSection -EndGlobal diff --git a/dotnet-backup/Multiflag/Bitflags/BigintBitManipulator.cs b/dotnet-backup/Multiflag/Bitflags/BigintBitManipulator.cs deleted file mode 100644 index dc56a8b..0000000 --- a/dotnet-backup/Multiflag/Bitflags/BigintBitManipulator.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace Multiflag.Bitflags -{ - internal class BigintBitManipulator : BitManipulator - { - private static BigintBitManipulator? current; - - public static BigintBitManipulator Current => current ??= new BigintBitManipulator(); - - private BigintBitManipulator() - { - } - - protected override bool IsPowerOfTwo(BigInteger value) => value.IsPowerOfTwo; - - public override BigInteger Zero => 0; - - public override bool IsZero(BigInteger flags) => flags == 0; - - public override BigInteger Or(BigInteger first, BigInteger second) => first | second; - - public override BigInteger AndNot(BigInteger first, BigInteger second) => first & ~second; - - public override bool AndEquals(BigInteger first, BigInteger second) => (first & second) == second; - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/Bitflags/BitManipulator.cs b/dotnet-backup/Multiflag/Bitflags/BitManipulator.cs deleted file mode 100644 index 2a5e52e..0000000 --- a/dotnet-backup/Multiflag/Bitflags/BitManipulator.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Numerics; - -namespace Multiflag.Bitflags -{ - internal abstract class BitManipulator - { - public abstract void CheckPowerOfTwo(object value); - - public abstract object ZeroObject { get; } - - public abstract bool IsZero(object flags); - - public abstract object Or(object first, object second); - - public abstract object AndNot(object first, object second); - - public abstract bool AndEquals(object first, object second); - } - - internal abstract class BitManipulator : BitManipulator - where T : notnull - { - public override void CheckPowerOfTwo(object value) => this.CheckPowerOfTwo((T)value); - - public void CheckPowerOfTwo(T value) - { - if (!this.IsPowerOfTwo(value)) - { - throw new InvalidBitflagValueException(); - } - } - - protected abstract bool IsPowerOfTwo(T value); - - public override object ZeroObject => this.Zero; - - public abstract T Zero { get; } - - public override bool IsZero(object flags) => this.IsZero((T)flags); - - public abstract bool IsZero(T flags); - - public override object Or(object first, object second) => this.Or((T)first, (T)second); - - public abstract T Or(T first, T second); - - public override object AndNot(object first, object second) => this.AndNot((T)first, (T)second); - - public abstract T AndNot(T first, T second); - - public override bool AndEquals(object first, object second) => this.AndEquals((T)first, (T)second); - - public abstract bool AndEquals(T first, T second); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/Bitflags/U16BitManipulator.cs b/dotnet-backup/Multiflag/Bitflags/U16BitManipulator.cs deleted file mode 100644 index d983ba2..0000000 --- a/dotnet-backup/Multiflag/Bitflags/U16BitManipulator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Multiflag.Bitflags -{ - internal class U16BitManipulator : BitManipulator - { - private static U16BitManipulator? current; - - public static U16BitManipulator Current => current ??= new U16BitManipulator(); - - private U16BitManipulator() - { - } - - protected override bool IsPowerOfTwo(ushort value) => value != 0 && (value & (value - 1)) == 0; - - public override ushort Zero => 0; - - public override bool IsZero(ushort flags) => flags == 0; - - public override ushort Or(ushort first, ushort second) => (ushort)(first | second); - - public override ushort AndNot(ushort first, ushort second) => (ushort)(first & ~second); - - public override bool AndEquals(ushort first, ushort second) => (first & second) == second; - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/Bitflags/U32BitManipulator.cs b/dotnet-backup/Multiflag/Bitflags/U32BitManipulator.cs deleted file mode 100644 index 3726fbc..0000000 --- a/dotnet-backup/Multiflag/Bitflags/U32BitManipulator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Multiflag.Bitflags -{ - internal class U32BitManipulator : BitManipulator - { - private static U32BitManipulator? current; - - public static U32BitManipulator Current => current ??= new U32BitManipulator(); - - private U32BitManipulator() - { - } - - protected override bool IsPowerOfTwo(uint value) => value != 0 && (value & (value - 1)) == 0; - - public override uint Zero => 0; - - public override bool IsZero(uint flags) => flags == 0; - - public override uint Or(uint first, uint second) => first | second; - - public override uint AndNot(uint first, uint second) => first & ~second; - - public override bool AndEquals(uint first, uint second) => (first & second) == second; - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/Bitflags/U64BitManipulator.cs b/dotnet-backup/Multiflag/Bitflags/U64BitManipulator.cs deleted file mode 100644 index 72b7b84..0000000 --- a/dotnet-backup/Multiflag/Bitflags/U64BitManipulator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Multiflag.Bitflags -{ - internal class U64BitManipulator : BitManipulator - { - private static U64BitManipulator? current; - - public static U64BitManipulator Current => current ??= new U64BitManipulator(); - - private U64BitManipulator() - { - } - - protected override bool IsPowerOfTwo(ulong value) => value != 0 && (value & (value - 1)) == 0; - - public override ulong Zero => 0; - - public override bool IsZero(ulong flags) => flags == 0; - - public override ulong Or(ulong first, ulong second) => first | second; - - public override ulong AndNot(ulong first, ulong second) => first & ~second; - - public override bool AndEquals(ulong first, ulong second) => (first & second) == second; - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/Bitflags/U8BitManipulator.cs b/dotnet-backup/Multiflag/Bitflags/U8BitManipulator.cs deleted file mode 100644 index 7f25714..0000000 --- a/dotnet-backup/Multiflag/Bitflags/U8BitManipulator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Multiflag.Bitflags -{ - internal class U8BitManipulator : BitManipulator - { - private static U8BitManipulator? current; - - public static U8BitManipulator Current => current ??= new U8BitManipulator(); - - private U8BitManipulator() - { - } - - protected override bool IsPowerOfTwo(byte value) => value != 0 && (value & (value - 1)) == 0; - - public override byte Zero => 0; - - public override bool IsZero(byte flags) => flags == 0; - - public override byte Or(byte first, byte second) => (byte)(first | second); - - public override byte AndNot(byte first, byte second) => (byte)(first & ~second); - - public override bool AndEquals(byte first, byte second) => (first & second) == second; - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/DynamicBitflagSet.cs b/dotnet-backup/Multiflag/DynamicBitflagSet.cs deleted file mode 100644 index c42c717..0000000 --- a/dotnet-backup/Multiflag/DynamicBitflagSet.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Numerics; -using Multiflag.Bitflags; - -namespace Multiflag -{ - /// - /// Provides bitflags based on dynamic integers (thus allowing any number of flags). - /// - public class DynamicBitflagSet : FlagSet - { - protected override void CheckValue(BigInteger value) => BigintBitManipulator.Current.CheckPowerOfTwo(value); - - public override BigInteger Empty() => BigintBitManipulator.Current.Zero; - - public override bool IsEmpty(BigInteger flags) => BigintBitManipulator.Current.IsZero(flags); - - public override BigInteger Union(BigInteger first, BigInteger second) => - BigintBitManipulator.Current.Or(first, second); - - public override BigInteger Difference(BigInteger first, BigInteger second) => - BigintBitManipulator.Current.AndNot(first, second); - - public override bool IsSupersetOf(BigInteger first, BigInteger second) => - BigintBitManipulator.Current.AndEquals(first, second); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/EnumBitflagSet.cs b/dotnet-backup/Multiflag/EnumBitflagSet.cs deleted file mode 100644 index b812f56..0000000 --- a/dotnet-backup/Multiflag/EnumBitflagSet.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using Multiflag.Bitflags; - -namespace Multiflag -{ - /// - /// Provides bitflags based on dynamic integers (thus allowing any number of flags). - /// - public class EnumBitflagSet : FlagSet - where T : Enum - { - private readonly Type enumType; - private readonly Type underlyingType; - private readonly BitManipulator bitManipulator; - - public EnumBitflagSet() - { - this.enumType = typeof(T); - this.underlyingType = this.enumType.GetEnumUnderlyingType(); - this.bitManipulator = FindBitManipulator(this.underlyingType); - } - - private static BitManipulator FindBitManipulator(Type underlyingType) - { - if (underlyingType == typeof(sbyte)) - { - throw new UnsupportedEnumTypeException(underlyingType, "byte"); - } - else if (underlyingType == typeof(byte)) - { - return U8BitManipulator.Current; - } - else if (underlyingType == typeof(short)) - { - throw new UnsupportedEnumTypeException(underlyingType, "ushort"); - } - else if (underlyingType == typeof(ushort)) - { - return U16BitManipulator.Current; - } - else if (underlyingType == typeof(int)) - { - throw new UnsupportedEnumTypeException(underlyingType, "uint"); - } - else if (underlyingType == typeof(uint)) - { - return U32BitManipulator.Current; - } - else if (underlyingType == typeof(long)) - { - throw new UnsupportedEnumTypeException(underlyingType, "ulong"); - } - else if (underlyingType == typeof(ulong)) - { - return U64BitManipulator.Current; - } - else - { - throw new UnsupportedEnumTypeException(underlyingType); - } - } - - private object EnumToInt(object value) => Convert.ChangeType(value, this.underlyingType); - - private T IntToEnum(object value) => (T)Enum.ToObject(this.enumType, value); - - protected override void CheckValue(T value) - { - this.bitManipulator.CheckPowerOfTwo(this.EnumToInt(value)); - - if (!Enum.IsDefined(this.enumType, value)) - { - throw new UndefinedEnumValueException(value); - } - } - - public override T Empty() => this.IntToEnum(this.bitManipulator.ZeroObject); - - public override bool IsEmpty(T flags) => this.bitManipulator.IsZero(this.EnumToInt(flags)); - - public override T Union(T first, T second) => - this.IntToEnum(this.bitManipulator.Or(this.EnumToInt(first), this.EnumToInt(second))); - - public override T Difference(T first, T second) => - this.IntToEnum(this.bitManipulator.AndNot(this.EnumToInt(first), this.EnumToInt(second))); - - public override bool IsSupersetOf(T first, T second) => - this.bitManipulator.AndEquals(this.EnumToInt(first), this.EnumToInt(second)); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/Flag.cs b/dotnet-backup/Multiflag/Flag.cs deleted file mode 100644 index 783eb9d..0000000 --- a/dotnet-backup/Multiflag/Flag.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Multiflag -{ - /// - /// A represents some element of - /// that can be added or removed from the set. - /// When a flag is added to the set, all of its parents are added along - /// with it, and when it is removed all of its children are removed too. - /// - /// - public class Flag - where T : notnull - { - private readonly FlagSet set; - private readonly T value; - private readonly List> parents; - private readonly List> children; - - /// - /// Creates a new flag. - /// - /// The set this flag belongs to. - /// The value of the flag. - /// The parent flags. - /// - /// If one of the parents doesn't belong to the same . - /// - internal Flag(FlagSet set, T value, IEnumerable> parents) - { - this.set = set; - this.value = value; - this.parents = parents.ToList(); - this.children = new List>(); - - foreach (var parent in this.parents) - { - if (!parent.BelongsTo(this.set)) - { - throw new ForeignFlagException(); - } - - parent.children.Add(this); - } - } - - private bool BelongsTo(FlagSet flagSet) - { - return this.set == flagSet; - } - - /// - /// Add a flag if it is not already present. - /// - /// The flags to add it to. - /// The modified flags. - /// - /// If is reference type, the flags passed to the function may be modified in-place. - /// - public T AddTo(T flags) - { - return this.parents.Aggregate( - this.set.Union(flags, this.value), - (current, parent) => parent.AddTo(current) - ); - } - - /// - /// See . - /// - public static T operator +(T value, Flag flag) - { - return flag.AddTo(value); - } - - /// - /// Removes a flag if it is present. - /// - /// The flags to remove it from. - /// The modified flags. - /// - /// If is reference type, the flags passed to the function may be modified in-place. - /// - public T RemoveFrom(T flags) - { - return this.children.Aggregate( - this.set.Difference(flags, this.value), - (current, child) => child.RemoveFrom(current) - ); - } - - /// - /// See - /// - public static T operator -(T value, Flag flag) - { - return flag.RemoveFrom(value); - } - - /// - /// Check whether this flag is in . - /// - /// The flags to search in. - /// - /// if this flag belongs to the set of - /// , otherwise . - /// - public bool IsIn(T flags) => this.set.IsSupersetOf(flags, this.value) - && this.parents.All(parent => parent.IsIn(flags)); - - /// - /// when this flag has no value on its own. - /// - public bool IsAbstract => this.set.IsEmpty(this.value); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/FlagSet.cs b/dotnet-backup/Multiflag/FlagSet.cs deleted file mode 100644 index 4ef4fe9..0000000 --- a/dotnet-backup/Multiflag/FlagSet.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System.Collections.Generic; - -namespace Multiflag -{ - /// - /// Represent a group of flags, and provide methods to use - /// as a set. Built-in implementations exist for - /// unsigned integers, enums and . - /// - /// The type to be used as a set of flags. - public abstract class FlagSet - where T : notnull - { - private readonly Dictionary> concreteFlags; - - protected FlagSet() - { - this.concreteFlags = new Dictionary>(); - } - - /// - /// Creates a flag without a value. - /// - /// Other flags required for this flag to be set. - /// A flag bound to this set. - /// - /// If one of the parents doesn't belong to the same . - /// - public Flag Flag(params Flag[] parents) - { - return new Flag(this, this.Empty(), parents); - } - - /// - /// Creates a flag with a value. - /// - /// The value of the flag. - /// Other flags required for this flag to be set. - /// A flag bound to this set. - /// - /// If one of the parents doesn't belong to the same . - /// - /// - /// If another flag has already been created with the same value. - /// - public Flag Flag(T value, params Flag[] parents) - { - this.CheckValue(value); - - if (this.concreteFlags.ContainsKey(value)) - { - throw new ReusedFlagValueException(value); - } - - var flag = new Flag(this, value, parents); - this.concreteFlags.Add(value, flag); - return flag; - } - - /// - /// This method will be called when a new flag is about to be created - /// with that value. The default implementation does nothing, but it - /// may be overriden to throw an exception on invalid values. - /// - /// The value that will be used for the flag. - protected virtual void CheckValue(T value) - { - } - - /// - /// Creates an empty set of flags. - /// - public abstract T Empty(); - - /// - /// Checks if a set of flags is the empty set. - /// - /// The set of flags to test. - public abstract bool IsEmpty(T flags); - - /// - /// Computes the union of two sets of flags. - /// - /// The first set of flags. - /// The second set of flags. - /// A new set that contains the flags of both sets. - public abstract T Union(T first, T second); - - /// - /// Computes the difference of two set of flags. - /// - /// The first set of flags. - /// The second set of flags (that will be subtracted from the first). - /// A new set that contains the flags of the first set that do not appear in the second. - public abstract T Difference(T first, T second); - - /// - /// Checks whether the first set of flags is a superset of the second. - /// - /// The first set of flags. - /// The second set of flags. - public abstract bool IsSupersetOf(T first, T second); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/ForeignFlagException.cs b/dotnet-backup/Multiflag/ForeignFlagException.cs deleted file mode 100644 index 843bbba..0000000 --- a/dotnet-backup/Multiflag/ForeignFlagException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Multiflag -{ - public class ForeignFlagException : ArgumentException - { - internal ForeignFlagException() : base( - "Cannot create a dependency between two flags created in different sets.") - { - } - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/HashedFlagSet.cs b/dotnet-backup/Multiflag/HashedFlagSet.cs deleted file mode 100644 index 10c2825..0000000 --- a/dotnet-backup/Multiflag/HashedFlagSet.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Collections.Immutable; - -namespace Multiflag -{ - /// - /// Provides flags that work on HashSets. The flags can have values of any type and there is no limit to the number - /// of different flags, and sets can easily be serialized (as a JSON array for example). - /// - public class HashedFlagSet : FlagSet> - where T : notnull - { - /// - /// Creates a flag with a value. - /// - /// The value of the flag. - /// Other flags required for this flag to be set. - /// A flag bound to this set. - /// - /// If one of the parents doesn't belong to the same . - /// - /// - /// If another flag has already been created with the same value. - /// - public Flag> Flag(T value, params Flag>[] parents) - { - return this.Flag(ImmutableHashSet.Create(value), parents); - } - - public override IImmutableSet Empty() => ImmutableHashSet.Empty; - - public override bool IsEmpty(IImmutableSet flags) => flags.Count == 0; - - public override IImmutableSet Union(IImmutableSet first, IImmutableSet second) => - first.Union(second); - - public override IImmutableSet Difference(IImmutableSet first, IImmutableSet second) => - first.Except(second); - - public override bool IsSupersetOf(IImmutableSet first, IImmutableSet second) => - first.IsSupersetOf(second); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/InvalidBitflagValueException.cs b/dotnet-backup/Multiflag/InvalidBitflagValueException.cs deleted file mode 100644 index 46cc15f..0000000 --- a/dotnet-backup/Multiflag/InvalidBitflagValueException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Multiflag -{ - public class InvalidBitflagValueException : ArgumentException - { - internal InvalidBitflagValueException() : base("Flag values for bit flags must be powers of two.") - { - } - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/Multiflag.csproj b/dotnet-backup/Multiflag/Multiflag.csproj deleted file mode 100644 index f651cca..0000000 --- a/dotnet-backup/Multiflag/Multiflag.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - netstandard2.1;net8.0;net9.0 - enable - True - Multiflag - 2.0.0 - Louis DEVIE - - True - MIT - flag:flagging;bitflag;enum;states;permissions;features; - https://github.com/louisdevie/multiflag - README.md - A library to help you manipulate (bit)flags easily and enables you to implement inheritance between flags. - https://louisdevie.github.io/multiflag - - - - - - - - - True - \ - - - - - - - - diff --git a/dotnet-backup/Multiflag/ReusedFlagValueException.cs b/dotnet-backup/Multiflag/ReusedFlagValueException.cs deleted file mode 100644 index 81a4958..0000000 --- a/dotnet-backup/Multiflag/ReusedFlagValueException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Multiflag -{ - public class ReusedFlagValueException : ArgumentException - { - internal ReusedFlagValueException(object value) - : base($"The flag value {value} is already being used for another flag.") - { - } - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/U16BitflagSet.cs b/dotnet-backup/Multiflag/U16BitflagSet.cs deleted file mode 100644 index aaf43e1..0000000 --- a/dotnet-backup/Multiflag/U16BitflagSet.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Multiflag.Bitflags; - -namespace Multiflag -{ - /// - /// Provides bitflags based on 16-bit unsigned integers (thus allowing 16 different flags). - /// - public class U16BitflagSet : FlagSet - { - protected override void CheckValue(ushort value) => U16BitManipulator.Current.CheckPowerOfTwo(value); - - public override ushort Empty() => U16BitManipulator.Current.Zero; - - public override bool IsEmpty(ushort flags) => U16BitManipulator.Current.IsZero(flags); - - public override ushort Union(ushort first, ushort second) => U16BitManipulator.Current.Or(first, second); - - public override ushort Difference(ushort first, ushort second) => - U16BitManipulator.Current.AndNot(first, second); - - public override bool IsSupersetOf(ushort first, ushort second) => - U16BitManipulator.Current.AndEquals(first, second); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/U32BitflagSet.cs b/dotnet-backup/Multiflag/U32BitflagSet.cs deleted file mode 100644 index 2b97b8a..0000000 --- a/dotnet-backup/Multiflag/U32BitflagSet.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Multiflag.Bitflags; - -namespace Multiflag -{ - /// - /// Provides bitflags based on 32-bit unsigned integers (thus allowing 32 different flags). - /// - public class U32BitflagSet : FlagSet - { - protected override void CheckValue(uint value) => U32BitManipulator.Current.CheckPowerOfTwo(value); - - public override uint Empty() => U32BitManipulator.Current.Zero; - - public override bool IsEmpty(uint flags) => U32BitManipulator.Current.IsZero(flags); - - public override uint Union(uint first, uint second) => U32BitManipulator.Current.Or(first, second); - - public override uint Difference(uint first, uint second) => U32BitManipulator.Current.AndNot(first, second); - - public override bool IsSupersetOf(uint first, uint second) => - U32BitManipulator.Current.AndEquals(first, second); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/U64BitflagSet.cs b/dotnet-backup/Multiflag/U64BitflagSet.cs deleted file mode 100644 index 1254b43..0000000 --- a/dotnet-backup/Multiflag/U64BitflagSet.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Multiflag.Bitflags; - -namespace Multiflag -{ - /// - /// Provides bitflags based on 64-bit unsigned integers (thus allowing 64 different flags). - /// - public class U64BitflagSet : FlagSet - { - protected override void CheckValue(ulong value) => U64BitManipulator.Current.CheckPowerOfTwo(value); - - public override ulong Empty() => U64BitManipulator.Current.Zero; - - public override bool IsEmpty(ulong flags) => U64BitManipulator.Current.IsZero(flags); - - public override ulong Union(ulong first, ulong second) => U64BitManipulator.Current.Or(first, second); - - public override ulong Difference(ulong first, ulong second) => U64BitManipulator.Current.AndNot(first, second); - - public override bool IsSupersetOf(ulong first, ulong second) => - U64BitManipulator.Current.AndEquals(first, second); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/U8BitflagSet.cs b/dotnet-backup/Multiflag/U8BitflagSet.cs deleted file mode 100644 index 5b03be7..0000000 --- a/dotnet-backup/Multiflag/U8BitflagSet.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Multiflag.Bitflags; - -namespace Multiflag -{ - /// - /// Provides bitflags based on 8-bit unsigned integers (thus allowing 8 different flags). - /// - public class U8BitflagSet : FlagSet - { - protected override void CheckValue(byte value) => U8BitManipulator.Current.CheckPowerOfTwo(value); - - public override byte Empty() => U8BitManipulator.Current.Zero; - - public override bool IsEmpty(byte flags) => U8BitManipulator.Current.IsZero(flags); - - public override byte Union(byte first, byte second) => U8BitManipulator.Current.Or(first, second); - - public override byte Difference(byte first, byte second) => U8BitManipulator.Current.AndNot(first, second); - - public override bool IsSupersetOf(byte first, byte second) => U8BitManipulator.Current.AndEquals(first, second); - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/UndefinedValueException.cs b/dotnet-backup/Multiflag/UndefinedValueException.cs deleted file mode 100644 index 80494ef..0000000 --- a/dotnet-backup/Multiflag/UndefinedValueException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Multiflag -{ - public class UndefinedEnumValueException : ArgumentException - { - internal UndefinedEnumValueException(object badValue) - : base($"The value {badValue} cannot be used as a flag because it isn't a member of the enum.") - { - } - } -} \ No newline at end of file diff --git a/dotnet-backup/Multiflag/UnsupportedEnumTypeException.cs b/dotnet-backup/Multiflag/UnsupportedEnumTypeException.cs deleted file mode 100644 index a053dcb..0000000 --- a/dotnet-backup/Multiflag/UnsupportedEnumTypeException.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Multiflag -{ - public class UnsupportedEnumTypeException : ArgumentException - { - internal UnsupportedEnumTypeException(Type underlyingType) - : base($"Enums with an underlying type of {underlyingType} are not supported. Use one of byte, ushort, uint or ulong instead.") - { - } - - internal UnsupportedEnumTypeException(Type underlyingType, string suggestedType) - : base($"Enums with an underlying type of {underlyingType} are not supported. Use {suggestedType} instead.") - { - } - } -} \ No newline at end of file diff --git a/dotnet-backup/README.md b/dotnet-backup/README.md deleted file mode 100644 index 3e33113..0000000 --- a/dotnet-backup/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Multiflag for .NET - diff --git a/dotnet-backup/Tests/DynamicBitflagSetTests.cs b/dotnet-backup/Tests/DynamicBitflagSetTests.cs deleted file mode 100644 index 535edfc..0000000 --- a/dotnet-backup/Tests/DynamicBitflagSetTests.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace Multiflag.Tests; - -public class DynamicBitflagSetTests -{ - private static readonly BigInteger BigPowerOfTwo = new BigInteger(1) << 100; - - [Fact] - public void ValueNotAPowerOfTwo() - { - var flags = new DynamicBitflagSet(); - Assert.Throws(() => flags.Flag(0)); - Assert.Throws(() => flags.Flag(11)); - } - - [Fact] - public void Add() - { - var flags = new DynamicBitflagSet(); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4); - var flags2And4 = flags.Flag(flag2, flag4); - var flag100 = flags.Flag(BigPowerOfTwo); - - Assert.Equal(3u, 1 + flag2); - Assert.Equal(5u, 1 + flag4); - Assert.Equal(7u, 1 + flags2And4); - Assert.Equal(BigPowerOfTwo + 1, 1 + flag100); - Assert.Equal(BigPowerOfTwo + 2, BigPowerOfTwo + flag2); - } - - [Fact] - public void Remove() - { - - var flags = new DynamicBitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - var flag100 = flags.Flag(BigPowerOfTwo); - - Assert.Equal(2u, 7 - flag1); - Assert.Equal(5u, 7 - flag2); - Assert.Equal(3u, 7 - flag4); - Assert.Equal(2, BigPowerOfTwo + 2 - flag100); - Assert.Equal(2, 2 - flag100); - Assert.Equal(BigPowerOfTwo - 6, BigPowerOfTwo - 1 - flag1); - } - - [Fact] - public void IsIn() - { - var flags = new DynamicBitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.True(flag1.IsIn(1)); - Assert.True(flag2.IsIn(3)); - Assert.False(flag4.IsIn(4)); - Assert.True(flag4.IsIn(5)); - Assert.False(flag4.IsIn(BigPowerOfTwo + 1)); - } - - [Fact] - public void IsAbstract() - { - var flags = new DynamicBitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flags1And2 = flags.Flag(flag1, flag2); - var flag4 = flags.Flag(4, flags1And2); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.True(flags1And2.IsAbstract); - Assert.False(flag4.IsAbstract); - } -} \ No newline at end of file diff --git a/dotnet-backup/Tests/EnumBitflagSetTests.cs b/dotnet-backup/Tests/EnumBitflagSetTests.cs deleted file mode 100644 index a3b5ff0..0000000 --- a/dotnet-backup/Tests/EnumBitflagSetTests.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Multiflag.Tests; - -public class EnumBitflagSetTests -{ - private enum S8Enum : sbyte; - - private enum U8Enum : byte - { - A = 1, - B = 2, - C = 4 - } - - private enum S16Enum : short; - - private enum U16Enum : ushort - { - A = 1, - B = 2, - C = 4 - } - - private enum S32Enum; - - private enum U32Enum : uint - { - A = 1, - B = 2, - C = 4 - } - - private enum S64Enum : long; - - private enum U64Enum : ulong - { - A = 1, - B = 2, - C = 4 - } - - [Fact] - public void SignedEnumsAreUnsupported() - { - Assert.Throws(() => new EnumBitflagSet()); - Assert.Throws(() => new EnumBitflagSet()); - Assert.Throws(() => new EnumBitflagSet()); - Assert.Throws(() => new EnumBitflagSet()); - } - - [Fact] - public void ValueNotAPowerOfTwo() - { - var flags = new EnumBitflagSet(); - Assert.Throws(() => flags.Flag(0)); - Assert.Throws(() => flags.Flag((U32Enum)11)); - } - - [Fact] - public void ValueNotDefined() - { - var flags = new EnumBitflagSet(); - Assert.Throws(() => flags.Flag((U32Enum)8)); - } - - [Fact] - public void Add() - { - var flags = new EnumBitflagSet(); - var flagB = flags.Flag(U32Enum.B); - var flagC = flags.Flag(U32Enum.C); - var flags2And4 = flags.Flag(flagB, flagC); - - Assert.Equal((U32Enum)3, U32Enum.A + flagB); - Assert.Equal((U32Enum)5, U32Enum.A + flagC); - Assert.Equal((U32Enum)7, U32Enum.A + flags2And4); - } - - [Fact] - public void Add8Bit() - { - var flags = new EnumBitflagSet(); - var flagB = flags.Flag(U8Enum.B); - var flagC = flags.Flag(U8Enum.C); - var flags2And4 = flags.Flag(flagB, flagC); - - Assert.Equal((U8Enum)3, U8Enum.A + flagB); - Assert.Equal((U8Enum)5, U8Enum.A + flagC); - Assert.Equal((U8Enum)7, U8Enum.A + flags2And4); - } - - [Fact] - public void Add16Bit() - { - var flags = new EnumBitflagSet(); - var flagB = flags.Flag(U16Enum.B); - var flagC = flags.Flag(U16Enum.C); - var flags2And4 = flags.Flag(flagB, flagC); - - Assert.Equal((U16Enum)3, U16Enum.A + flagB); - Assert.Equal((U16Enum)5, U16Enum.A + flagC); - Assert.Equal((U16Enum)7, U16Enum.A + flags2And4); - } - - [Fact] - public void Add64Bit() - { - var flags = new EnumBitflagSet(); - var flagB = flags.Flag(U64Enum.B); - var flagC = flags.Flag(U64Enum.C); - var flags2And4 = flags.Flag(flagB, flagC); - - Assert.Equal((U64Enum)3, U64Enum.A + flagB); - Assert.Equal((U64Enum)5, U64Enum.A + flagC); - Assert.Equal((U64Enum)7, U64Enum.A + flags2And4); - } - - [Fact] - public void Remove() - { - var flags = new EnumBitflagSet(); - var flagA = flags.Flag(U32Enum.A); - var flagB = flags.Flag(U32Enum.B); - var flagC = flags.Flag(U32Enum.C, flagA); - - Assert.Equal(U32Enum.B, (U32Enum)7 - flagA); - Assert.Equal((U32Enum)5, (U32Enum)7 - flagB); - Assert.Equal((U32Enum)3, (U32Enum)7 - flagC); - } - - [Fact] - public void IsIn() - { - var flags = new EnumBitflagSet(); - var flagA = flags.Flag(U32Enum.A); - var flagB = flags.Flag(U32Enum.B); - var flagC = flags.Flag(U32Enum.C, flagA); - - Assert.True(flagA.IsIn(U32Enum.A)); - Assert.True(flagB.IsIn((U32Enum)3)); - Assert.False(flagC.IsIn(U32Enum.B)); - Assert.True(flagC.IsIn((U32Enum)5)); - } - - [Fact] - public void IsAbstract() - { - var flags = new EnumBitflagSet(); - var flagA = flags.Flag(U32Enum.A); - var flagB = flags.Flag(U32Enum.B); - var flags1And2 = flags.Flag(flagA, flagB); - var flagC = flags.Flag(U32Enum.C, flags1And2); - - Assert.False(flagA.IsAbstract); - Assert.False(flagB.IsAbstract); - Assert.True(flags1And2.IsAbstract); - Assert.False(flagC.IsAbstract); - } -} \ No newline at end of file diff --git a/dotnet-backup/Tests/FlagSetTests.cs b/dotnet-backup/Tests/FlagSetTests.cs deleted file mode 100644 index 5b26ffb..0000000 --- a/dotnet-backup/Tests/FlagSetTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Multiflag.Tests; - -public class FlagSetTests -{ - [Fact] - public void UseFlagFromOtherSetAsParent() - { - var flags = new U8BitflagSet(); - var flag = flags.Flag(1); - - var otherFlags = new U8BitflagSet(); - Assert.Throws(() => otherFlags.Flag(2, flag)); - } - - [Fact] - public void UseSameValueTwice() - { - var flags = new U8BitflagSet(); - var flag = flags.Flag(1); - Assert.Throws(() => flags.Flag(1, flag)); - } -} \ No newline at end of file diff --git a/dotnet-backup/Tests/FlagTests.cs b/dotnet-backup/Tests/FlagTests.cs deleted file mode 100644 index 12e088c..0000000 --- a/dotnet-backup/Tests/FlagTests.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Multiflag.Tests; - -public class FlagTests -{ - private class MyBitflags : U8BitflagSet - { - private static MyBitflags? current; - - public static MyBitflags Current => current ??= new MyBitflags(); - - public Flag FlagA { get; } - public Flag FlagB { get; } - public Flag FlagC { get; } - public Flag FlagD { get; } - - private MyBitflags() - { - this.FlagA = this.Flag(1); - this.FlagB = this.Flag(2); - this.FlagC = this.Flag(this.FlagA, this.FlagB); - this.FlagD = this.Flag(4, this.FlagA); - } - } - - [Fact] - public void AddTo() - { - Assert.Equal(1, MyBitflags.Current.FlagA.AddTo(0)); - Assert.Equal(3, MyBitflags.Current.FlagA.AddTo(2)); - Assert.Equal(7, MyBitflags.Current.FlagA.AddTo(7)); - - Assert.Equal(2, MyBitflags.Current.FlagB.AddTo(0)); - Assert.Equal(2, MyBitflags.Current.FlagB.AddTo(2)); - Assert.Equal(7, MyBitflags.Current.FlagB.AddTo(7)); - - Assert.Equal(3, MyBitflags.Current.FlagC.AddTo(0)); - Assert.Equal(3, MyBitflags.Current.FlagC.AddTo(2)); - Assert.Equal(7, MyBitflags.Current.FlagC.AddTo(7)); - - Assert.Equal(7, MyBitflags.Current.FlagD.AddTo(2)); - Assert.Equal(5, MyBitflags.Current.FlagD.AddTo(0)); - Assert.Equal(7, MyBitflags.Current.FlagD.AddTo(7)); - } - - [Fact] - public void Addition() - { - Assert.Equal(1, 0 + MyBitflags.Current.FlagA); - Assert.Equal(3, 2 + MyBitflags.Current.FlagA); - Assert.Equal(7, 7 + MyBitflags.Current.FlagA); - - Assert.Equal(2, 0 + MyBitflags.Current.FlagB); - Assert.Equal(2, 2 + MyBitflags.Current.FlagB); - Assert.Equal(7, 7 + MyBitflags.Current.FlagB); - - Assert.Equal(3, 0 + MyBitflags.Current.FlagC); - Assert.Equal(3, 2 + MyBitflags.Current.FlagC); - Assert.Equal(7, 7 + MyBitflags.Current.FlagC); - - Assert.Equal(7, 2 + MyBitflags.Current.FlagD); - Assert.Equal(5, 0 + MyBitflags.Current.FlagD); - Assert.Equal(7, 7 + MyBitflags.Current.FlagD); - } - - [Fact] - public void RemoveFrom() - { - Assert.Equal(0, MyBitflags.Current.FlagA.RemoveFrom(0)); - Assert.Equal(2, MyBitflags.Current.FlagA.RemoveFrom(2)); - Assert.Equal(2, MyBitflags.Current.FlagA.RemoveFrom(7)); - - Assert.Equal(0, MyBitflags.Current.FlagB.RemoveFrom(0)); - Assert.Equal(0, MyBitflags.Current.FlagB.RemoveFrom(2)); - Assert.Equal(5, MyBitflags.Current.FlagB.RemoveFrom(7)); - - Assert.Equal(0, MyBitflags.Current.FlagC.RemoveFrom(0)); - Assert.Equal(2, MyBitflags.Current.FlagC.RemoveFrom(2)); - Assert.Equal(7, MyBitflags.Current.FlagC.RemoveFrom(7)); - - Assert.Equal(2, MyBitflags.Current.FlagD.RemoveFrom(2)); - Assert.Equal(0, MyBitflags.Current.FlagD.RemoveFrom(0)); - Assert.Equal(3, MyBitflags.Current.FlagD.RemoveFrom(7)); - } - - [Fact] - public void Subtraction() - { - Assert.Equal(0, 0 - MyBitflags.Current.FlagA); - Assert.Equal(2, 2 - MyBitflags.Current.FlagA); - Assert.Equal(2, 7 - MyBitflags.Current.FlagA); - - Assert.Equal(0, 0 - MyBitflags.Current.FlagB); - Assert.Equal(0, 2 - MyBitflags.Current.FlagB); - Assert.Equal(5, 7 - MyBitflags.Current.FlagB); - - Assert.Equal(0, 0 - MyBitflags.Current.FlagC); - Assert.Equal(2, 2 - MyBitflags.Current.FlagC); - Assert.Equal(7, 7 - MyBitflags.Current.FlagC); - - Assert.Equal(0, 0 - MyBitflags.Current.FlagD); - Assert.Equal(2, 2 - MyBitflags.Current.FlagD); - Assert.Equal(3, 7 - MyBitflags.Current.FlagD); - } - - [Fact] - public void IsIn() - { - Assert.False(MyBitflags.Current.FlagA.IsIn(0)); - Assert.True(MyBitflags.Current.FlagA.IsIn(1)); - Assert.False(MyBitflags.Current.FlagA.IsIn(4)); - Assert.True(MyBitflags.Current.FlagA.IsIn(7)); - - Assert.False(MyBitflags.Current.FlagB.IsIn(0)); - Assert.True(MyBitflags.Current.FlagB.IsIn(2)); - Assert.False(MyBitflags.Current.FlagB.IsIn(4)); - Assert.True(MyBitflags.Current.FlagB.IsIn(7)); - - Assert.False(MyBitflags.Current.FlagC.IsIn(0)); - Assert.False(MyBitflags.Current.FlagC.IsIn(1)); - Assert.False(MyBitflags.Current.FlagC.IsIn(2)); - Assert.True(MyBitflags.Current.FlagC.IsIn(3)); - Assert.False(MyBitflags.Current.FlagC.IsIn(4)); - Assert.True(MyBitflags.Current.FlagC.IsIn(7)); - - Assert.False(MyBitflags.Current.FlagD.IsIn(0)); - Assert.False(MyBitflags.Current.FlagD.IsIn(1)); - Assert.False(MyBitflags.Current.FlagD.IsIn(4)); - Assert.True(MyBitflags.Current.FlagD.IsIn(5)); - Assert.False(MyBitflags.Current.FlagD.IsIn(6)); - Assert.True(MyBitflags.Current.FlagD.IsIn(7)); - } - - [Fact] - public void IsAbstract() - { - Assert.False(MyBitflags.Current.FlagA.IsAbstract); - Assert.False(MyBitflags.Current.FlagB.IsAbstract); - Assert.True(MyBitflags.Current.FlagC.IsAbstract); - Assert.False(MyBitflags.Current.FlagD.IsAbstract); - } -} \ No newline at end of file diff --git a/dotnet-backup/Tests/GlobalUsings.cs b/dotnet-backup/Tests/GlobalUsings.cs deleted file mode 100644 index 734476d..0000000 --- a/dotnet-backup/Tests/GlobalUsings.cs +++ /dev/null @@ -1,2 +0,0 @@ -global using Xunit; -global using Multiflag; \ No newline at end of file diff --git a/dotnet-backup/Tests/HashedFlagSetTests.cs b/dotnet-backup/Tests/HashedFlagSetTests.cs deleted file mode 100644 index 94af9b0..0000000 --- a/dotnet-backup/Tests/HashedFlagSetTests.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Immutable; -using System.Runtime.CompilerServices; - -namespace Multiflag.Tests; - -public class HashedFlagSetTests -{ - [Fact] - public void Add() - { - var flags = new HashedFlagSet(); - var flagB = flags.Flag("B"); - var flagC = flags.Flag("C"); - var flags2And4 = flags.Flag(flagB, flagC); - - Assert.Equal(ImmutableHashSet.Create("A", "B"), ImmutableHashSet.Create("A") + flagB); - Assert.Equal(ImmutableHashSet.Create("A", "C"), ImmutableHashSet.Create("A") + flagC); - Assert.Equal(ImmutableHashSet.Create("A", "B", "C"), ImmutableHashSet.Create("A") + flags2And4); - } - - [Fact] - public void Remove() - { - var flags = new HashedFlagSet(); - var flagA = flags.Flag("A"); - var flagB = flags.Flag("B"); - var flagC = flags.Flag("C", flagA); - - Assert.Equal(ImmutableHashSet.Create("B"), ImmutableHashSet.Create("A", "B", "C") - flagA); - Assert.Equal(ImmutableHashSet.Create("A", "C"), ImmutableHashSet.Create("A", "B", "C") - flagB); - Assert.Equal(ImmutableHashSet.Create("A", "B"), ImmutableHashSet.Create("A", "B", "C") - flagC); - } - - [Fact] - public void IsIn() - { - var flags = new HashedFlagSet(); - var flagA = flags.Flag("A"); - var flagB = flags.Flag("B"); - var flagC = flags.Flag("C", flagA); - - Assert.True(flagA.IsIn(ImmutableHashSet.Create("A"))); - Assert.True(flagB.IsIn(ImmutableHashSet.Create("A", "B"))); - Assert.False(flagC.IsIn(ImmutableHashSet.Create("C"))); - Assert.True(flagC.IsIn(ImmutableHashSet.Create("A", "C"))); - } - - [Fact] - public void IsAbstract() - { - var flags = new HashedFlagSet(); - var flagA = flags.Flag("A"); - var flagB = flags.Flag("B"); - var flags1And2 = flags.Flag(flagA, flagB); - var flagC = flags.Flag("C", flags1And2); - - Assert.False(flagA.IsAbstract); - Assert.False(flagB.IsAbstract); - Assert.True(flags1And2.IsAbstract); - Assert.False(flagC.IsAbstract); - } -} \ No newline at end of file diff --git a/dotnet-backup/Tests/Tests.csproj b/dotnet-backup/Tests/Tests.csproj deleted file mode 100644 index 443d84e..0000000 --- a/dotnet-backup/Tests/Tests.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - net9.0 - enable - enable - Multiflag.Tests - false - true - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/dotnet-backup/Tests/U16BitflagSetTests.cs b/dotnet-backup/Tests/U16BitflagSetTests.cs deleted file mode 100644 index 68f1054..0000000 --- a/dotnet-backup/Tests/U16BitflagSetTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Multiflag.Tests; - -public class U16BitflagSetTests -{ - [Fact] - public void ValueNotAPowerOfTwo() - { - var flags = new U16BitflagSet(); - Assert.Throws(() => flags.Flag(0)); - Assert.Throws(() => flags.Flag(11)); - } - - [Fact] - public void Add() - { - var flags = new U16BitflagSet(); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4); - var flags2And4 = flags.Flag(flag2, flag4); - - Assert.Equal(3, 1 + flag2); - Assert.Equal(5, 1 + flag4); - Assert.Equal(7, 1 + flags2And4); - } - - [Fact] - public void Remove() - { - var flags = new U16BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.Equal(2, 7 - flag1); - Assert.Equal(5, 7 - flag2); - Assert.Equal(3, 7 - flag4); - } - - [Fact] - public void IsIn() - { - var flags = new U16BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.True(flag1.IsIn(1)); - Assert.True(flag2.IsIn(3)); - Assert.False(flag4.IsIn(4)); - Assert.True(flag4.IsIn(5)); - } - - [Fact] - public void IsAbstract() - { - var flags = new U16BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flags1And2 = flags.Flag(flag1, flag2); - var flag4 = flags.Flag(4, flags1And2); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.True(flags1And2.IsAbstract); - Assert.False(flag4.IsAbstract); - } -} \ No newline at end of file diff --git a/dotnet-backup/Tests/U32BitflagSetTests.cs b/dotnet-backup/Tests/U32BitflagSetTests.cs deleted file mode 100644 index 7919fe0..0000000 --- a/dotnet-backup/Tests/U32BitflagSetTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Multiflag.Tests; - -public class U32BitflagSetTests -{ - [Fact] - public void ValueNotAPowerOfTwo() - { - var flags = new U32BitflagSet(); - Assert.Throws(() => flags.Flag(0)); - Assert.Throws(() => flags.Flag(11)); - } - - [Fact] - public void Add() - { - var flags = new U32BitflagSet(); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4); - var flags2And4 = flags.Flag(flag2, flag4); - - Assert.Equal(3u, 1 + flag2); - Assert.Equal(5u, 1 + flag4); - Assert.Equal(7u, 1 + flags2And4); - } - - [Fact] - public void Remove() - { - var flags = new U32BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.Equal(2u, 7 - flag1); - Assert.Equal(5u, 7 - flag2); - Assert.Equal(3u, 7 - flag4); - } - - [Fact] - public void IsIn() - { - var flags = new U32BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.True(flag1.IsIn(1)); - Assert.True(flag2.IsIn(3)); - Assert.False(flag4.IsIn(4)); - Assert.True(flag4.IsIn(5)); - } - - [Fact] - public void IsAbstract() - { - var flags = new U32BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flags1And2 = flags.Flag(flag1, flag2); - var flag4 = flags.Flag(4, flags1And2); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.True(flags1And2.IsAbstract); - Assert.False(flag4.IsAbstract); - } -} \ No newline at end of file diff --git a/dotnet-backup/Tests/U64BitflagSetTests.cs b/dotnet-backup/Tests/U64BitflagSetTests.cs deleted file mode 100644 index 71c52f7..0000000 --- a/dotnet-backup/Tests/U64BitflagSetTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Multiflag.Tests; - -public class U64BitflagSetTests -{ - [Fact] - public void ValueNotAPowerOfTwo() - { - var flags = new U64BitflagSet(); - Assert.Throws(() => flags.Flag(0)); - Assert.Throws(() => flags.Flag(11)); - } - - [Fact] - public void Add() - { - var flags = new U64BitflagSet(); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4); - var flags2And4 = flags.Flag(flag2, flag4); - - Assert.Equal(3u, 1 + flag2); - Assert.Equal(5u, 1 + flag4); - Assert.Equal(7u, 1 + flags2And4); - } - - [Fact] - public void Remove() - { - var flags = new U64BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.Equal(2u, 7 - flag1); - Assert.Equal(5u, 7 - flag2); - Assert.Equal(3u, 7 - flag4); - } - - [Fact] - public void IsIn() - { - var flags = new U64BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.True(flag1.IsIn(1)); - Assert.True(flag2.IsIn(3)); - Assert.False(flag4.IsIn(4)); - Assert.True(flag4.IsIn(5)); - } - - [Fact] - public void IsAbstract() - { - var flags = new U64BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flags1And2 = flags.Flag(flag1, flag2); - var flag4 = flags.Flag(4, flags1And2); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.True(flags1And2.IsAbstract); - Assert.False(flag4.IsAbstract); - } -} \ No newline at end of file diff --git a/dotnet-backup/Tests/U8BitflagSetTests.cs b/dotnet-backup/Tests/U8BitflagSetTests.cs deleted file mode 100644 index 97acf07..0000000 --- a/dotnet-backup/Tests/U8BitflagSetTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Multiflag.Tests; - -public class U8BitflagSetTests -{ - [Fact] - public void ValueNotAPowerOfTwo() - { - var flags = new U8BitflagSet(); - Assert.Throws(() => flags.Flag(0)); - Assert.Throws(() => flags.Flag(11)); - } - - [Fact] - public void Add() - { - var flags = new U8BitflagSet(); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4); - var flags2And4 = flags.Flag(flag2, flag4); - - Assert.Equal(3, 1 + flag2); - Assert.Equal(5, 1 + flag4); - Assert.Equal(7, 1 + flags2And4); - } - - [Fact] - public void Remove() - { - var flags = new U8BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.Equal(2, 7 - flag1); - Assert.Equal(5, 7 - flag2); - Assert.Equal(3, 7 - flag4); - } - - [Fact] - public void IsIn() - { - var flags = new U8BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.True(flag1.IsIn(1)); - Assert.True(flag2.IsIn(3)); - Assert.False(flag4.IsIn(4)); - Assert.True(flag4.IsIn(5)); - } - - [Fact] - public void IsAbstract() - { - var flags = new U8BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flags1And2 = flags.Flag(flag1, flag2); - var flag4 = flags.Flag(4, flags1And2); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.True(flags1And2.IsAbstract); - Assert.False(flag4.IsAbstract); - } -} \ No newline at end of file diff --git a/dotnet-backup/global.json b/dotnet-backup/global.json deleted file mode 100644 index a27a2b8..0000000 --- a/dotnet-backup/global.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "sdk": { - "version": "9.0.0", - "rollForward": "latestMajor", - "allowPrerelease": false - } -} \ No newline at end of file From 3fdeac56d09bcd7ab0499f07e0735df0d6cce056 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Thu, 1 May 2025 13:41:23 +0200 Subject: [PATCH 05/15] fix: restore badly merged files --- dotnet/.idea/.idea.Multiflag/.idea/.gitignore | 16 ++ dotnet/.idea/.idea.Multiflag/.idea/vcs.xml | 6 + dotnet/Multiflag.sln | 1 + .../BuiltInValueTypes/ByteFlagValue.cs | 18 -- .../BuiltInValueTypes/EnumFlagValue.cs | 54 ----- .../BuiltInValueTypes/SetFlagValue.cs | 36 --- .../BuiltInValueTypes/UIntFlagValue.cs | 18 -- .../BuiltInValueTypes/ULongFlagValue.cs | 18 -- .../BuiltInValueTypes/UShortFlagValue.cs | 18 -- dotnet/Multiflag/Flag16.cs | 22 -- dotnet/Multiflag/Flag32.cs | 22 -- dotnet/Multiflag/Flag64.cs | 16 -- dotnet/Multiflag/Flag8.cs | 16 -- dotnet/Multiflag/FlagEnum.cs | 21 -- dotnet/Multiflag/ForeignFlagException.cs | 16 ++ dotnet/Multiflag/IFlagValue.cs | 64 ----- .../Multiflag/InvalidBitflagValueException.cs | 15 ++ .../Multiflag/InvalidHashSetValueException.cs | 15 ++ dotnet/Multiflag/Multiflag.csproj | 59 +++-- dotnet/Multiflag/UndefinedValueException.cs | 16 ++ .../Multiflag/UnsupportedEnumTypeException.cs | 23 ++ dotnet/Tests/Base64CodecTests.cs | 224 ++++++++++++++++++ dotnet/Tests/DynamicBitflagSetTests.cs | 79 ++++++ dotnet/Tests/EnumBitflagSetTests.cs | 158 ++++++++++++ dotnet/Tests/Flag16Tests.cs | 182 -------------- dotnet/Tests/Flag32Tests.cs | 182 -------------- dotnet/Tests/Flag64Tests.cs | 182 -------------- dotnet/Tests/Flag8Tests.cs | 182 -------------- dotnet/Tests/FlagEnumTests.cs | 215 ----------------- dotnet/Tests/FlagSetTests.cs | 217 ++--------------- dotnet/Tests/FlagTests.cs | 141 +++++++++++ dotnet/Tests/Tests.csproj | 54 ++--- dotnet/Tests/U16BitflagSetTests.cs | 67 ++++++ dotnet/Tests/U32BitflagSetTests.cs | 67 ++++++ dotnet/Tests/U64BitflagSetTests.cs | 67 ++++++ dotnet/Tests/U8BitflagSetTests.cs | 67 ++++++ dotnet/global.json | 7 + 37 files changed, 1060 insertions(+), 1521 deletions(-) create mode 100644 dotnet/.idea/.idea.Multiflag/.idea/.gitignore create mode 100644 dotnet/.idea/.idea.Multiflag/.idea/vcs.xml delete mode 100644 dotnet/Multiflag/BuiltInValueTypes/ByteFlagValue.cs delete mode 100644 dotnet/Multiflag/BuiltInValueTypes/EnumFlagValue.cs delete mode 100644 dotnet/Multiflag/BuiltInValueTypes/SetFlagValue.cs delete mode 100644 dotnet/Multiflag/BuiltInValueTypes/UIntFlagValue.cs delete mode 100644 dotnet/Multiflag/BuiltInValueTypes/ULongFlagValue.cs delete mode 100644 dotnet/Multiflag/BuiltInValueTypes/UShortFlagValue.cs delete mode 100644 dotnet/Multiflag/Flag16.cs delete mode 100644 dotnet/Multiflag/Flag32.cs delete mode 100644 dotnet/Multiflag/Flag64.cs delete mode 100644 dotnet/Multiflag/Flag8.cs delete mode 100644 dotnet/Multiflag/FlagEnum.cs create mode 100644 dotnet/Multiflag/ForeignFlagException.cs delete mode 100644 dotnet/Multiflag/IFlagValue.cs create mode 100644 dotnet/Multiflag/InvalidBitflagValueException.cs create mode 100644 dotnet/Multiflag/InvalidHashSetValueException.cs create mode 100644 dotnet/Multiflag/UndefinedValueException.cs create mode 100644 dotnet/Multiflag/UnsupportedEnumTypeException.cs create mode 100644 dotnet/Tests/Base64CodecTests.cs create mode 100644 dotnet/Tests/DynamicBitflagSetTests.cs create mode 100644 dotnet/Tests/EnumBitflagSetTests.cs delete mode 100644 dotnet/Tests/Flag16Tests.cs delete mode 100644 dotnet/Tests/Flag32Tests.cs delete mode 100644 dotnet/Tests/Flag64Tests.cs delete mode 100644 dotnet/Tests/Flag8Tests.cs delete mode 100644 dotnet/Tests/FlagEnumTests.cs create mode 100644 dotnet/Tests/FlagTests.cs create mode 100644 dotnet/Tests/U16BitflagSetTests.cs create mode 100644 dotnet/Tests/U32BitflagSetTests.cs create mode 100644 dotnet/Tests/U64BitflagSetTests.cs create mode 100644 dotnet/Tests/U8BitflagSetTests.cs create mode 100644 dotnet/global.json diff --git a/dotnet/.idea/.idea.Multiflag/.idea/.gitignore b/dotnet/.idea/.idea.Multiflag/.idea/.gitignore new file mode 100644 index 0000000..7df85a9 --- /dev/null +++ b/dotnet/.idea/.idea.Multiflag/.idea/.gitignore @@ -0,0 +1,16 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/projectSettingsUpdater.xml +/contentModel.xml +/.idea.Multiflag.iml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +.name +discord.xml +indexLayout.xml \ No newline at end of file diff --git a/dotnet/.idea/.idea.Multiflag/.idea/vcs.xml b/dotnet/.idea/.idea.Multiflag/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/dotnet/.idea/.idea.Multiflag/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/dotnet/Multiflag.sln b/dotnet/Multiflag.sln index 31bc844..a78a811 100644 --- a/dotnet/Multiflag.sln +++ b/dotnet/Multiflag.sln @@ -10,6 +10,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Éléments de solution", "Éléments de solution", "{A2326173-037B-4F50-B202-D385541624BE}" ProjectSection(SolutionItems) = preProject README.md = README.md + ..\.github\workflows\tests.yml = ..\.github\workflows\tests.yml EndProjectSection EndProject Global diff --git a/dotnet/Multiflag/BuiltInValueTypes/ByteFlagValue.cs b/dotnet/Multiflag/BuiltInValueTypes/ByteFlagValue.cs deleted file mode 100644 index 5ba99ce..0000000 --- a/dotnet/Multiflag/BuiltInValueTypes/ByteFlagValue.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Multiflag.BuiltInValueTypes -{ - /// - /// Built-in implementation of for . - /// - public class ByteFlagValue : IFlagValue - { - public byte Substraction(byte first, byte second) => (byte)(first & ~second); - - public bool Includes(byte first, byte second) => (first & second) == second; - - public byte Union(byte first, byte second) => (byte)(first | second); - - public byte Nothing() => 0; - - public bool Equivalent(byte first, byte second) => first == second; - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/BuiltInValueTypes/EnumFlagValue.cs b/dotnet/Multiflag/BuiltInValueTypes/EnumFlagValue.cs deleted file mode 100644 index e4ba077..0000000 --- a/dotnet/Multiflag/BuiltInValueTypes/EnumFlagValue.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace Multiflag.BuiltInValueTypes -{ - public class InvalidEnumTypeException : Exception - { - public InvalidEnumTypeException(string message) : base(message) { } - } - - /// - /// Built-in implementation of for s backed by . - /// - public class EnumFlagValue : IFlagValue where TEnum : Enum - { - public EnumFlagValue() - { - if (!typeof(int).IsAssignableFrom(Enum.GetUnderlyingType(typeof(TEnum)))) - throw new InvalidEnumTypeException("FlagEnums are only compatible with int-backed enums."); - } - - private int EnumToInt(TEnum value) - { - return (int)(object)value; - } - - private TEnum IntToEnum(int value) - { - return (TEnum)(object)value; - } - - public TEnum Substraction(TEnum first, TEnum second) - { - int intFirst = EnumToInt(first); - int intSecond = EnumToInt(second); - return IntToEnum(intFirst & ~intSecond); - } - - public bool Includes(TEnum first, TEnum second) - { - int intFirst = EnumToInt(first); - int intSecond = EnumToInt(second); - return (intFirst & intSecond) == intSecond; - } - - public TEnum Union(TEnum first, TEnum second) - { - int intFirst = EnumToInt(first); - int intSecond = EnumToInt(second); - return IntToEnum(intFirst | intSecond); - } - - public TEnum Nothing() => IntToEnum(0); - - public bool Equivalent(TEnum first, TEnum second) => first.Equals(second); - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/BuiltInValueTypes/SetFlagValue.cs b/dotnet/Multiflag/BuiltInValueTypes/SetFlagValue.cs deleted file mode 100644 index 5e20dd5..0000000 --- a/dotnet/Multiflag/BuiltInValueTypes/SetFlagValue.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Multiflag.BuiltInValueTypes -{ - /// - /// Built-in implementation of for . - /// - /// - /// The set is modified in-place. If you do not want this behavior, make a - /// copy of your set before using flag operation on it. - /// - public class SetFlagValue : IFlagValue> - { - public HashSet Substraction(HashSet first, HashSet second) - { - first.ExceptWith(second); - return first; - } - - public bool Includes(HashSet first, HashSet second) - { - return first.IsSupersetOf(second); - } - - public HashSet Nothing() - { - return new HashSet(); - } - - public HashSet Union(HashSet first, HashSet second) - { - first.UnionWith(second); - return first; - } - - public bool Equivalent(HashSet first, HashSet second) => first.SetEquals(second); - } -} diff --git a/dotnet/Multiflag/BuiltInValueTypes/UIntFlagValue.cs b/dotnet/Multiflag/BuiltInValueTypes/UIntFlagValue.cs deleted file mode 100644 index b5ca446..0000000 --- a/dotnet/Multiflag/BuiltInValueTypes/UIntFlagValue.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Multiflag.BuiltInValueTypes -{ - /// - /// Built-in implementation of for . - /// - public class UIntFlagValue : IFlagValue - { - public uint Substraction(uint first, uint second) => first & ~second; - - public bool Includes(uint first, uint second) => (first & second) == second; - - public uint Union(uint first, uint second) => first | second; - - public uint Nothing() => 0; - - public bool Equivalent(uint first, uint second) => first == second; - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/BuiltInValueTypes/ULongFlagValue.cs b/dotnet/Multiflag/BuiltInValueTypes/ULongFlagValue.cs deleted file mode 100644 index cc610ee..0000000 --- a/dotnet/Multiflag/BuiltInValueTypes/ULongFlagValue.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Multiflag.BuiltInValueTypes -{ - /// - /// Built-in implementation of for . - /// - public class ULongFlagValue : IFlagValue - { - public ulong Substraction(ulong first, ulong second) => first & ~second; - - public bool Includes(ulong first, ulong second) => (first & second) == second; - - public ulong Union(ulong first, ulong second) => first | second; - - public ulong Nothing() => 0; - - public bool Equivalent(ulong first, ulong second) => first == second; - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/BuiltInValueTypes/UShortFlagValue.cs b/dotnet/Multiflag/BuiltInValueTypes/UShortFlagValue.cs deleted file mode 100644 index ea1ae8f..0000000 --- a/dotnet/Multiflag/BuiltInValueTypes/UShortFlagValue.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Multiflag.BuiltInValueTypes -{ - /// - /// Built-in implementation of for . - /// - public class UShortFlagValue : IFlagValue - { - public ushort Substraction(ushort first, ushort second) => (ushort)(first & ~second); - - public bool Includes(ushort first, ushort second) => (first & second) == second; - - public ushort Union(ushort first, ushort second) => (ushort)(first | second); - - public ushort Nothing() => 0; - - public bool Equivalent(ushort first, ushort second) => first == second; - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/Flag16.cs b/dotnet/Multiflag/Flag16.cs deleted file mode 100644 index 0794d44..0000000 --- a/dotnet/Multiflag/Flag16.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Multiflag.BuiltInValueTypes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Multiflag -{ - /// - /// A flag based on a 16-bit usingned integer (thus allowing 16 different flags). - /// - public class Flag16 : Flag - { - /// - public Flag16(ushort value, params Flag16[] parents) : base(value, parents) { } - - /// - public Flag16(params Flag16[] parents) : base(parents) { } - } - -} diff --git a/dotnet/Multiflag/Flag32.cs b/dotnet/Multiflag/Flag32.cs deleted file mode 100644 index dfca890..0000000 --- a/dotnet/Multiflag/Flag32.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Multiflag.BuiltInValueTypes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Multiflag -{ - /// - /// A flag based on a 32-bit usingned integer (thus allowing 32 different flags). - /// - public class Flag32 : Flag - { - /// - public Flag32(uint value, params Flag32[] parents) : base(value, parents) { } - - /// - public Flag32(params Flag32[] parents) : base(parents) { } - } - -} diff --git a/dotnet/Multiflag/Flag64.cs b/dotnet/Multiflag/Flag64.cs deleted file mode 100644 index 529f0fc..0000000 --- a/dotnet/Multiflag/Flag64.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Multiflag.BuiltInValueTypes; - -namespace Multiflag -{ - /// - /// A flag based on a 64-bit usingned integer (thus allowing 64 different flags). - /// - public class Flag64 : Flag - { - /// - public Flag64(ulong value, params Flag64[] parents) : base(value, parents) { } - - /// - public Flag64(params Flag64[] parents) : base(parents) { } - } -} diff --git a/dotnet/Multiflag/Flag8.cs b/dotnet/Multiflag/Flag8.cs deleted file mode 100644 index 838b910..0000000 --- a/dotnet/Multiflag/Flag8.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Multiflag.BuiltInValueTypes; - -namespace Multiflag -{ - /// - /// A flag based on a 8-bit usingned integer (thus allowing 8 different flags). - /// - public class Flag8 : Flag - { - /// - public Flag8(byte value, params Flag8[] parents) : base(value, parents) { } - - /// - public Flag8(params Flag8[] parents) : base(parents) { } - } -} diff --git a/dotnet/Multiflag/FlagEnum.cs b/dotnet/Multiflag/FlagEnum.cs deleted file mode 100644 index 1e89ecf..0000000 --- a/dotnet/Multiflag/FlagEnum.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Multiflag.BuiltInValueTypes; - -namespace Multiflag -{ - /// - /// A flag based on an enum.
- ///
- /// - /// It only works with enums backed by an int, but you can implement - /// to support other enums. - /// - public class FlagEnum : Flag> - where TEnum : Enum - { - /// - public FlagEnum(TEnum value, params FlagEnum[] parents) : base(value, parents) { } - - /// - public FlagEnum(params FlagEnum[] parents) : base(parents) { } - } -} diff --git a/dotnet/Multiflag/ForeignFlagException.cs b/dotnet/Multiflag/ForeignFlagException.cs new file mode 100644 index 0000000..934986d --- /dev/null +++ b/dotnet/Multiflag/ForeignFlagException.cs @@ -0,0 +1,16 @@ +using System; + +namespace Multiflag +{ + /// + /// Exception thrown when a flag is associated with another one + /// that was created from a different . + /// + public class ForeignFlagException : ArgumentException + { + internal ForeignFlagException() : base( + "Cannot create a dependency between two flags created in different sets.") + { + } + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/IFlagValue.cs b/dotnet/Multiflag/IFlagValue.cs deleted file mode 100644 index 4ae9e2e..0000000 --- a/dotnet/Multiflag/IFlagValue.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace Multiflag -{ - /// - /// An adapter to use a regular type as a flag. Built-in implementations - /// exist for , , , - /// , s and . - ///
- /// For other integers and custom enumerations, it can easily be implented - /// as such: - /// - /// Nothing() => 0 - /// Union(a, b) => a | b - /// Substraction => a & ~b - /// Includes => (a & b) == b - /// Equivalent => a == b - /// - ///
- /// The type to be used as a flag. - public interface IFlagValue - { - /// - /// Creates an empty set of flags that can only include itself. - /// - T Nothing(); - - /// - /// Returns the union of two sets of flags. - /// - /// The first set of flags. - /// The second set of flags. - /// - /// If is a reference type, the operation may - /// be done in-place on the first set.
That is, the first parameter is - /// should not be reused after being passed to that function. - ///
- T Union(T first, T second); - - /// - /// Returns the substraction af one set of flags by another. - /// - /// The first set of flags. - /// The second set of flags that is substracted to the first. - /// - /// If is a reference type, the operation may - /// be done in-place on the first set.
That is, the first parameter is - /// should not be reused after being passed to that function. - ///
- T Substraction(T first, T second); - - /// - /// Checks wether the first set of flags is a superset of the second. - /// - /// The first set of flags. - /// The second set of flags. - bool Includes(T first, T second); - - /// - /// Checks wether two sets of flags contains exactly the same same flags. - /// - /// The first set of flags. - /// The second set of flags. - bool Equivalent(T first, T second); - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/InvalidBitflagValueException.cs b/dotnet/Multiflag/InvalidBitflagValueException.cs new file mode 100644 index 0000000..0e61109 --- /dev/null +++ b/dotnet/Multiflag/InvalidBitflagValueException.cs @@ -0,0 +1,15 @@ +using System; + +namespace Multiflag +{ + /// + /// Exception thrown by FlagSets that represents the flags using a binary format when + /// a flag value isn't a power of two. + /// + public class InvalidBitflagValueException : ArgumentException + { + internal InvalidBitflagValueException() : base("Flag values for bit flags must be powers of two.") + { + } + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/InvalidHashSetValueException.cs b/dotnet/Multiflag/InvalidHashSetValueException.cs new file mode 100644 index 0000000..b85654a --- /dev/null +++ b/dotnet/Multiflag/InvalidHashSetValueException.cs @@ -0,0 +1,15 @@ +using System; + +namespace Multiflag +{ + /// + /// Exception thrown by FlagSets that represents the flags using hash sets when a flag value + /// does not contain exactly one element. + /// + public class InvalidHashSetValueException : ArgumentException + { + internal InvalidHashSetValueException() : base("Flag values for hash sets must contain exactly one value.") + { + } + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/Multiflag.csproj b/dotnet/Multiflag/Multiflag.csproj index dd6da54..9570218 100644 --- a/dotnet/Multiflag/Multiflag.csproj +++ b/dotnet/Multiflag/Multiflag.csproj @@ -1,32 +1,39 @@  - - net7.0;net6.0 - enable - enable - True - Multiflag - 1.0.0 - Louis DEVIE - - True - MIT - flag:flagging;bitflag;enum;states;permissions;features; - https://github.com/louisdevie/multiflag - README.md - A library to help you manipulate (bit)flags easily and enables you to implement inheritance between flags. - https://louisdevie.github.io/multiflag - + + netstandard2.1;net8.0;net9.0 + enable + True + True + Multiflag + 2.0.0 + Louis DEVIE + True + MIT + flag:flagging;bitflag;enum;states;permissions;features; + https://github.com/louisdevie/multiflag + README.md + A library to help you manipulate (bit)flags easily and enables you to implement inheritance between flags. + https://louisdevie.github.io/multiflag + - - - + + + - - - True - \ - - + + + + + + + True + \ + + + + + + diff --git a/dotnet/Multiflag/UndefinedValueException.cs b/dotnet/Multiflag/UndefinedValueException.cs new file mode 100644 index 0000000..88b46dc --- /dev/null +++ b/dotnet/Multiflag/UndefinedValueException.cs @@ -0,0 +1,16 @@ +using System; + +namespace Multiflag +{ + /// + /// Exception thrown when a flag is created from an with a value + /// that is not explicitly declared in the enum. + /// + public class UndefinedEnumValueException : ArgumentException + { + internal UndefinedEnumValueException(object badValue) + : base($"The value {badValue} cannot be used as a flag because it isn't a member of the enum.") + { + } + } +} \ No newline at end of file diff --git a/dotnet/Multiflag/UnsupportedEnumTypeException.cs b/dotnet/Multiflag/UnsupportedEnumTypeException.cs new file mode 100644 index 0000000..a2cae44 --- /dev/null +++ b/dotnet/Multiflag/UnsupportedEnumTypeException.cs @@ -0,0 +1,23 @@ +using System; + +namespace Multiflag +{ + /// + /// Exception thrown when an is intanciated with an enumeration type + /// that is not backed by one of , , or + /// . + /// + public class UnsupportedEnumTypeException : ArgumentException + { + internal UnsupportedEnumTypeException(Type underlyingType) + : base( + $"Enums with an underlying type of {underlyingType} are not supported. Use one of byte, ushort, uint or ulong instead.") + { + } + + internal UnsupportedEnumTypeException(Type underlyingType, string suggestedType) + : base($"Enums with an underlying type of {underlyingType} are not supported. Use {suggestedType} instead.") + { + } + } +} \ No newline at end of file diff --git a/dotnet/Tests/Base64CodecTests.cs b/dotnet/Tests/Base64CodecTests.cs new file mode 100644 index 0000000..0c408bd --- /dev/null +++ b/dotnet/Tests/Base64CodecTests.cs @@ -0,0 +1,224 @@ +using Multiflag.Base64Format; + +namespace Multiflag.Tests; + +public class Base64CodecTests +{ + [Fact] + public void EncodeByte() + { + Assert.Equal('A', Base64Codec.EncodeByte(0)); + Assert.Equal('B', Base64Codec.EncodeByte(1)); + Assert.Equal('C', Base64Codec.EncodeByte(2)); + Assert.Equal('D', Base64Codec.EncodeByte(3)); + Assert.Equal('E', Base64Codec.EncodeByte(4)); + Assert.Equal('F', Base64Codec.EncodeByte(5)); + Assert.Equal('G', Base64Codec.EncodeByte(6)); + Assert.Equal('H', Base64Codec.EncodeByte(7)); + Assert.Equal('I', Base64Codec.EncodeByte(8)); + Assert.Equal('J', Base64Codec.EncodeByte(9)); + Assert.Equal('K', Base64Codec.EncodeByte(10)); + Assert.Equal('L', Base64Codec.EncodeByte(11)); + Assert.Equal('M', Base64Codec.EncodeByte(12)); + Assert.Equal('N', Base64Codec.EncodeByte(13)); + Assert.Equal('O', Base64Codec.EncodeByte(14)); + Assert.Equal('P', Base64Codec.EncodeByte(15)); + Assert.Equal('Q', Base64Codec.EncodeByte(16)); + Assert.Equal('R', Base64Codec.EncodeByte(17)); + Assert.Equal('S', Base64Codec.EncodeByte(18)); + Assert.Equal('T', Base64Codec.EncodeByte(19)); + Assert.Equal('U', Base64Codec.EncodeByte(20)); + Assert.Equal('V', Base64Codec.EncodeByte(21)); + Assert.Equal('W', Base64Codec.EncodeByte(22)); + Assert.Equal('X', Base64Codec.EncodeByte(23)); + Assert.Equal('Y', Base64Codec.EncodeByte(24)); + Assert.Equal('Z', Base64Codec.EncodeByte(25)); + Assert.Equal('a', Base64Codec.EncodeByte(26)); + Assert.Equal('b', Base64Codec.EncodeByte(27)); + Assert.Equal('c', Base64Codec.EncodeByte(28)); + Assert.Equal('d', Base64Codec.EncodeByte(29)); + Assert.Equal('e', Base64Codec.EncodeByte(30)); + Assert.Equal('f', Base64Codec.EncodeByte(31)); + Assert.Equal('g', Base64Codec.EncodeByte(32)); + Assert.Equal('h', Base64Codec.EncodeByte(33)); + Assert.Equal('i', Base64Codec.EncodeByte(34)); + Assert.Equal('j', Base64Codec.EncodeByte(35)); + Assert.Equal('k', Base64Codec.EncodeByte(36)); + Assert.Equal('l', Base64Codec.EncodeByte(37)); + Assert.Equal('m', Base64Codec.EncodeByte(38)); + Assert.Equal('n', Base64Codec.EncodeByte(39)); + Assert.Equal('o', Base64Codec.EncodeByte(40)); + Assert.Equal('p', Base64Codec.EncodeByte(41)); + Assert.Equal('q', Base64Codec.EncodeByte(42)); + Assert.Equal('r', Base64Codec.EncodeByte(43)); + Assert.Equal('s', Base64Codec.EncodeByte(44)); + Assert.Equal('t', Base64Codec.EncodeByte(45)); + Assert.Equal('u', Base64Codec.EncodeByte(46)); + Assert.Equal('v', Base64Codec.EncodeByte(47)); + Assert.Equal('w', Base64Codec.EncodeByte(48)); + Assert.Equal('x', Base64Codec.EncodeByte(49)); + Assert.Equal('y', Base64Codec.EncodeByte(50)); + Assert.Equal('z', Base64Codec.EncodeByte(51)); + Assert.Equal('0', Base64Codec.EncodeByte(52)); + Assert.Equal('1', Base64Codec.EncodeByte(53)); + Assert.Equal('2', Base64Codec.EncodeByte(54)); + Assert.Equal('3', Base64Codec.EncodeByte(55)); + Assert.Equal('4', Base64Codec.EncodeByte(56)); + Assert.Equal('5', Base64Codec.EncodeByte(57)); + Assert.Equal('6', Base64Codec.EncodeByte(58)); + Assert.Equal('7', Base64Codec.EncodeByte(59)); + Assert.Equal('8', Base64Codec.EncodeByte(60)); + Assert.Equal('9', Base64Codec.EncodeByte(61)); + Assert.Equal('-', Base64Codec.EncodeByte(62)); + Assert.Equal('_', Base64Codec.EncodeByte(63)); + } + + [Fact] + public void DecodeByte() + { + Assert.Equal(0, Base64Codec.DecodeByte('A')); + Assert.Equal(1, Base64Codec.DecodeByte('B')); + Assert.Equal(2, Base64Codec.DecodeByte('C')); + Assert.Equal(3, Base64Codec.DecodeByte('D')); + Assert.Equal(4, Base64Codec.DecodeByte('E')); + Assert.Equal(5, Base64Codec.DecodeByte('F')); + Assert.Equal(6, Base64Codec.DecodeByte('G')); + Assert.Equal(7, Base64Codec.DecodeByte('H')); + Assert.Equal(8, Base64Codec.DecodeByte('I')); + Assert.Equal(9, Base64Codec.DecodeByte('J')); + Assert.Equal(10, Base64Codec.DecodeByte('K')); + Assert.Equal(11, Base64Codec.DecodeByte('L')); + Assert.Equal(12, Base64Codec.DecodeByte('M')); + Assert.Equal(13, Base64Codec.DecodeByte('N')); + Assert.Equal(14, Base64Codec.DecodeByte('O')); + Assert.Equal(15, Base64Codec.DecodeByte('P')); + Assert.Equal(16, Base64Codec.DecodeByte('Q')); + Assert.Equal(17, Base64Codec.DecodeByte('R')); + Assert.Equal(18, Base64Codec.DecodeByte('S')); + Assert.Equal(19, Base64Codec.DecodeByte('T')); + Assert.Equal(20, Base64Codec.DecodeByte('U')); + Assert.Equal(21, Base64Codec.DecodeByte('V')); + Assert.Equal(22, Base64Codec.DecodeByte('W')); + Assert.Equal(23, Base64Codec.DecodeByte('X')); + Assert.Equal(24, Base64Codec.DecodeByte('Y')); + Assert.Equal(25, Base64Codec.DecodeByte('Z')); + Assert.Equal(26, Base64Codec.DecodeByte('a')); + Assert.Equal(27, Base64Codec.DecodeByte('b')); + Assert.Equal(28, Base64Codec.DecodeByte('c')); + Assert.Equal(29, Base64Codec.DecodeByte('d')); + Assert.Equal(30, Base64Codec.DecodeByte('e')); + Assert.Equal(31, Base64Codec.DecodeByte('f')); + Assert.Equal(32, Base64Codec.DecodeByte('g')); + Assert.Equal(33, Base64Codec.DecodeByte('h')); + Assert.Equal(34, Base64Codec.DecodeByte('i')); + Assert.Equal(35, Base64Codec.DecodeByte('j')); + Assert.Equal(36, Base64Codec.DecodeByte('k')); + Assert.Equal(37, Base64Codec.DecodeByte('l')); + Assert.Equal(38, Base64Codec.DecodeByte('m')); + Assert.Equal(39, Base64Codec.DecodeByte('n')); + Assert.Equal(40, Base64Codec.DecodeByte('o')); + Assert.Equal(41, Base64Codec.DecodeByte('p')); + Assert.Equal(42, Base64Codec.DecodeByte('q')); + Assert.Equal(43, Base64Codec.DecodeByte('r')); + Assert.Equal(44, Base64Codec.DecodeByte('s')); + Assert.Equal(45, Base64Codec.DecodeByte('t')); + Assert.Equal(46, Base64Codec.DecodeByte('u')); + Assert.Equal(47, Base64Codec.DecodeByte('v')); + Assert.Equal(48, Base64Codec.DecodeByte('w')); + Assert.Equal(49, Base64Codec.DecodeByte('x')); + Assert.Equal(50, Base64Codec.DecodeByte('y')); + Assert.Equal(51, Base64Codec.DecodeByte('z')); + Assert.Equal(52, Base64Codec.DecodeByte('0')); + Assert.Equal(53, Base64Codec.DecodeByte('1')); + Assert.Equal(54, Base64Codec.DecodeByte('2')); + Assert.Equal(55, Base64Codec.DecodeByte('3')); + Assert.Equal(56, Base64Codec.DecodeByte('4')); + Assert.Equal(57, Base64Codec.DecodeByte('5')); + Assert.Equal(58, Base64Codec.DecodeByte('6')); + Assert.Equal(59, Base64Codec.DecodeByte('7')); + Assert.Equal(60, Base64Codec.DecodeByte('8')); + Assert.Equal(61, Base64Codec.DecodeByte('9')); + Assert.Equal(62, Base64Codec.DecodeByte('-')); + Assert.Equal(63, Base64Codec.DecodeByte('_')); + } + + [Fact] + public void EncodeSingleFlag() + { + Assert.Equal("B", Base64Codec.EncodeSingleFlag(1)); + Assert.Equal("C", Base64Codec.EncodeSingleFlag(2)); + Assert.Equal("E", Base64Codec.EncodeSingleFlag(3)); + Assert.Equal("I", Base64Codec.EncodeSingleFlag(4)); + Assert.Equal("Q", Base64Codec.EncodeSingleFlag(5)); + Assert.Equal("g", Base64Codec.EncodeSingleFlag(6)); + Assert.Equal("AB", Base64Codec.EncodeSingleFlag(7)); + Assert.Equal("AI", Base64Codec.EncodeSingleFlag(10)); + Assert.Equal("AAAAAAAAAAAAAAAAI", Base64Codec.EncodeSingleFlag(100)); + } + + [Fact] + public void DecodesToZero() + { + Assert.True(Base64Codec.DecodesToZero("")); + Assert.True(Base64Codec.DecodesToZero("A")); + Assert.False(Base64Codec.DecodesToZero("X")); + Assert.False(Base64Codec.DecodesToZero("AX")); + Assert.True(Base64Codec.DecodesToZero("AA")); + Assert.False(Base64Codec.DecodesToZero("XA")); + } + + [Fact] + public void DecodesToSingleFlag() + { + Assert.False(Base64Codec.DecodesToSingleFlag("")); + Assert.False(Base64Codec.DecodesToSingleFlag("A")); + Assert.True(Base64Codec.DecodesToSingleFlag("B")); + Assert.True(Base64Codec.DecodesToSingleFlag("C")); + Assert.False(Base64Codec.DecodesToSingleFlag("D")); + Assert.True(Base64Codec.DecodesToSingleFlag("E")); + Assert.True(Base64Codec.DecodesToSingleFlag("I")); + Assert.True(Base64Codec.DecodesToSingleFlag("IAA")); + Assert.True(Base64Codec.DecodesToSingleFlag("AAI")); + Assert.False(Base64Codec.DecodesToSingleFlag("IAI")); + } + + [Fact] + public void BitwiseOr() + { + Assert.Equal("A", Base64Codec.BitwiseOr("", "")); + Assert.Equal("A", Base64Codec.BitwiseOr("A", "")); + Assert.Equal("B", Base64Codec.BitwiseOr("B", "")); + Assert.Equal("X", Base64Codec.BitwiseOr("X", "")); + Assert.Equal("X", Base64Codec.BitwiseOr("", "X")); + Assert.Equal("V", Base64Codec.BitwiseOr("R", "F")); + Assert.Equal("VD0", Base64Codec.BitwiseOr("RD0", "F")); + Assert.Equal("VD0", Base64Codec.BitwiseOr("RD0", "FAA")); + } + + [Fact] + public void BitwiseAndNot() + { + Assert.Equal("A", Base64Codec.BitwiseAndNot("", "")); + Assert.Equal("A", Base64Codec.BitwiseAndNot("A", "")); + Assert.Equal("B", Base64Codec.BitwiseAndNot("B", "")); + Assert.Equal("X", Base64Codec.BitwiseAndNot("X", "")); + Assert.Equal("A", Base64Codec.BitwiseAndNot("", "X")); + Assert.Equal("Q", Base64Codec.BitwiseAndNot("R", "F")); + Assert.Equal("QD0", Base64Codec.BitwiseAndNot("RD0", "F")); + Assert.Equal("QD0", Base64Codec.BitwiseAndNot("RD0", "FAA")); + Assert.Equal("E", Base64Codec.BitwiseAndNot("F", "RD0")); + } + + [Fact] + public void BitwiseAndEquals() + { + Assert.True(Base64Codec.BitwiseAndEquals("", "")); + Assert.True(Base64Codec.BitwiseAndEquals("A", "")); + Assert.True(Base64Codec.BitwiseAndEquals("", "A")); + Assert.True(Base64Codec.BitwiseAndEquals("X", "")); + Assert.False(Base64Codec.BitwiseAndEquals("", "X")); + Assert.False(Base64Codec.BitwiseAndEquals("R", "F")); + Assert.True(Base64Codec.BitwiseAndEquals("RD0", "AA0")); + Assert.True(Base64Codec.BitwiseAndEquals("RD0", "RAA")); + } +} \ No newline at end of file diff --git a/dotnet/Tests/DynamicBitflagSetTests.cs b/dotnet/Tests/DynamicBitflagSetTests.cs new file mode 100644 index 0000000..c6fef35 --- /dev/null +++ b/dotnet/Tests/DynamicBitflagSetTests.cs @@ -0,0 +1,79 @@ +using System.Numerics; + +namespace Multiflag.Tests; + +public class DynamicBitflagSetTests +{ + private static readonly BigInteger BigPowerOfTwo = new BigInteger(1) << 100; + + [Fact] + public void ValueNotAPowerOfTwo() + { + var flags = new DynamicBitflagSet(); + Assert.Throws(() => flags.Flag(0)); + Assert.Throws(() => flags.Flag(11)); + } + + [Fact] + public void Add() + { + var flags = new DynamicBitflagSet(); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4); + var flags2And4 = flags.Flag(flag2, flag4); + var flag100 = flags.Flag(BigPowerOfTwo); + + Assert.Equal(3u, 1 + flag2); + Assert.Equal(5u, 1 + flag4); + Assert.Equal(7u, 1 + flags2And4); + Assert.Equal(BigPowerOfTwo + 1, 1 + flag100); + Assert.Equal(BigPowerOfTwo + 2, BigPowerOfTwo + flag2); + } + + [Fact] + public void Remove() + { + var flags = new DynamicBitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + var flag100 = flags.Flag(BigPowerOfTwo); + + Assert.Equal(2u, 7 - flag1); + Assert.Equal(5u, 7 - flag2); + Assert.Equal(3u, 7 - flag4); + Assert.Equal(2, BigPowerOfTwo + 2 - flag100); + Assert.Equal(2, 2 - flag100); + Assert.Equal(BigPowerOfTwo - 6, BigPowerOfTwo - 1 - flag1); + } + + [Fact] + public void IsIn() + { + var flags = new DynamicBitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + + Assert.True(flag1.IsIn(1)); + Assert.True(flag2.IsIn(3)); + Assert.False(flag4.IsIn(4)); + Assert.True(flag4.IsIn(5)); + Assert.False(flag4.IsIn(BigPowerOfTwo + 1)); + } + + [Fact] + public void IsAbstract() + { + var flags = new DynamicBitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flags1And2 = flags.Flag(flag1, flag2); + var flag4 = flags.Flag(4, flags1And2); + + Assert.False(flag1.IsAbstract); + Assert.False(flag2.IsAbstract); + Assert.True(flags1And2.IsAbstract); + Assert.False(flag4.IsAbstract); + } +} \ No newline at end of file diff --git a/dotnet/Tests/EnumBitflagSetTests.cs b/dotnet/Tests/EnumBitflagSetTests.cs new file mode 100644 index 0000000..cacccf5 --- /dev/null +++ b/dotnet/Tests/EnumBitflagSetTests.cs @@ -0,0 +1,158 @@ +namespace Multiflag.Tests; + +public class EnumBitflagSetTests +{ + [Fact] + public void SignedEnumsAreUnsupported() + { + Assert.Throws(() => new EnumBitflagSet()); + Assert.Throws(() => new EnumBitflagSet()); + Assert.Throws(() => new EnumBitflagSet()); + Assert.Throws(() => new EnumBitflagSet()); + } + + [Fact] + public void ValueNotAPowerOfTwo() + { + var flags = new EnumBitflagSet(); + Assert.Throws(() => flags.Flag(0)); + Assert.Throws(() => flags.Flag((U32Enum)11)); + } + + [Fact] + public void ValueNotDefined() + { + var flags = new EnumBitflagSet(); + Assert.Throws(() => flags.Flag((U32Enum)8)); + } + + [Fact] + public void Add() + { + var flags = new EnumBitflagSet(); + var flagB = flags.Flag(U32Enum.B); + var flagC = flags.Flag(U32Enum.C); + var flags2And4 = flags.Flag(flagB, flagC); + + Assert.Equal((U32Enum)3, U32Enum.A + flagB); + Assert.Equal((U32Enum)5, U32Enum.A + flagC); + Assert.Equal((U32Enum)7, U32Enum.A + flags2And4); + } + + [Fact] + public void Add8Bit() + { + var flags = new EnumBitflagSet(); + var flagB = flags.Flag(U8Enum.B); + var flagC = flags.Flag(U8Enum.C); + var flags2And4 = flags.Flag(flagB, flagC); + + Assert.Equal((U8Enum)3, U8Enum.A + flagB); + Assert.Equal((U8Enum)5, U8Enum.A + flagC); + Assert.Equal((U8Enum)7, U8Enum.A + flags2And4); + } + + [Fact] + public void Add16Bit() + { + var flags = new EnumBitflagSet(); + var flagB = flags.Flag(U16Enum.B); + var flagC = flags.Flag(U16Enum.C); + var flags2And4 = flags.Flag(flagB, flagC); + + Assert.Equal((U16Enum)3, U16Enum.A + flagB); + Assert.Equal((U16Enum)5, U16Enum.A + flagC); + Assert.Equal((U16Enum)7, U16Enum.A + flags2And4); + } + + [Fact] + public void Add64Bit() + { + var flags = new EnumBitflagSet(); + var flagB = flags.Flag(U64Enum.B); + var flagC = flags.Flag(U64Enum.C); + var flags2And4 = flags.Flag(flagB, flagC); + + Assert.Equal((U64Enum)3, U64Enum.A + flagB); + Assert.Equal((U64Enum)5, U64Enum.A + flagC); + Assert.Equal((U64Enum)7, U64Enum.A + flags2And4); + } + + [Fact] + public void Remove() + { + var flags = new EnumBitflagSet(); + var flagA = flags.Flag(U32Enum.A); + var flagB = flags.Flag(U32Enum.B); + var flagC = flags.Flag(U32Enum.C, flagA); + + Assert.Equal(U32Enum.B, (U32Enum)7 - flagA); + Assert.Equal((U32Enum)5, (U32Enum)7 - flagB); + Assert.Equal((U32Enum)3, (U32Enum)7 - flagC); + } + + [Fact] + public void IsIn() + { + var flags = new EnumBitflagSet(); + var flagA = flags.Flag(U32Enum.A); + var flagB = flags.Flag(U32Enum.B); + var flagC = flags.Flag(U32Enum.C, flagA); + + Assert.True(flagA.IsIn(U32Enum.A)); + Assert.True(flagB.IsIn((U32Enum)3)); + Assert.False(flagC.IsIn(U32Enum.B)); + Assert.True(flagC.IsIn((U32Enum)5)); + } + + [Fact] + public void IsAbstract() + { + var flags = new EnumBitflagSet(); + var flagA = flags.Flag(U32Enum.A); + var flagB = flags.Flag(U32Enum.B); + var flags1And2 = flags.Flag(flagA, flagB); + var flagC = flags.Flag(U32Enum.C, flags1And2); + + Assert.False(flagA.IsAbstract); + Assert.False(flagB.IsAbstract); + Assert.True(flags1And2.IsAbstract); + Assert.False(flagC.IsAbstract); + } + + private enum S8Enum : sbyte; + + private enum U8Enum : byte + { + A = 1, + B = 2, + C = 4 + } + + private enum S16Enum : short; + + private enum U16Enum : ushort + { + A = 1, + B = 2, + C = 4 + } + + private enum S32Enum; + + private enum U32Enum : uint + { + A = 1, + B = 2, + C = 4 + } + + private enum S64Enum : long; + + private enum U64Enum : ulong + { + A = 1, + B = 2, + C = 4 + } +} \ No newline at end of file diff --git a/dotnet/Tests/Flag16Tests.cs b/dotnet/Tests/Flag16Tests.cs deleted file mode 100644 index 3e86310..0000000 --- a/dotnet/Tests/Flag16Tests.cs +++ /dev/null @@ -1,182 +0,0 @@ -using Multiflag.BuiltInValueTypes; - -namespace Tests -{ - public class Flag16Tests - { - [Fact] - public void Addition() - { - Flag16 flag1 = new Flag16(); - Flag16 flag2 = new Flag16(1); - Flag16 flag3 = new Flag16(2); - Flag16 flag4 = new Flag16(4, flag2); - - ushort flags = 0; - Assert.Equal(0, flags + flag1); - Assert.Equal(1, flags + flag2); - Assert.Equal(2, flags + flag3); - Assert.Equal(5, flags + flag4); - - flags = 2; - Assert.Equal(2, flags + flag1); - Assert.Equal(3, flags + flag2); - Assert.Equal(2, flags + flag3); - Assert.Equal(7, flags + flag4); - - flags = 255; - Assert.Equal(255, flags + flag1); - Assert.Equal(255, flags + flag2); - Assert.Equal(255, flags + flag3); - Assert.Equal(255, flags + flag4); - } - - [Fact] - public void Substraction() - { - Flag16 flag1 = new Flag16(); - Flag16 flag2 = new Flag16(1); - Flag16 flag3 = new Flag16(2); - Flag16 flag4 = new Flag16(4, flag2); - - ushort flags = 0; - Assert.Equal(0, flags - flag1); - Assert.Equal(0, flags - flag2); - Assert.Equal(0, flags - flag3); - Assert.Equal(0, flags - flag4); - - flags = 3; - Assert.Equal(3, flags - flag1); - Assert.Equal(2, flags - flag2); - Assert.Equal(1, flags - flag3); - Assert.Equal(3, flags - flag4); - - flags = 255; - Assert.Equal(255, flags - flag1); - Assert.Equal(250, flags - flag2); - Assert.Equal(253, flags - flag3); - Assert.Equal(251, flags - flag4); - } - - [Fact] - public void Includes() - { - Flag16 flag1 = new Flag16(); - Flag16 flag2 = new Flag16(1); - Flag16 flag3 = new Flag16(2); - Flag16 flag4 = new Flag16(4, flag2); - - ushort flags = 0; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.False(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = 6; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = 7; - Assert.True(flags.Includes(flag1)); - Assert.True(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.True(flags.Includes(flag4)); - } - - [Fact] - public void Properties() - { - Flag16 flag1 = new Flag16(); - Flag16 flag2 = new Flag16(1); - Flag16 flag3 = new Flag16(2, flag1); - Flag16 flag4 = new Flag16(flag1); - Flag16 flag5 = new Flag16(4, flag2); - Flag16 flag6 = new Flag16(flag2); - Flag16 flag7 = new Flag16(flag4, flag6); - - Assert.True(flag1.IsNothing); - Assert.False(flag2.IsNothing); - Assert.False(flag3.IsNothing); - Assert.True(flag4.IsNothing); - Assert.False(flag5.IsNothing); - Assert.False(flag6.IsNothing); - Assert.False(flag7.IsNothing); - - Assert.False(flag1.IsConcrete); - Assert.True(flag2.IsConcrete); - Assert.True(flag3.IsConcrete); - Assert.False(flag4.IsConcrete); - Assert.True(flag5.IsConcrete); - Assert.False(flag6.IsConcrete); - Assert.False(flag7.IsConcrete); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.False(flag3.IsAbstract); - Assert.False(flag4.IsAbstract); - Assert.False(flag5.IsAbstract); - Assert.True(flag6.IsAbstract); - Assert.True(flag7.IsAbstract); - } - - [Fact] - public void PositiveEquality() - { - Flag16 flag1 = new Flag16(); - Flag16 flag2 = new Flag16(1); - Flag16 flag3 = new Flag16(2, flag2); - Flag16 flag4 = new Flag16(flag2); - - Assert.True(flag1.PositiveEquals(flag1)); - Assert.False(flag1.PositiveEquals(flag2)); - Assert.False(flag1.PositiveEquals(flag3)); - Assert.False(flag1.PositiveEquals(flag4)); - - Assert.False(flag2.PositiveEquals(flag1)); - Assert.True(flag2.PositiveEquals(flag2)); - Assert.False(flag2.PositiveEquals(flag3)); - Assert.True(flag2.PositiveEquals(flag4)); - - Assert.False(flag3.PositiveEquals(flag1)); - Assert.False(flag3.PositiveEquals(flag2)); - Assert.True(flag3.PositiveEquals(flag3)); - Assert.False(flag3.PositiveEquals(flag4)); - - Assert.False(flag4.PositiveEquals(flag1)); - Assert.True(flag4.PositiveEquals(flag2)); - Assert.False(flag4.PositiveEquals(flag3)); - Assert.True(flag4.PositiveEquals(flag4)); - } - - [Fact] - public void NegativeEquality() - { - Flag16 flag1 = new Flag16(); - Flag16 flag2 = new Flag16(1); - Flag16 flag3 = new Flag16(2, flag2); - Flag16 flag4 = new Flag16(flag2); - - Assert.True(flag1.NegativeEquals(flag1)); - Assert.False(flag1.NegativeEquals(flag2)); - Assert.False(flag1.NegativeEquals(flag3)); - Assert.True(flag1.NegativeEquals(flag4)); - - Assert.False(flag2.NegativeEquals(flag1)); - Assert.True(flag2.NegativeEquals(flag2)); - Assert.False(flag2.NegativeEquals(flag3)); - Assert.False(flag2.NegativeEquals(flag4)); - - Assert.False(flag3.NegativeEquals(flag1)); - Assert.False(flag3.NegativeEquals(flag2)); - Assert.True(flag3.NegativeEquals(flag3)); - Assert.False(flag3.NegativeEquals(flag4)); - - Assert.True(flag4.NegativeEquals(flag1)); - Assert.False(flag4.NegativeEquals(flag2)); - Assert.False(flag4.NegativeEquals(flag3)); - Assert.True(flag4.NegativeEquals(flag4)); - } - } -} \ No newline at end of file diff --git a/dotnet/Tests/Flag32Tests.cs b/dotnet/Tests/Flag32Tests.cs deleted file mode 100644 index b97bd72..0000000 --- a/dotnet/Tests/Flag32Tests.cs +++ /dev/null @@ -1,182 +0,0 @@ -using Multiflag.BuiltInValueTypes; - -namespace Tests -{ - public class Flag32Tests - { - [Fact] - public void Addition() - { - Flag32 flag1 = new Flag32(); - Flag32 flag2 = new Flag32(1); - Flag32 flag3 = new Flag32(2); - Flag32 flag4 = new Flag32(4, flag2); - - uint flags = 0; - Assert.Equal(0u, flags + flag1); - Assert.Equal(1u, flags + flag2); - Assert.Equal(2u, flags + flag3); - Assert.Equal(5u, flags + flag4); - - flags = 2; - Assert.Equal(2u, flags + flag1); - Assert.Equal(3u, flags + flag2); - Assert.Equal(2u, flags + flag3); - Assert.Equal(7u, flags + flag4); - - flags = 255; - Assert.Equal(255u, flags + flag1); - Assert.Equal(255u, flags + flag2); - Assert.Equal(255u, flags + flag3); - Assert.Equal(255u, flags + flag4); - } - - [Fact] - public void Substraction() - { - Flag32 flag1 = new Flag32(); - Flag32 flag2 = new Flag32(1); - Flag32 flag3 = new Flag32(2); - Flag32 flag4 = new Flag32(4, flag2); - - uint flags = 0; - Assert.Equal(0u, flags - flag1); - Assert.Equal(0u, flags - flag2); - Assert.Equal(0u, flags - flag3); - Assert.Equal(0u, flags - flag4); - - flags = 3; - Assert.Equal(3u, flags - flag1); - Assert.Equal(2u, flags - flag2); - Assert.Equal(1u, flags - flag3); - Assert.Equal(3u, flags - flag4); - - flags = 255; - Assert.Equal(255u, flags - flag1); - Assert.Equal(250u, flags - flag2); - Assert.Equal(253u, flags - flag3); - Assert.Equal(251u, flags - flag4); - } - - [Fact] - public void Includes() - { - Flag32 flag1 = new Flag32(); - Flag32 flag2 = new Flag32(1); - Flag32 flag3 = new Flag32(2); - Flag32 flag4 = new Flag32(4, flag2); - - uint flags = 0; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.False(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = 6; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = 7; - Assert.True(flags.Includes(flag1)); - Assert.True(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.True(flags.Includes(flag4)); - } - - [Fact] - public void Properties() - { - Flag32 flag1 = new Flag32(); - Flag32 flag2 = new Flag32(1); - Flag32 flag3 = new Flag32(2, flag1); - Flag32 flag4 = new Flag32(flag1); - Flag32 flag5 = new Flag32(4, flag2); - Flag32 flag6 = new Flag32(flag2); - Flag32 flag7 = new Flag32(flag4, flag6); - - Assert.True(flag1.IsNothing); - Assert.False(flag2.IsNothing); - Assert.False(flag3.IsNothing); - Assert.True(flag4.IsNothing); - Assert.False(flag5.IsNothing); - Assert.False(flag6.IsNothing); - Assert.False(flag7.IsNothing); - - Assert.False(flag1.IsConcrete); - Assert.True(flag2.IsConcrete); - Assert.True(flag3.IsConcrete); - Assert.False(flag4.IsConcrete); - Assert.True(flag5.IsConcrete); - Assert.False(flag6.IsConcrete); - Assert.False(flag7.IsConcrete); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.False(flag3.IsAbstract); - Assert.False(flag4.IsAbstract); - Assert.False(flag5.IsAbstract); - Assert.True(flag6.IsAbstract); - Assert.True(flag7.IsAbstract); - } - - [Fact] - public void PositiveEquality() - { - Flag32 flag1 = new Flag32(); - Flag32 flag2 = new Flag32(1); - Flag32 flag3 = new Flag32(2, flag2); - Flag32 flag4 = new Flag32(flag2); - - Assert.True(flag1.PositiveEquals(flag1)); - Assert.False(flag1.PositiveEquals(flag2)); - Assert.False(flag1.PositiveEquals(flag3)); - Assert.False(flag1.PositiveEquals(flag4)); - - Assert.False(flag2.PositiveEquals(flag1)); - Assert.True(flag2.PositiveEquals(flag2)); - Assert.False(flag2.PositiveEquals(flag3)); - Assert.True(flag2.PositiveEquals(flag4)); - - Assert.False(flag3.PositiveEquals(flag1)); - Assert.False(flag3.PositiveEquals(flag2)); - Assert.True(flag3.PositiveEquals(flag3)); - Assert.False(flag3.PositiveEquals(flag4)); - - Assert.False(flag4.PositiveEquals(flag1)); - Assert.True(flag4.PositiveEquals(flag2)); - Assert.False(flag4.PositiveEquals(flag3)); - Assert.True(flag4.PositiveEquals(flag4)); - } - - [Fact] - public void NegativeEquality() - { - Flag32 flag1 = new Flag32(); - Flag32 flag2 = new Flag32(1); - Flag32 flag3 = new Flag32(2, flag2); - Flag32 flag4 = new Flag32(flag2); - - Assert.True(flag1.NegativeEquals(flag1)); - Assert.False(flag1.NegativeEquals(flag2)); - Assert.False(flag1.NegativeEquals(flag3)); - Assert.True(flag1.NegativeEquals(flag4)); - - Assert.False(flag2.NegativeEquals(flag1)); - Assert.True(flag2.NegativeEquals(flag2)); - Assert.False(flag2.NegativeEquals(flag3)); - Assert.False(flag2.NegativeEquals(flag4)); - - Assert.False(flag3.NegativeEquals(flag1)); - Assert.False(flag3.NegativeEquals(flag2)); - Assert.True(flag3.NegativeEquals(flag3)); - Assert.False(flag3.NegativeEquals(flag4)); - - Assert.True(flag4.NegativeEquals(flag1)); - Assert.False(flag4.NegativeEquals(flag2)); - Assert.False(flag4.NegativeEquals(flag3)); - Assert.True(flag4.NegativeEquals(flag4)); - } - } -} \ No newline at end of file diff --git a/dotnet/Tests/Flag64Tests.cs b/dotnet/Tests/Flag64Tests.cs deleted file mode 100644 index fea3957..0000000 --- a/dotnet/Tests/Flag64Tests.cs +++ /dev/null @@ -1,182 +0,0 @@ -using Multiflag.BuiltInValueTypes; - -namespace Tests -{ - public class Flag64Tests - { - [Fact] - public void Addition() - { - Flag64 flag1 = new Flag64(); - Flag64 flag2 = new Flag64(1); - Flag64 flag3 = new Flag64(2); - Flag64 flag4 = new Flag64(4, flag2); - - ulong flags = 0; - Assert.Equal(0u, flags + flag1); - Assert.Equal(1u, flags + flag2); - Assert.Equal(2u, flags + flag3); - Assert.Equal(5u, flags + flag4); - - flags = 2; - Assert.Equal(2u, flags + flag1); - Assert.Equal(3u, flags + flag2); - Assert.Equal(2u, flags + flag3); - Assert.Equal(7u, flags + flag4); - - flags = 255; - Assert.Equal(255u, flags + flag1); - Assert.Equal(255u, flags + flag2); - Assert.Equal(255u, flags + flag3); - Assert.Equal(255u, flags + flag4); - } - - [Fact] - public void Substraction() - { - Flag64 flag1 = new Flag64(); - Flag64 flag2 = new Flag64(1); - Flag64 flag3 = new Flag64(2); - Flag64 flag4 = new Flag64(4, flag2); - - ulong flags = 0; - Assert.Equal(0u, flags - flag1); - Assert.Equal(0u, flags - flag2); - Assert.Equal(0u, flags - flag3); - Assert.Equal(0u, flags - flag4); - - flags = 3; - Assert.Equal(3u, flags - flag1); - Assert.Equal(2u, flags - flag2); - Assert.Equal(1u, flags - flag3); - Assert.Equal(3u, flags - flag4); - - flags = 255; - Assert.Equal(255u, flags - flag1); - Assert.Equal(250u, flags - flag2); - Assert.Equal(253u, flags - flag3); - Assert.Equal(251u, flags - flag4); - } - - [Fact] - public void Includes() - { - Flag64 flag1 = new Flag64(); - Flag64 flag2 = new Flag64(1); - Flag64 flag3 = new Flag64(2); - Flag64 flag4 = new Flag64(4, flag2); - - ulong flags = 0; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.False(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = 6; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = 7; - Assert.True(flags.Includes(flag1)); - Assert.True(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.True(flags.Includes(flag4)); - } - - [Fact] - public void Properties() - { - Flag64 flag1 = new Flag64(); - Flag64 flag2 = new Flag64(1); - Flag64 flag3 = new Flag64(2, flag1); - Flag64 flag4 = new Flag64(flag1); - Flag64 flag5 = new Flag64(4, flag2); - Flag64 flag6 = new Flag64(flag2); - Flag64 flag7 = new Flag64(flag4, flag6); - - Assert.True(flag1.IsNothing); - Assert.False(flag2.IsNothing); - Assert.False(flag3.IsNothing); - Assert.True(flag4.IsNothing); - Assert.False(flag5.IsNothing); - Assert.False(flag6.IsNothing); - Assert.False(flag7.IsNothing); - - Assert.False(flag1.IsConcrete); - Assert.True(flag2.IsConcrete); - Assert.True(flag3.IsConcrete); - Assert.False(flag4.IsConcrete); - Assert.True(flag5.IsConcrete); - Assert.False(flag6.IsConcrete); - Assert.False(flag7.IsConcrete); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.False(flag3.IsAbstract); - Assert.False(flag4.IsAbstract); - Assert.False(flag5.IsAbstract); - Assert.True(flag6.IsAbstract); - Assert.True(flag7.IsAbstract); - } - - [Fact] - public void PositiveEquality() - { - Flag64 flag1 = new Flag64(); - Flag64 flag2 = new Flag64(1); - Flag64 flag3 = new Flag64(2, flag2); - Flag64 flag4 = new Flag64(flag2); - - Assert.True(flag1.PositiveEquals(flag1)); - Assert.False(flag1.PositiveEquals(flag2)); - Assert.False(flag1.PositiveEquals(flag3)); - Assert.False(flag1.PositiveEquals(flag4)); - - Assert.False(flag2.PositiveEquals(flag1)); - Assert.True(flag2.PositiveEquals(flag2)); - Assert.False(flag2.PositiveEquals(flag3)); - Assert.True(flag2.PositiveEquals(flag4)); - - Assert.False(flag3.PositiveEquals(flag1)); - Assert.False(flag3.PositiveEquals(flag2)); - Assert.True(flag3.PositiveEquals(flag3)); - Assert.False(flag3.PositiveEquals(flag4)); - - Assert.False(flag4.PositiveEquals(flag1)); - Assert.True(flag4.PositiveEquals(flag2)); - Assert.False(flag4.PositiveEquals(flag3)); - Assert.True(flag4.PositiveEquals(flag4)); - } - - [Fact] - public void NegativeEquality() - { - Flag64 flag1 = new Flag64(); - Flag64 flag2 = new Flag64(1); - Flag64 flag3 = new Flag64(2, flag2); - Flag64 flag4 = new Flag64(flag2); - - Assert.True(flag1.NegativeEquals(flag1)); - Assert.False(flag1.NegativeEquals(flag2)); - Assert.False(flag1.NegativeEquals(flag3)); - Assert.True(flag1.NegativeEquals(flag4)); - - Assert.False(flag2.NegativeEquals(flag1)); - Assert.True(flag2.NegativeEquals(flag2)); - Assert.False(flag2.NegativeEquals(flag3)); - Assert.False(flag2.NegativeEquals(flag4)); - - Assert.False(flag3.NegativeEquals(flag1)); - Assert.False(flag3.NegativeEquals(flag2)); - Assert.True(flag3.NegativeEquals(flag3)); - Assert.False(flag3.NegativeEquals(flag4)); - - Assert.True(flag4.NegativeEquals(flag1)); - Assert.False(flag4.NegativeEquals(flag2)); - Assert.False(flag4.NegativeEquals(flag3)); - Assert.True(flag4.NegativeEquals(flag4)); - } - } -} \ No newline at end of file diff --git a/dotnet/Tests/Flag8Tests.cs b/dotnet/Tests/Flag8Tests.cs deleted file mode 100644 index 2b01849..0000000 --- a/dotnet/Tests/Flag8Tests.cs +++ /dev/null @@ -1,182 +0,0 @@ -using Multiflag.BuiltInValueTypes; - -namespace Tests -{ - public class Flag8Tests - { - [Fact] - public void Addition() - { - Flag8 flag1 = new Flag8(); - Flag8 flag2 = new Flag8(1); - Flag8 flag3 = new Flag8(2); - Flag8 flag4 = new Flag8(4, flag2); - - byte flags = 0; - Assert.Equal(0, flags + flag1); - Assert.Equal(1, flags + flag2); - Assert.Equal(2, flags + flag3); - Assert.Equal(5, flags + flag4); - - flags = 2; - Assert.Equal(2, flags + flag1); - Assert.Equal(3, flags + flag2); - Assert.Equal(2, flags + flag3); - Assert.Equal(7, flags + flag4); - - flags = 255; - Assert.Equal(255, flags + flag1); - Assert.Equal(255, flags + flag2); - Assert.Equal(255, flags + flag3); - Assert.Equal(255, flags + flag4); - } - - [Fact] - public void Substraction() - { - Flag8 flag1 = new Flag8(); - Flag8 flag2 = new Flag8(1); - Flag8 flag3 = new Flag8(2); - Flag8 flag4 = new Flag8(4, flag2); - - byte flags = 0; - Assert.Equal(0, flags - flag1); - Assert.Equal(0, flags - flag2); - Assert.Equal(0, flags - flag3); - Assert.Equal(0, flags - flag4); - - flags = 3; - Assert.Equal(3, flags - flag1); - Assert.Equal(2, flags - flag2); - Assert.Equal(1, flags - flag3); - Assert.Equal(3, flags - flag4); - - flags = 255; - Assert.Equal(255, flags - flag1); - Assert.Equal(250, flags - flag2); - Assert.Equal(253, flags - flag3); - Assert.Equal(251, flags - flag4); - } - - [Fact] - public void Includes() - { - Flag8 flag1 = new Flag8(); - Flag8 flag2 = new Flag8(1); - Flag8 flag3 = new Flag8(2); - Flag8 flag4 = new Flag8(4, flag2); - - byte flags = 0; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.False(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = 6; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = 7; - Assert.True(flags.Includes(flag1)); - Assert.True(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.True(flags.Includes(flag4)); - } - - [Fact] - public void Properties() - { - Flag8 flag1 = new Flag8(); - Flag8 flag2 = new Flag8(1); - Flag8 flag3 = new Flag8(2, flag1); - Flag8 flag4 = new Flag8(flag1); - Flag8 flag5 = new Flag8(4, flag2); - Flag8 flag6 = new Flag8(flag2); - Flag8 flag7 = new Flag8(flag4, flag6); - - Assert.True(flag1.IsNothing); - Assert.False(flag2.IsNothing); - Assert.False(flag3.IsNothing); - Assert.True(flag4.IsNothing); - Assert.False(flag5.IsNothing); - Assert.False(flag6.IsNothing); - Assert.False(flag7.IsNothing); - - Assert.False(flag1.IsConcrete); - Assert.True(flag2.IsConcrete); - Assert.True(flag3.IsConcrete); - Assert.False(flag4.IsConcrete); - Assert.True(flag5.IsConcrete); - Assert.False(flag6.IsConcrete); - Assert.False(flag7.IsConcrete); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.False(flag3.IsAbstract); - Assert.False(flag4.IsAbstract); - Assert.False(flag5.IsAbstract); - Assert.True(flag6.IsAbstract); - Assert.True(flag7.IsAbstract); - } - - [Fact] - public void PositiveEquality() - { - Flag8 flag1 = new Flag8(); - Flag8 flag2 = new Flag8(1); - Flag8 flag3 = new Flag8(2, flag2); - Flag8 flag4 = new Flag8(flag2); - - Assert.True(flag1.PositiveEquals(flag1)); - Assert.False(flag1.PositiveEquals(flag2)); - Assert.False(flag1.PositiveEquals(flag3)); - Assert.False(flag1.PositiveEquals(flag4)); - - Assert.False(flag2.PositiveEquals(flag1)); - Assert.True(flag2.PositiveEquals(flag2)); - Assert.False(flag2.PositiveEquals(flag3)); - Assert.True(flag2.PositiveEquals(flag4)); - - Assert.False(flag3.PositiveEquals(flag1)); - Assert.False(flag3.PositiveEquals(flag2)); - Assert.True(flag3.PositiveEquals(flag3)); - Assert.False(flag3.PositiveEquals(flag4)); - - Assert.False(flag4.PositiveEquals(flag1)); - Assert.True(flag4.PositiveEquals(flag2)); - Assert.False(flag4.PositiveEquals(flag3)); - Assert.True(flag4.PositiveEquals(flag4)); - } - - [Fact] - public void NegativeEquality() - { - Flag8 flag1 = new Flag8(); - Flag8 flag2 = new Flag8(1); - Flag8 flag3 = new Flag8(2, flag2); - Flag8 flag4 = new Flag8(flag2); - - Assert.True(flag1.NegativeEquals(flag1)); - Assert.False(flag1.NegativeEquals(flag2)); - Assert.False(flag1.NegativeEquals(flag3)); - Assert.True(flag1.NegativeEquals(flag4)); - - Assert.False(flag2.NegativeEquals(flag1)); - Assert.True(flag2.NegativeEquals(flag2)); - Assert.False(flag2.NegativeEquals(flag3)); - Assert.False(flag2.NegativeEquals(flag4)); - - Assert.False(flag3.NegativeEquals(flag1)); - Assert.False(flag3.NegativeEquals(flag2)); - Assert.True(flag3.NegativeEquals(flag3)); - Assert.False(flag3.NegativeEquals(flag4)); - - Assert.True(flag4.NegativeEquals(flag1)); - Assert.False(flag4.NegativeEquals(flag2)); - Assert.False(flag4.NegativeEquals(flag3)); - Assert.True(flag4.NegativeEquals(flag4)); - } - } -} \ No newline at end of file diff --git a/dotnet/Tests/FlagEnumTests.cs b/dotnet/Tests/FlagEnumTests.cs deleted file mode 100644 index 74319a5..0000000 --- a/dotnet/Tests/FlagEnumTests.cs +++ /dev/null @@ -1,215 +0,0 @@ -using Multiflag.BuiltInValueTypes; -using System.Reflection; - -namespace Tests -{ - public class FlagEnumTests - { - private enum TheEnum - { - A = 1, - B = 2, - C = 4, - - None = 0, - All = A | B | C - } - - private enum TheWrongEnum : ulong { Caca } - - [Fact] - public void Addition() - { - FlagEnum flag1 = new(); - FlagEnum flag2 = new(TheEnum.A); - FlagEnum flag3 = new(TheEnum.B); - FlagEnum flag4 = new(TheEnum.C, flag2); - - TheEnum flags = TheEnum.None; - Assert.Equal(TheEnum.None, flags + flag1); - Assert.Equal(TheEnum.A, flags + flag2); - Assert.Equal(TheEnum.B, flags + flag3); - Assert.Equal(TheEnum.C | TheEnum.A, flags + flag4); - - flags = TheEnum.B; - Assert.Equal(TheEnum.B, flags + flag1); - Assert.Equal(TheEnum.A | TheEnum.B, flags + flag2); - Assert.Equal(TheEnum.B, flags + flag3); - Assert.Equal(TheEnum.All, flags + flag4); - - flags = TheEnum.All; - Assert.Equal(TheEnum.All, flags + flag1); - Assert.Equal(TheEnum.All, flags + flag2); - Assert.Equal(TheEnum.All, flags + flag3); - Assert.Equal(TheEnum.All, flags + flag4); - } - - [Fact] - public void Substraction() - { - FlagEnum flag1 = new(); - FlagEnum flag2 = new(TheEnum.A); - FlagEnum flag3 = new(TheEnum.B); - FlagEnum flag4 = new(TheEnum.C, flag2); - - TheEnum flags = TheEnum.None; - Assert.Equal(TheEnum.None, flags - flag1); - Assert.Equal(TheEnum.None, flags - flag2); - Assert.Equal(TheEnum.None, flags - flag3); - Assert.Equal(TheEnum.None, flags - flag4); - - flags = TheEnum.A | TheEnum.B; - Assert.Equal(TheEnum.A | TheEnum.B, flags - flag1); - Assert.Equal(TheEnum.B, flags - flag2); - Assert.Equal(TheEnum.A, flags - flag3); - Assert.Equal(TheEnum.A | TheEnum.B, flags - flag4); - - flags = TheEnum.All; - Assert.Equal(TheEnum.All, flags - flag1); - Assert.Equal(TheEnum.B, flags - flag2); - Assert.Equal(TheEnum.A | TheEnum.C, flags - flag3); - Assert.Equal(TheEnum.A | TheEnum.B, flags - flag4); - } - - [Fact] - public void Includes() - { - FlagEnum flag1 = new(); - FlagEnum flag2 = new(TheEnum.A); - FlagEnum flag3 = new(TheEnum.B); - FlagEnum flag4 = new(TheEnum.C, flag2); - - TheEnum flags = TheEnum.None; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.False(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = TheEnum.B | TheEnum.C; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = TheEnum.All; - Assert.True(flags.Includes(flag1)); - Assert.True(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.True(flags.Includes(flag4)); - } - - [Fact] - public void Properties() - { - FlagEnum flag1 = new(); - FlagEnum flag2 = new(TheEnum.A); - FlagEnum flag3 = new(TheEnum.B, flag1); - FlagEnum flag4 = new(flag1); - FlagEnum flag5 = new(TheEnum.C, flag2); - FlagEnum flag6 = new(flag2); - FlagEnum flag7 = new(flag4, flag6); - - Assert.True(flag1.IsNothing); - Assert.False(flag2.IsNothing); - Assert.False(flag3.IsNothing); - Assert.True(flag4.IsNothing); - Assert.False(flag5.IsNothing); - Assert.False(flag6.IsNothing); - Assert.False(flag7.IsNothing); - - Assert.False(flag1.IsConcrete); - Assert.True(flag2.IsConcrete); - Assert.True(flag3.IsConcrete); - Assert.False(flag4.IsConcrete); - Assert.True(flag5.IsConcrete); - Assert.False(flag6.IsConcrete); - Assert.False(flag7.IsConcrete); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.False(flag3.IsAbstract); - Assert.False(flag4.IsAbstract); - Assert.False(flag5.IsAbstract); - Assert.True(flag6.IsAbstract); - Assert.True(flag7.IsAbstract); - } - - [Fact] - public void PositiveEquality() - { - FlagEnum flag1 = new(); - FlagEnum flag2 = new(TheEnum.A); - FlagEnum flag3 = new(TheEnum.B, flag2); - FlagEnum flag4 = new(flag2); - - Assert.True(flag1.PositiveEquals(flag1)); - Assert.False(flag1.PositiveEquals(flag2)); - Assert.False(flag1.PositiveEquals(flag3)); - Assert.False(flag1.PositiveEquals(flag4)); - - Assert.False(flag2.PositiveEquals(flag1)); - Assert.True(flag2.PositiveEquals(flag2)); - Assert.False(flag2.PositiveEquals(flag3)); - Assert.True(flag2.PositiveEquals(flag4)); - - Assert.False(flag3.PositiveEquals(flag1)); - Assert.False(flag3.PositiveEquals(flag2)); - Assert.True(flag3.PositiveEquals(flag3)); - Assert.False(flag3.PositiveEquals(flag4)); - - Assert.False(flag4.PositiveEquals(flag1)); - Assert.True(flag4.PositiveEquals(flag2)); - Assert.False(flag4.PositiveEquals(flag3)); - Assert.True(flag4.PositiveEquals(flag4)); - } - - [Fact] - public void NegativeEquality() - { - FlagEnum flag1 = new(); - FlagEnum flag2 = new(TheEnum.A); - FlagEnum flag3 = new(TheEnum.B, flag2); - FlagEnum flag4 = new(flag2); - - Assert.True(flag1.NegativeEquals(flag1)); - Assert.False(flag1.NegativeEquals(flag2)); - Assert.False(flag1.NegativeEquals(flag3)); - Assert.True(flag1.NegativeEquals(flag4)); - - Assert.False(flag2.NegativeEquals(flag1)); - Assert.True(flag2.NegativeEquals(flag2)); - Assert.False(flag2.NegativeEquals(flag3)); - Assert.False(flag2.NegativeEquals(flag4)); - - Assert.False(flag3.NegativeEquals(flag1)); - Assert.False(flag3.NegativeEquals(flag2)); - Assert.True(flag3.NegativeEquals(flag3)); - Assert.False(flag3.NegativeEquals(flag4)); - - Assert.True(flag4.NegativeEquals(flag1)); - Assert.False(flag4.NegativeEquals(flag2)); - Assert.False(flag4.NegativeEquals(flag3)); - Assert.True(flag4.NegativeEquals(flag4)); - } - - [Fact] - public void ThrowsWhenNotInt() - { - try - { - FlagEnum flag = new(TheWrongEnum.Caca); - } - catch (TargetInvocationException error) - { - if (error.InnerException is not InvalidEnumTypeException) - { - Assert.Fail($"Wrong exception type inside the TargetInvocationException (expected InvalidEnumTypeException, got {error.InnerException?.GetType()}"); - } - } - catch (Exception other) - { - Assert.Fail($"Wrong exception type thrown (expected TargetInvocationException, got {other.GetType()}"); - } - } - } -} \ No newline at end of file diff --git a/dotnet/Tests/FlagSetTests.cs b/dotnet/Tests/FlagSetTests.cs index 3c54141..76f6467 100644 --- a/dotnet/Tests/FlagSetTests.cs +++ b/dotnet/Tests/FlagSetTests.cs @@ -1,209 +1,22 @@ -using Multiflag.BuiltInValueTypes; +namespace Multiflag.Tests; -namespace Tests +public class FlagSetTests { - public class FlagSetTests + [Fact] + public void UseFlagFromOtherSetAsParent() { - private HashSet EmptySet => new HashSet { }; - private HashSet ASet => new HashSet { "A" }; - private HashSet BSet => new HashSet { "B" }; - private HashSet CSet => new HashSet { "C" }; - private HashSet ABSet => new HashSet { "A", "B" }; - private HashSet BCSet => new HashSet { "B", "C" }; - private HashSet ACSet => new HashSet { "A", "C" }; - private HashSet ABCSet => new HashSet { "A", "B", "C" }; + var flags = new U8BitflagSet(); + var flag = flags.Flag(1); - [Fact] - public void Addition() - { - FlagSet flag1 = new(); - FlagSet flag2 = new("A"); - FlagSet flag3 = new("B"); - FlagSet flag4 = new("C", flag2); - - HashSet flags = EmptySet; - Assert.Equal(EmptySet, flags + flag1); - flags = EmptySet; - Assert.Equal(ASet, flags + flag2); - flags = EmptySet; - Assert.Equal(BSet, flags + flag3); - flags = EmptySet; - Assert.Equal(ACSet, flags + flag4); - - flags = new HashSet { "B" }; - Assert.Equal(BSet, flags + flag1); - flags = new HashSet { "B" }; - Assert.Equal(ABSet, flags + flag2); - flags = new HashSet { "B" }; - Assert.Equal(BSet, flags + flag3); - flags = new HashSet { "B" }; - Assert.Equal(ABCSet, flags + flag4); - - flags = new HashSet { "A", "B", "C" }; - Assert.Equal(ABCSet, flags + flag1); - flags = new HashSet { "A", "B", "C" }; - Assert.Equal(ABCSet, flags + flag2); - flags = new HashSet { "A", "B", "C" }; - Assert.Equal(ABCSet, flags + flag3); - flags = new HashSet { "A", "B", "C" }; - Assert.Equal(ABCSet, flags + flag4); - } - - [Fact] - public void Substraction() - { - FlagSet flag1 = new(); - FlagSet flag2 = new("A"); - FlagSet flag3 = new("B"); - FlagSet flag4 = new("C", flag2); - - HashSet flags = EmptySet; - Assert.Equal(EmptySet, flags - flag1); - flags = EmptySet; - Assert.Equal(EmptySet, flags - flag2); - flags = EmptySet; - Assert.Equal(EmptySet, flags - flag3); - flags = EmptySet; - Assert.Equal(EmptySet, flags - flag4); - - flags = ABSet; - Assert.Equal(ABSet, flags - flag1); - flags = ABSet; - Assert.Equal(BSet, flags - flag2); - flags = ABSet; - Assert.Equal(ASet, flags - flag3); - flags = ABSet; - Assert.Equal(ABSet, flags - flag4); - - flags = ABCSet; - Assert.Equal(ABCSet, flags - flag1); - flags = ABCSet; - Assert.Equal(BSet, flags - flag2); - flags = ABCSet; - Assert.Equal(ACSet, flags - flag3); - flags = ABCSet; - Assert.Equal(ABSet, flags - flag4); - } - - [Fact] - public void Includes() - { - FlagSet flag1 = new(); - FlagSet flag2 = new(ASet); - FlagSet flag3 = new(BSet); - FlagSet flag4 = new("C", flag2); - - HashSet flags = EmptySet; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.False(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = BCSet; - Assert.True(flags.Includes(flag1)); - Assert.False(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.False(flags.Includes(flag4)); - - flags = ABCSet; - Assert.True(flags.Includes(flag1)); - Assert.True(flags.Includes(flag2)); - Assert.True(flags.Includes(flag3)); - Assert.True(flags.Includes(flag4)); - } - - [Fact] - public void Properties() - { - FlagSet flag1 = new(); - FlagSet flag2 = new("A"); - FlagSet flag3 = new("B", flag1); - FlagSet flag4 = new(flag1); - FlagSet flag5 = new("C", flag2); - FlagSet flag6 = new(flag2); - FlagSet flag7 = new(flag4, flag6); - - Assert.True(flag1.IsNothing); - Assert.False(flag2.IsNothing); - Assert.False(flag3.IsNothing); - Assert.True(flag4.IsNothing); - Assert.False(flag5.IsNothing); - Assert.False(flag6.IsNothing); - Assert.False(flag7.IsNothing); - - Assert.False(flag1.IsConcrete); - Assert.True(flag2.IsConcrete); - Assert.True(flag3.IsConcrete); - Assert.False(flag4.IsConcrete); - Assert.True(flag5.IsConcrete); - Assert.False(flag6.IsConcrete); - Assert.False(flag7.IsConcrete); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.False(flag3.IsAbstract); - Assert.False(flag4.IsAbstract); - Assert.False(flag5.IsAbstract); - Assert.True(flag6.IsAbstract); - Assert.True(flag7.IsAbstract); - } - - [Fact] - public void PositiveEquality() - { - FlagSet flag1 = new(); - FlagSet flag2 = new("A"); - FlagSet flag3 = new("B", flag2); - FlagSet flag4 = new(flag2); - - Assert.True(flag1.PositiveEquals(flag1)); - Assert.False(flag1.PositiveEquals(flag2)); - Assert.False(flag1.PositiveEquals(flag3)); - Assert.False(flag1.PositiveEquals(flag4)); - - Assert.False(flag2.PositiveEquals(flag1)); - Assert.True(flag2.PositiveEquals(flag2)); - Assert.False(flag2.PositiveEquals(flag3)); - Assert.True(flag2.PositiveEquals(flag4)); - - Assert.False(flag3.PositiveEquals(flag1)); - Assert.False(flag3.PositiveEquals(flag2)); - Assert.True(flag3.PositiveEquals(flag3)); - Assert.False(flag3.PositiveEquals(flag4)); - - Assert.False(flag4.PositiveEquals(flag1)); - Assert.True(flag4.PositiveEquals(flag2)); - Assert.False(flag4.PositiveEquals(flag3)); - Assert.True(flag4.PositiveEquals(flag4)); - } - - [Fact] - public void NegativeEquality() - { - FlagSet flag1 = new(); - FlagSet flag2 = new("A"); - FlagSet flag3 = new("B", flag2); - FlagSet flag4 = new(flag2); - - Assert.True(flag1.NegativeEquals(flag1)); - Assert.False(flag1.NegativeEquals(flag2)); - Assert.False(flag1.NegativeEquals(flag3)); - Assert.True(flag1.NegativeEquals(flag4)); - - Assert.False(flag2.NegativeEquals(flag1)); - Assert.True(flag2.NegativeEquals(flag2)); - Assert.False(flag2.NegativeEquals(flag3)); - Assert.False(flag2.NegativeEquals(flag4)); - - Assert.False(flag3.NegativeEquals(flag1)); - Assert.False(flag3.NegativeEquals(flag2)); - Assert.True(flag3.NegativeEquals(flag3)); - Assert.False(flag3.NegativeEquals(flag4)); + var otherFlags = new U8BitflagSet(); + Assert.Throws(() => otherFlags.Flag(2, flag)); + } - Assert.True(flag4.NegativeEquals(flag1)); - Assert.False(flag4.NegativeEquals(flag2)); - Assert.False(flag4.NegativeEquals(flag3)); - Assert.True(flag4.NegativeEquals(flag4)); - } + [Fact] + public void UseSameValueTwice() + { + var flags = new U8BitflagSet(); + var flag = flags.Flag(1); + Assert.Throws(() => flags.Flag(1, flag)); } } \ No newline at end of file diff --git a/dotnet/Tests/FlagTests.cs b/dotnet/Tests/FlagTests.cs new file mode 100644 index 0000000..69a12e6 --- /dev/null +++ b/dotnet/Tests/FlagTests.cs @@ -0,0 +1,141 @@ +namespace Multiflag.Tests; + +public class FlagTests +{ + [Fact] + public void AddTo() + { + Assert.Equal(1, MyBitflags.Current.FlagA.AddTo(0)); + Assert.Equal(3, MyBitflags.Current.FlagA.AddTo(2)); + Assert.Equal(7, MyBitflags.Current.FlagA.AddTo(7)); + + Assert.Equal(2, MyBitflags.Current.FlagB.AddTo(0)); + Assert.Equal(2, MyBitflags.Current.FlagB.AddTo(2)); + Assert.Equal(7, MyBitflags.Current.FlagB.AddTo(7)); + + Assert.Equal(3, MyBitflags.Current.FlagC.AddTo(0)); + Assert.Equal(3, MyBitflags.Current.FlagC.AddTo(2)); + Assert.Equal(7, MyBitflags.Current.FlagC.AddTo(7)); + + Assert.Equal(7, MyBitflags.Current.FlagD.AddTo(2)); + Assert.Equal(5, MyBitflags.Current.FlagD.AddTo(0)); + Assert.Equal(7, MyBitflags.Current.FlagD.AddTo(7)); + } + + [Fact] + public void Addition() + { + Assert.Equal(1, 0 + MyBitflags.Current.FlagA); + Assert.Equal(3, 2 + MyBitflags.Current.FlagA); + Assert.Equal(7, 7 + MyBitflags.Current.FlagA); + + Assert.Equal(2, 0 + MyBitflags.Current.FlagB); + Assert.Equal(2, 2 + MyBitflags.Current.FlagB); + Assert.Equal(7, 7 + MyBitflags.Current.FlagB); + + Assert.Equal(3, 0 + MyBitflags.Current.FlagC); + Assert.Equal(3, 2 + MyBitflags.Current.FlagC); + Assert.Equal(7, 7 + MyBitflags.Current.FlagC); + + Assert.Equal(7, 2 + MyBitflags.Current.FlagD); + Assert.Equal(5, 0 + MyBitflags.Current.FlagD); + Assert.Equal(7, 7 + MyBitflags.Current.FlagD); + } + + [Fact] + public void RemoveFrom() + { + Assert.Equal(0, MyBitflags.Current.FlagA.RemoveFrom(0)); + Assert.Equal(2, MyBitflags.Current.FlagA.RemoveFrom(2)); + Assert.Equal(2, MyBitflags.Current.FlagA.RemoveFrom(7)); + + Assert.Equal(0, MyBitflags.Current.FlagB.RemoveFrom(0)); + Assert.Equal(0, MyBitflags.Current.FlagB.RemoveFrom(2)); + Assert.Equal(5, MyBitflags.Current.FlagB.RemoveFrom(7)); + + Assert.Equal(0, MyBitflags.Current.FlagC.RemoveFrom(0)); + Assert.Equal(2, MyBitflags.Current.FlagC.RemoveFrom(2)); + Assert.Equal(7, MyBitflags.Current.FlagC.RemoveFrom(7)); + + Assert.Equal(2, MyBitflags.Current.FlagD.RemoveFrom(2)); + Assert.Equal(0, MyBitflags.Current.FlagD.RemoveFrom(0)); + Assert.Equal(3, MyBitflags.Current.FlagD.RemoveFrom(7)); + } + + [Fact] + public void Subtraction() + { + Assert.Equal(0, 0 - MyBitflags.Current.FlagA); + Assert.Equal(2, 2 - MyBitflags.Current.FlagA); + Assert.Equal(2, 7 - MyBitflags.Current.FlagA); + + Assert.Equal(0, 0 - MyBitflags.Current.FlagB); + Assert.Equal(0, 2 - MyBitflags.Current.FlagB); + Assert.Equal(5, 7 - MyBitflags.Current.FlagB); + + Assert.Equal(0, 0 - MyBitflags.Current.FlagC); + Assert.Equal(2, 2 - MyBitflags.Current.FlagC); + Assert.Equal(7, 7 - MyBitflags.Current.FlagC); + + Assert.Equal(0, 0 - MyBitflags.Current.FlagD); + Assert.Equal(2, 2 - MyBitflags.Current.FlagD); + Assert.Equal(3, 7 - MyBitflags.Current.FlagD); + } + + [Fact] + public void IsIn() + { + Assert.False(MyBitflags.Current.FlagA.IsIn(0)); + Assert.True(MyBitflags.Current.FlagA.IsIn(1)); + Assert.False(MyBitflags.Current.FlagA.IsIn(4)); + Assert.True(MyBitflags.Current.FlagA.IsIn(7)); + + Assert.False(MyBitflags.Current.FlagB.IsIn(0)); + Assert.True(MyBitflags.Current.FlagB.IsIn(2)); + Assert.False(MyBitflags.Current.FlagB.IsIn(4)); + Assert.True(MyBitflags.Current.FlagB.IsIn(7)); + + Assert.False(MyBitflags.Current.FlagC.IsIn(0)); + Assert.False(MyBitflags.Current.FlagC.IsIn(1)); + Assert.False(MyBitflags.Current.FlagC.IsIn(2)); + Assert.True(MyBitflags.Current.FlagC.IsIn(3)); + Assert.False(MyBitflags.Current.FlagC.IsIn(4)); + Assert.True(MyBitflags.Current.FlagC.IsIn(7)); + + Assert.False(MyBitflags.Current.FlagD.IsIn(0)); + Assert.False(MyBitflags.Current.FlagD.IsIn(1)); + Assert.False(MyBitflags.Current.FlagD.IsIn(4)); + Assert.True(MyBitflags.Current.FlagD.IsIn(5)); + Assert.False(MyBitflags.Current.FlagD.IsIn(6)); + Assert.True(MyBitflags.Current.FlagD.IsIn(7)); + } + + [Fact] + public void IsAbstract() + { + Assert.False(MyBitflags.Current.FlagA.IsAbstract); + Assert.False(MyBitflags.Current.FlagB.IsAbstract); + Assert.True(MyBitflags.Current.FlagC.IsAbstract); + Assert.False(MyBitflags.Current.FlagD.IsAbstract); + } + + private class MyBitflags : U8BitflagSet + { + private static MyBitflags? current; + + private MyBitflags() + { + this.FlagA = this.Flag(1); + this.FlagB = this.Flag(2); + this.FlagC = this.Flag(this.FlagA, this.FlagB); + this.FlagD = this.Flag(4, this.FlagA); + } + + public static MyBitflags Current => current ??= new MyBitflags(); + + public Flag FlagA { get; } + public Flag FlagB { get; } + public Flag FlagC { get; } + public Flag FlagD { get; } + } +} \ No newline at end of file diff --git a/dotnet/Tests/Tests.csproj b/dotnet/Tests/Tests.csproj index dfd9060..0a34995 100644 --- a/dotnet/Tests/Tests.csproj +++ b/dotnet/Tests/Tests.csproj @@ -1,33 +1,33 @@ - - net7.0 - enable - enable + + net9.0 + enable + enable + Multiflag.Tests + false + true + - false - true - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - + + + diff --git a/dotnet/Tests/U16BitflagSetTests.cs b/dotnet/Tests/U16BitflagSetTests.cs new file mode 100644 index 0000000..46089b2 --- /dev/null +++ b/dotnet/Tests/U16BitflagSetTests.cs @@ -0,0 +1,67 @@ +namespace Multiflag.Tests; + +public class U16BitflagSetTests +{ + [Fact] + public void ValueNotAPowerOfTwo() + { + var flags = new U16BitflagSet(); + Assert.Throws(() => flags.Flag(0)); + Assert.Throws(() => flags.Flag(11)); + } + + [Fact] + public void Add() + { + var flags = new U16BitflagSet(); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4); + var flags2And4 = flags.Flag(flag2, flag4); + + Assert.Equal(3, 1 + flag2); + Assert.Equal(5, 1 + flag4); + Assert.Equal(7, 1 + flags2And4); + } + + [Fact] + public void Remove() + { + var flags = new U16BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + + Assert.Equal(2, 7 - flag1); + Assert.Equal(5, 7 - flag2); + Assert.Equal(3, 7 - flag4); + } + + [Fact] + public void IsIn() + { + var flags = new U16BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + + Assert.True(flag1.IsIn(1)); + Assert.True(flag2.IsIn(3)); + Assert.False(flag4.IsIn(4)); + Assert.True(flag4.IsIn(5)); + } + + [Fact] + public void IsAbstract() + { + var flags = new U16BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flags1And2 = flags.Flag(flag1, flag2); + var flag4 = flags.Flag(4, flags1And2); + + Assert.False(flag1.IsAbstract); + Assert.False(flag2.IsAbstract); + Assert.True(flags1And2.IsAbstract); + Assert.False(flag4.IsAbstract); + } +} \ No newline at end of file diff --git a/dotnet/Tests/U32BitflagSetTests.cs b/dotnet/Tests/U32BitflagSetTests.cs new file mode 100644 index 0000000..3e92ad7 --- /dev/null +++ b/dotnet/Tests/U32BitflagSetTests.cs @@ -0,0 +1,67 @@ +namespace Multiflag.Tests; + +public class U32BitflagSetTests +{ + [Fact] + public void ValueNotAPowerOfTwo() + { + var flags = new U32BitflagSet(); + Assert.Throws(() => flags.Flag(0)); + Assert.Throws(() => flags.Flag(11)); + } + + [Fact] + public void Add() + { + var flags = new U32BitflagSet(); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4); + var flags2And4 = flags.Flag(flag2, flag4); + + Assert.Equal(3u, 1 + flag2); + Assert.Equal(5u, 1 + flag4); + Assert.Equal(7u, 1 + flags2And4); + } + + [Fact] + public void Remove() + { + var flags = new U32BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + + Assert.Equal(2u, 7 - flag1); + Assert.Equal(5u, 7 - flag2); + Assert.Equal(3u, 7 - flag4); + } + + [Fact] + public void IsIn() + { + var flags = new U32BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + + Assert.True(flag1.IsIn(1)); + Assert.True(flag2.IsIn(3)); + Assert.False(flag4.IsIn(4)); + Assert.True(flag4.IsIn(5)); + } + + [Fact] + public void IsAbstract() + { + var flags = new U32BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flags1And2 = flags.Flag(flag1, flag2); + var flag4 = flags.Flag(4, flags1And2); + + Assert.False(flag1.IsAbstract); + Assert.False(flag2.IsAbstract); + Assert.True(flags1And2.IsAbstract); + Assert.False(flag4.IsAbstract); + } +} \ No newline at end of file diff --git a/dotnet/Tests/U64BitflagSetTests.cs b/dotnet/Tests/U64BitflagSetTests.cs new file mode 100644 index 0000000..70b94de --- /dev/null +++ b/dotnet/Tests/U64BitflagSetTests.cs @@ -0,0 +1,67 @@ +namespace Multiflag.Tests; + +public class U64BitflagSetTests +{ + [Fact] + public void ValueNotAPowerOfTwo() + { + var flags = new U64BitflagSet(); + Assert.Throws(() => flags.Flag(0)); + Assert.Throws(() => flags.Flag(11)); + } + + [Fact] + public void Add() + { + var flags = new U64BitflagSet(); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4); + var flags2And4 = flags.Flag(flag2, flag4); + + Assert.Equal(3u, 1 + flag2); + Assert.Equal(5u, 1 + flag4); + Assert.Equal(7u, 1 + flags2And4); + } + + [Fact] + public void Remove() + { + var flags = new U64BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + + Assert.Equal(2u, 7 - flag1); + Assert.Equal(5u, 7 - flag2); + Assert.Equal(3u, 7 - flag4); + } + + [Fact] + public void IsIn() + { + var flags = new U64BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + + Assert.True(flag1.IsIn(1)); + Assert.True(flag2.IsIn(3)); + Assert.False(flag4.IsIn(4)); + Assert.True(flag4.IsIn(5)); + } + + [Fact] + public void IsAbstract() + { + var flags = new U64BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flags1And2 = flags.Flag(flag1, flag2); + var flag4 = flags.Flag(4, flags1And2); + + Assert.False(flag1.IsAbstract); + Assert.False(flag2.IsAbstract); + Assert.True(flags1And2.IsAbstract); + Assert.False(flag4.IsAbstract); + } +} \ No newline at end of file diff --git a/dotnet/Tests/U8BitflagSetTests.cs b/dotnet/Tests/U8BitflagSetTests.cs new file mode 100644 index 0000000..4e19592 --- /dev/null +++ b/dotnet/Tests/U8BitflagSetTests.cs @@ -0,0 +1,67 @@ +namespace Multiflag.Tests; + +public class U8BitflagSetTests +{ + [Fact] + public void ValueNotAPowerOfTwo() + { + var flags = new U8BitflagSet(); + Assert.Throws(() => flags.Flag(0)); + Assert.Throws(() => flags.Flag(11)); + } + + [Fact] + public void Add() + { + var flags = new U8BitflagSet(); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4); + var flags2And4 = flags.Flag(flag2, flag4); + + Assert.Equal(3, 1 + flag2); + Assert.Equal(5, 1 + flag4); + Assert.Equal(7, 1 + flags2And4); + } + + [Fact] + public void Remove() + { + var flags = new U8BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + + Assert.Equal(2, 7 - flag1); + Assert.Equal(5, 7 - flag2); + Assert.Equal(3, 7 - flag4); + } + + [Fact] + public void IsIn() + { + var flags = new U8BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flag4 = flags.Flag(4, flag1); + + Assert.True(flag1.IsIn(1)); + Assert.True(flag2.IsIn(3)); + Assert.False(flag4.IsIn(4)); + Assert.True(flag4.IsIn(5)); + } + + [Fact] + public void IsAbstract() + { + var flags = new U8BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2); + var flags1And2 = flags.Flag(flag1, flag2); + var flag4 = flags.Flag(4, flags1And2); + + Assert.False(flag1.IsAbstract); + Assert.False(flag2.IsAbstract); + Assert.True(flags1And2.IsAbstract); + Assert.False(flag4.IsAbstract); + } +} \ No newline at end of file diff --git a/dotnet/global.json b/dotnet/global.json new file mode 100644 index 0000000..a27a2b8 --- /dev/null +++ b/dotnet/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "9.0.0", + "rollForward": "latestMajor", + "allowPrerelease": false + } +} \ No newline at end of file From 935f4202b4d7f6d6b0d705ba1dac2ccec5f2879c Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 20:58:53 +0200 Subject: [PATCH 06/15] docs: added the flag API docs --- .gitignore | 4 +- docs/Multiflag docs.sublime-project | 11 +++ docs/requirements.txt | 30 +++++++ docs/source/_static/overrides.css | 3 + docs/source/common/flags.rst | 128 ++++++++++++++++++++++++++++ docs/source/common/flagsets.rst | 11 +++ docs/source/common/index.rst | 9 ++ docs/source/concepts.rst | 16 ++++ docs/source/conf.py | 15 +++- docs/source/dotnet/index.rst | 7 ++ docs/source/index.rst | 21 ++--- docs/source/node/index.rst | 7 ++ 12 files changed, 243 insertions(+), 19 deletions(-) create mode 100644 docs/Multiflag docs.sublime-project create mode 100644 docs/source/_static/overrides.css create mode 100644 docs/source/common/flags.rst create mode 100644 docs/source/common/flagsets.rst create mode 100644 docs/source/common/index.rst create mode 100644 docs/source/concepts.rst create mode 100644 docs/source/dotnet/index.rst create mode 100644 docs/source/node/index.rst diff --git a/.gitignore b/.gitignore index fdbeb9d..f4fed02 100644 --- a/.gitignore +++ b/.gitignore @@ -532,4 +532,6 @@ dist .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz -.pnp.* \ No newline at end of file +.pnp.* + +*.sublime-workspace \ No newline at end of file diff --git a/docs/Multiflag docs.sublime-project b/docs/Multiflag docs.sublime-project new file mode 100644 index 0000000..8788d4b --- /dev/null +++ b/docs/Multiflag docs.sublime-project @@ -0,0 +1,11 @@ +{ + "folders": + [ + { + "path": "source" + } + ], + "settings": { + "rulers": [80] + } +} diff --git a/docs/requirements.txt b/docs/requirements.txt index e69de29..ef5f826 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -0,0 +1,30 @@ +alabaster==1.0.0 +Babel==2.13.1 +beautifulsoup4==4.12.2 +certifi==2023.11.17 +charset-normalizer==3.3.2 +docutils==0.20.1 +furo==2024.8.6 +idna==3.6 +imagesize==1.4.1 +Jinja2==3.1.2 +lxml==4.9.3 +MarkupSafe==2.1.3 +packaging==23.2 +Pygments==2.17.2 +PyYAML==6.0.2 +requests==2.31.0 +snowballstemmer==2.2.0 +soupsieve==2.5 +Sphinx==8.1.3 +sphinx-basic-ng==1.0.0b2 +sphinx-tabs==3.4.7 +sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-devhelp==2.0.0 +sphinxcontrib-htmlhelp==2.1.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-mermaid==1.0.0 +sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-serializinghtml==1.1.9 +tomli==2.2.1 +urllib3==2.1.0 diff --git a/docs/source/_static/overrides.css b/docs/source/_static/overrides.css new file mode 100644 index 0000000..2511d13 --- /dev/null +++ b/docs/source/_static/overrides.css @@ -0,0 +1,3 @@ +.sphinx-tabs-tab { + padding: 0.5rem 1rem !important; +} diff --git a/docs/source/common/flags.rst b/docs/source/common/flags.rst new file mode 100644 index 0000000..5f603b2 --- /dev/null +++ b/docs/source/common/flags.rst @@ -0,0 +1,128 @@ +Flags +===== + +A ``Flag`` represents some element of a set. + +.. tabs:: + .. code-tab:: cs + + public class Flag + { + public virtual bool IsAbstract { get; } + + public virtual TSet AddTo(TSet flags); + + public static TSet operator +(TSet value, Flag flag); + + public virtual TSet RemoveFrom(TSet flags); + + public static TSet operator -(TSet value, Flag flag); + + public virtual bool IsIn(TSet flags); + } + + .. code-tab:: ts + + export class Flag { + public readonly isAbstract: boolean + + public addTo(flags: T): T + + public removeFrom(flags: T): T + + public isIn(flags: T): boolean + } + +Add to set +---------- + +Adds a flag and its parents to a set if they are not already present. This +operation will return a new set of flags, or the same set if it hasn't been +modified. The input set will never be modified in-place. + +.. tabs:: + .. code-tab:: cs + + var newSet = flag.AddTo(mySet); + var newSet = mySet + flag; + mySet += flag; + + .. code-tab:: ts + + const newSet = flag.addTo(mySet); + +.. versionchanged:: 2.0 + this method won't modify the set in-place anymore. +.. versionadded:: 1.0 + + +Remove from set +--------------- + +Removes a flag and any of its children that appear in a set. This operation will +return a new set of flags, or the same set if it hasn't been modified. The input +set will never be modified in-place. + +.. tabs:: + .. code-tab:: cs + + var newSet = flag.RemoveFrom(mySet); + var newSet = mySet - flag; + mySet -= flag; + + .. code-tab:: ts + + const newSet = flag.removeFrom(mySet); + +.. versionchanged:: 2.0 + this method won't modify the set in-place anymore. +.. versionadded:: 1.0 + + +Is in set +--------- + +Tests if a flag and all its parents are present in a set. + +.. tabs:: + .. code-tab:: cs + + if(flag.IsIn(mySet)) { + ... + } + + .. code-tab:: ts + + if(flag.isIn(mySet)) { + ... + } + +.. versionchanged:: 2.0 + this method is now called ``IsIn`` instead of ``In``. +.. versionadded:: 1.0 + + +Is abstract +----------- + +If this property is ``true``, it indicates that the flag has no value on its +own. + +.. tabs:: + .. code-tab:: cs + + if(flag.IsAbstract) { + ... + } + + .. code-tab:: ts + + if(flag.isAbstract) { + ... + } + +.. versionchanged:: 2.0 + a value of ``true`` is equivalent to either ``IsAbstract`` or ``IsNothing`` + being ``true`` in v1, and a value of ``false`` is equivalent to + ``IsConcrete`` being ``true``. +.. versionadded:: 1.0 \ No newline at end of file diff --git a/docs/source/common/flagsets.rst b/docs/source/common/flagsets.rst new file mode 100644 index 0000000..90b822f --- /dev/null +++ b/docs/source/common/flagsets.rst @@ -0,0 +1,11 @@ +Flagsets +======== + +A ``FlagSet`` is a group of flags that can be combined with each other. + +Declaring a flagset +------------------- + +Anonymous flagset +***************** + diff --git a/docs/source/common/index.rst b/docs/source/common/index.rst new file mode 100644 index 0000000..b4fa552 --- /dev/null +++ b/docs/source/common/index.rst @@ -0,0 +1,9 @@ +Common APIs +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + flagsets.rst + flags.rst diff --git a/docs/source/concepts.rst b/docs/source/concepts.rst new file mode 100644 index 0000000..225a3c1 --- /dev/null +++ b/docs/source/concepts.rst @@ -0,0 +1,16 @@ +Concepts +======== + +Flags hierarchy +--------------- + +.. mermaid:: + :align: center + + flowchart TD + B(("B")) --> A(("A")) + C(("C")) --> A + D(("D")) --> B + E(("E")) --> B + F(("F")) --> C + class E,B,A mmd-node-added \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index 1453ccd..b9734aa 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -18,11 +18,11 @@ # -- Project information ----------------------------------------------------- project = "Multiflag" -copyright = "2023, Louis DEVIE" +copyright = "2023-2025, Louis DEVIE" author = "Louis DEVIE" # The full version, including alpha/beta/rc tags -release = "1.0" +release = "2.0" # -- General configuration --------------------------------------------------- @@ -30,7 +30,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] +extensions = ["sphinx_tabs.tabs", "sphinxcontrib.mermaid"] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -52,3 +52,12 @@ # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] + +html_css_files = ["overrides.css"] + + +# -- reST configuration ------------------------------------------------------ + +rst_prolog = """ +.. role:: badge +""" diff --git a/docs/source/dotnet/index.rst b/docs/source/dotnet/index.rst new file mode 100644 index 0000000..08bebf9 --- /dev/null +++ b/docs/source/dotnet/index.rst @@ -0,0 +1,7 @@ +C# API +====== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + diff --git a/docs/source/index.rst b/docs/source/index.rst index 4118da2..81342a4 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,20 +1,11 @@ -.. Multiflag documentation master file, created by - sphinx-quickstart on Sat Dec 9 14:29:33 2023. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to Multiflag's documentation! -===================================== +Multiflag docs +============== .. toctree:: :maxdepth: 2 :caption: Contents: - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` + concepts + common/index.rst + dotnet/index.rst + node/index.rst diff --git a/docs/source/node/index.rst b/docs/source/node/index.rst new file mode 100644 index 0000000..e7be4c7 --- /dev/null +++ b/docs/source/node/index.rst @@ -0,0 +1,7 @@ +JavaScript API +============== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + From 72ed904101cd2b40330f9d4a5b8ff3f5a09adc1d Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 20:59:37 +0200 Subject: [PATCH 07/15] docs: change type parameter name in Flag doc comment --- dotnet/Multiflag/Flag.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dotnet/Multiflag/Flag.cs b/dotnet/Multiflag/Flag.cs index b03b38c..18a0c75 100644 --- a/dotnet/Multiflag/Flag.cs +++ b/dotnet/Multiflag/Flag.cs @@ -4,12 +4,11 @@ namespace Multiflag { /// - /// A represents some element of + /// A represents some element of /// that can be added or removed from the set. /// When a flag is added to the set, all of its parents are added along /// with it, and when it is removed all of its children are removed too. /// - /// public class Flag { private readonly ISetOperations operations; From b8690b971b6a55e839d33065131bb7803d5c6f95 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 21:17:14 +0200 Subject: [PATCH 08/15] fix(cs): fix increment of current value in `EnumFlagEnumerator` and `NumericFlagEnumerator` --- .../Enumerators/EnumFlagEnumerator.cs | 2 +- .../Enumerators/NumericFlagEnumerator.cs | 2 +- dotnet/Tests/U16BitflagSetTests.cs | 85 +++++++++++++++++++ dotnet/Tests/U32BitflagSetTests.cs | 85 +++++++++++++++++++ dotnet/Tests/U64BitflagSetTests.cs | 85 +++++++++++++++++++ dotnet/Tests/U8BitflagSetTests.cs | 85 +++++++++++++++++++ 6 files changed, 342 insertions(+), 2 deletions(-) diff --git a/dotnet/Multiflag/Enumerators/EnumFlagEnumerator.cs b/dotnet/Multiflag/Enumerators/EnumFlagEnumerator.cs index f10acfb..dd2ad81 100644 --- a/dotnet/Multiflag/Enumerators/EnumFlagEnumerator.cs +++ b/dotnet/Multiflag/Enumerators/EnumFlagEnumerator.cs @@ -41,7 +41,7 @@ public bool MoveNext() while (this.bitManipulator.IsEven(this.remaining)) { this.remaining = this.bitManipulator.ShiftRight(this.remaining); - this.current = this.bitManipulator.ShiftLeft(this.remaining); + this.current = this.bitManipulator.ShiftLeft(this.current); } // discard this bit diff --git a/dotnet/Multiflag/Enumerators/NumericFlagEnumerator.cs b/dotnet/Multiflag/Enumerators/NumericFlagEnumerator.cs index f122ceb..074e955 100644 --- a/dotnet/Multiflag/Enumerators/NumericFlagEnumerator.cs +++ b/dotnet/Multiflag/Enumerators/NumericFlagEnumerator.cs @@ -41,7 +41,7 @@ public bool MoveNext() while (this.bitManipulator.IsEven(this.remaining)) { this.remaining = this.bitManipulator.ShiftRight(this.remaining); - this.current = this.bitManipulator.ShiftLeft(this.remaining); + this.current = this.bitManipulator.ShiftLeft(this.current); } // discard this bit diff --git a/dotnet/Tests/U16BitflagSetTests.cs b/dotnet/Tests/U16BitflagSetTests.cs index 46089b2..e2de7c0 100644 --- a/dotnet/Tests/U16BitflagSetTests.cs +++ b/dotnet/Tests/U16BitflagSetTests.cs @@ -10,6 +10,91 @@ public void ValueNotAPowerOfTwo() Assert.Throws(() => flags.Flag(11)); } + [Fact] + public void Union() + { + var flags = new U16BitflagSet(); + + Assert.Equal(0, flags.Union(0, 0)); + Assert.Equal(1, flags.Union(1, 0)); + Assert.Equal(2, flags.Union(0, 2)); + Assert.Equal(3, flags.Union(1, 2)); + Assert.Equal(7, flags.Union(3, 6)); + } + + [Fact] + public void Difference() { + var flags = new U16BitflagSet(); + + Assert.Equal(0, flags.Difference(0, 0)); + Assert.Equal(1, flags.Difference(1, 0)); + Assert.Equal(1, flags.Difference(3, 6)); + Assert.Equal(4, flags.Difference(6, 3)); + Assert.Equal(8, flags.Difference(8, 17)); + } + + [Fact] + public void Intersection() + { + var flags = new U16BitflagSet(); + + Assert.Equal(0, flags.Intersection(0, 0)); + Assert.Equal(0, flags.Intersection(1, 0)); + Assert.Equal(0, flags.Intersection(1, 2)); + Assert.Equal(1, flags.Intersection(1, 3)); + Assert.Equal(1, flags.Intersection(11, 5)); + Assert.Equal(3, flags.Intersection(11, 7)); + } + + [Fact] + public void Iterate() + { + var flags = new U16BitflagSet(); + + Assert.Equal([], flags.Iterate(0)); + Assert.Equal([1], flags.Iterate(1)); + Assert.Equal([2], flags.Iterate(2)); + Assert.Equal([1, 2], flags.Iterate(3)); + Assert.Equal([1, 2, 8], flags.Iterate(11)); + Assert.Equal([4, 32, 64], flags.Iterate(100)); + } + + [Fact] + public void Minimum() + { + var flags = new U16BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0, flags.Minimum(0)); + Assert.Equal(1, flags.Minimum(1)); + Assert.Equal(0, flags.Minimum(2)); + Assert.Equal(3, flags.Minimum(3)); + Assert.Equal(3, flags.Minimum(11)); + Assert.Equal(13, flags.Minimum(13)); + Assert.Equal(1, flags.Minimum(17)); + } + + [Fact] + public void Maximum() + { + var flags = new U16BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0, flags.Maximum(0)); + Assert.Equal(1, flags.Maximum(1)); + Assert.Equal(3, flags.Maximum(2)); + Assert.Equal(3, flags.Maximum(3)); + Assert.Equal(15, flags.Maximum(11)); + Assert.Equal(13, flags.Maximum(13)); + Assert.Equal(1, flags.Maximum(17)); + } + [Fact] public void Add() { diff --git a/dotnet/Tests/U32BitflagSetTests.cs b/dotnet/Tests/U32BitflagSetTests.cs index 3e92ad7..090de55 100644 --- a/dotnet/Tests/U32BitflagSetTests.cs +++ b/dotnet/Tests/U32BitflagSetTests.cs @@ -10,6 +10,91 @@ public void ValueNotAPowerOfTwo() Assert.Throws(() => flags.Flag(11)); } + [Fact] + public void Union() + { + var flags = new U32BitflagSet(); + + Assert.Equal(0u, flags.Union(0, 0)); + Assert.Equal(1u, flags.Union(1, 0)); + Assert.Equal(2u, flags.Union(0, 2)); + Assert.Equal(3u, flags.Union(1, 2)); + Assert.Equal(7u, flags.Union(3, 6)); + } + + [Fact] + public void Difference() { + var flags = new U32BitflagSet(); + + Assert.Equal(0u, flags.Difference(0, 0)); + Assert.Equal(1u, flags.Difference(1, 0)); + Assert.Equal(1u, flags.Difference(3, 6)); + Assert.Equal(4u, flags.Difference(6, 3)); + Assert.Equal(8u, flags.Difference(8, 17)); + } + + [Fact] + public void Intersection() + { + var flags = new U32BitflagSet(); + + Assert.Equal(0u, flags.Intersection(0, 0)); + Assert.Equal(0u, flags.Intersection(1, 0)); + Assert.Equal(0u, flags.Intersection(1, 2)); + Assert.Equal(1u, flags.Intersection(1, 3)); + Assert.Equal(1u, flags.Intersection(11, 5)); + Assert.Equal(3u, flags.Intersection(11, 7)); + } + + [Fact] + public void Iterate() + { + var flags = new U32BitflagSet(); + + Assert.Equal([], flags.Iterate(0)); + Assert.Equal([1], flags.Iterate(1)); + Assert.Equal([2], flags.Iterate(2)); + Assert.Equal([1, 2], flags.Iterate(3)); + Assert.Equal([1, 2, 8], flags.Iterate(11)); + Assert.Equal([4, 32, 64], flags.Iterate(100)); + } + + [Fact] + public void Minimum() + { + var flags = new U32BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0u, flags.Minimum(0)); + Assert.Equal(1u, flags.Minimum(1)); + Assert.Equal(0u, flags.Minimum(2)); + Assert.Equal(3u, flags.Minimum(3)); + Assert.Equal(3u, flags.Minimum(11)); + Assert.Equal(13u, flags.Minimum(13)); + Assert.Equal(1u, flags.Minimum(17)); + } + + [Fact] + public void Maximum() + { + var flags = new U32BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0u, flags.Maximum(0)); + Assert.Equal(1u, flags.Maximum(1)); + Assert.Equal(3u, flags.Maximum(2)); + Assert.Equal(3u, flags.Maximum(3)); + Assert.Equal(15u, flags.Maximum(11)); + Assert.Equal(13u, flags.Maximum(13)); + Assert.Equal(1u, flags.Maximum(17)); + } + [Fact] public void Add() { diff --git a/dotnet/Tests/U64BitflagSetTests.cs b/dotnet/Tests/U64BitflagSetTests.cs index 70b94de..544e965 100644 --- a/dotnet/Tests/U64BitflagSetTests.cs +++ b/dotnet/Tests/U64BitflagSetTests.cs @@ -10,6 +10,91 @@ public void ValueNotAPowerOfTwo() Assert.Throws(() => flags.Flag(11)); } + [Fact] + public void Union() + { + var flags = new U64BitflagSet(); + + Assert.Equal(0u, flags.Union(0, 0)); + Assert.Equal(1u, flags.Union(1, 0)); + Assert.Equal(2u, flags.Union(0, 2)); + Assert.Equal(3u, flags.Union(1, 2)); + Assert.Equal(7u, flags.Union(3, 6)); + } + + [Fact] + public void Difference() { + var flags = new U64BitflagSet(); + + Assert.Equal(0u, flags.Difference(0, 0)); + Assert.Equal(1u, flags.Difference(1, 0)); + Assert.Equal(1u, flags.Difference(3, 6)); + Assert.Equal(4u, flags.Difference(6, 3)); + Assert.Equal(8u, flags.Difference(8, 17)); + } + + [Fact] + public void Intersection() + { + var flags = new U64BitflagSet(); + + Assert.Equal(0u, flags.Intersection(0, 0)); + Assert.Equal(0u, flags.Intersection(1, 0)); + Assert.Equal(0u, flags.Intersection(1, 2)); + Assert.Equal(1u, flags.Intersection(1, 3)); + Assert.Equal(1u, flags.Intersection(11, 5)); + Assert.Equal(3u, flags.Intersection(11, 7)); + } + + [Fact] + public void Iterate() + { + var flags = new U64BitflagSet(); + + Assert.Equal([], flags.Iterate(0)); + Assert.Equal([1], flags.Iterate(1)); + Assert.Equal([2], flags.Iterate(2)); + Assert.Equal([1, 2], flags.Iterate(3)); + Assert.Equal([1, 2, 8], flags.Iterate(11)); + Assert.Equal([4, 32, 64], flags.Iterate(100)); + } + + [Fact] + public void Minimum() + { + var flags = new U64BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0u, flags.Minimum(0)); + Assert.Equal(1u, flags.Minimum(1)); + Assert.Equal(0u, flags.Minimum(2)); + Assert.Equal(3u, flags.Minimum(3)); + Assert.Equal(3u, flags.Minimum(11)); + Assert.Equal(13u, flags.Minimum(13)); + Assert.Equal(1u, flags.Minimum(17)); + } + + [Fact] + public void Maximum() + { + var flags = new U64BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0u, flags.Maximum(0)); + Assert.Equal(1u, flags.Maximum(1)); + Assert.Equal(3u, flags.Maximum(2)); + Assert.Equal(3u, flags.Maximum(3)); + Assert.Equal(15u, flags.Maximum(11)); + Assert.Equal(13u, flags.Maximum(13)); + Assert.Equal(1u, flags.Maximum(17)); + } + [Fact] public void Add() { diff --git a/dotnet/Tests/U8BitflagSetTests.cs b/dotnet/Tests/U8BitflagSetTests.cs index 4e19592..84ad1c8 100644 --- a/dotnet/Tests/U8BitflagSetTests.cs +++ b/dotnet/Tests/U8BitflagSetTests.cs @@ -10,6 +10,91 @@ public void ValueNotAPowerOfTwo() Assert.Throws(() => flags.Flag(11)); } + [Fact] + public void Union() + { + var flags = new U8BitflagSet(); + + Assert.Equal(0, flags.Union(0, 0)); + Assert.Equal(1, flags.Union(1, 0)); + Assert.Equal(2, flags.Union(0, 2)); + Assert.Equal(3, flags.Union(1, 2)); + Assert.Equal(7, flags.Union(3, 6)); + } + + [Fact] + public void Difference() { + var flags = new U8BitflagSet(); + + Assert.Equal(0, flags.Difference(0, 0)); + Assert.Equal(1, flags.Difference(1, 0)); + Assert.Equal(1, flags.Difference(3, 6)); + Assert.Equal(4, flags.Difference(6, 3)); + Assert.Equal(8, flags.Difference(8, 17)); + } + + [Fact] + public void Intersection() + { + var flags = new U8BitflagSet(); + + Assert.Equal(0, flags.Intersection(0, 0)); + Assert.Equal(0, flags.Intersection(1, 0)); + Assert.Equal(0, flags.Intersection(1, 2)); + Assert.Equal(1, flags.Intersection(1, 3)); + Assert.Equal(1, flags.Intersection(11, 5)); + Assert.Equal(3, flags.Intersection(11, 7)); + } + + [Fact] + public void Iterate() + { + var flags = new U8BitflagSet(); + + Assert.Equal([], flags.Iterate(0)); + Assert.Equal([1], flags.Iterate(1)); + Assert.Equal([2], flags.Iterate(2)); + Assert.Equal([1, 2], flags.Iterate(3)); + Assert.Equal([1, 2, 8], flags.Iterate(11)); + Assert.Equal([4, 32, 64], flags.Iterate(100)); + } + + [Fact] + public void Minimum() + { + var flags = new U8BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0, flags.Minimum(0)); + Assert.Equal(1, flags.Minimum(1)); + Assert.Equal(0, flags.Minimum(2)); + Assert.Equal(3, flags.Minimum(3)); + Assert.Equal(3, flags.Minimum(11)); + Assert.Equal(13, flags.Minimum(13)); + Assert.Equal(1, flags.Minimum(17)); + } + + [Fact] + public void Maximum() + { + var flags = new U8BitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0, flags.Maximum(0)); + Assert.Equal(1, flags.Maximum(1)); + Assert.Equal(3, flags.Maximum(2)); + Assert.Equal(3, flags.Maximum(3)); + Assert.Equal(15, flags.Maximum(11)); + Assert.Equal(13, flags.Maximum(13)); + Assert.Equal(1, flags.Maximum(17)); + } + [Fact] public void Add() { From 59986cc29ff05afdab774f63b27e69d26b25acfa Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 21:18:51 +0200 Subject: [PATCH 09/15] ci(cs): update tests to build solution without warnings --- .github/workflows/tests.yml | 2 ++ dotnet/Multiflag.sln | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 059a8c3..d62ca6a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,6 +21,8 @@ jobs: dotnet-version: 7.x - name: Restore dependencies run: dotnet restore + - name: Build solution + run: dotnet build /warnaserror - name: Run tests run: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput='../coverage.xml' - name: Report coverage diff --git a/dotnet/Multiflag.sln b/dotnet/Multiflag.sln index a78a811..7d2ab1b 100644 --- a/dotnet/Multiflag.sln +++ b/dotnet/Multiflag.sln @@ -11,6 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Éléments de solution", " ProjectSection(SolutionItems) = preProject README.md = README.md ..\.github\workflows\tests.yml = ..\.github\workflows\tests.yml + ..\.github\workflows\publish.yml = ..\.github\workflows\publish.yml EndProjectSection EndProject Global From 82fa84c7a659d8dead0e6b10a86288ee8a1364d6 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 21:21:47 +0200 Subject: [PATCH 10/15] ci: update dotnet version to 9.x --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d62ca6a..4594b65 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,7 +18,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 7.x + dotnet-version: 9.x - name: Restore dependencies run: dotnet restore - name: Build solution From d657484a24c12cb05b990df646cbb85de777eb92 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 21:26:28 +0200 Subject: [PATCH 11/15] docs: update doc comments of exception and remove unused `InvalidHashSetValueException` --- dotnet/Multiflag/InvalidHashSetValueException.cs | 15 --------------- dotnet/Multiflag/ReusedFlagValueException.cs | 4 ++-- dotnet/Multiflag/UnsupportedEnumTypeException.cs | 2 +- 3 files changed, 3 insertions(+), 18 deletions(-) delete mode 100644 dotnet/Multiflag/InvalidHashSetValueException.cs diff --git a/dotnet/Multiflag/InvalidHashSetValueException.cs b/dotnet/Multiflag/InvalidHashSetValueException.cs deleted file mode 100644 index b85654a..0000000 --- a/dotnet/Multiflag/InvalidHashSetValueException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Multiflag -{ - /// - /// Exception thrown by FlagSets that represents the flags using hash sets when a flag value - /// does not contain exactly one element. - /// - public class InvalidHashSetValueException : ArgumentException - { - internal InvalidHashSetValueException() : base("Flag values for hash sets must contain exactly one value.") - { - } - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/ReusedFlagValueException.cs b/dotnet/Multiflag/ReusedFlagValueException.cs index e63725f..517ff18 100644 --- a/dotnet/Multiflag/ReusedFlagValueException.cs +++ b/dotnet/Multiflag/ReusedFlagValueException.cs @@ -3,8 +3,8 @@ namespace Multiflag { /// - /// Exception thrown if the method is called - /// with a value that was already used for another flag in the same . + /// Exception thrown if the method is called + /// with a value that was already used for another flag in the same . /// public class ReusedFlagValueException : ArgumentException { diff --git a/dotnet/Multiflag/UnsupportedEnumTypeException.cs b/dotnet/Multiflag/UnsupportedEnumTypeException.cs index a2cae44..939b0f7 100644 --- a/dotnet/Multiflag/UnsupportedEnumTypeException.cs +++ b/dotnet/Multiflag/UnsupportedEnumTypeException.cs @@ -3,7 +3,7 @@ namespace Multiflag { /// - /// Exception thrown when an is intanciated with an enumeration type + /// Exception thrown when an is instantiated with an enumeration type /// that is not backed by one of , , or /// . /// From 9037564a62f9624efb7c8dd5a43f85c5e1bd1c79 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 21:27:34 +0200 Subject: [PATCH 12/15] docs: fix another reference to `FlagSet` --- dotnet/Multiflag/ForeignFlagException.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/Multiflag/ForeignFlagException.cs b/dotnet/Multiflag/ForeignFlagException.cs index 934986d..3a795aa 100644 --- a/dotnet/Multiflag/ForeignFlagException.cs +++ b/dotnet/Multiflag/ForeignFlagException.cs @@ -4,7 +4,7 @@ namespace Multiflag { /// /// Exception thrown when a flag is associated with another one - /// that was created from a different . + /// that was created from a different . /// public class ForeignFlagException : ArgumentException { From 34f11e4e144325417af32a328ec3b4894483ddf4 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 21:39:21 +0200 Subject: [PATCH 13/15] ci: distribution to nuget.org --- .github/workflows/publish.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 284b7cd..6c1d729 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -6,6 +6,25 @@ on: - '**' jobs: + publish-nuget: + if: ${{ startsWith(github.ref, 'refs/tags/dotnet/') }} + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./dotnet + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 9.x + - name: Restore dependencies + run: dotnet restore + - name: Package C# library + run: dotnet pack Multiflag -c Release -o ./pkg + - name: Push to nuget.org + run: dotnet nuget push ./pkg/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json + publish-npm: if: ${{ startsWith(github.ref, 'refs/tags/node/') }} runs-on: ubuntu-latest From 69cbc064dbaa8bca4a98e8341689f69f085bce44 Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 21:55:58 +0200 Subject: [PATCH 14/15] feat(dotnet): drop support for 8 and 16-bit bitflags --- README.md | 17 +- dotnet/Multiflag/Base64BitflagSet.cs | 2 - .../Bitflags/BigintBitManipulator.cs | 1 - dotnet/Multiflag/Bitflags/BitManipulator.cs | 2 - .../Multiflag/Bitflags/U16BitManipulator.cs | 56 ------- dotnet/Multiflag/Bitflags/U8BitManipulator.cs | 56 ------- dotnet/Multiflag/EnumBitflagSet.cs | 33 +--- dotnet/Multiflag/FlagSet.cs | 1 - dotnet/Multiflag/U16BitflagSet.cs | 58 ------- dotnet/Multiflag/U8BitflagSet.cs | 58 ------- dotnet/Multiflag/ValueFlag.cs | 1 - dotnet/Tests/FlagSetTests.cs | 6 +- dotnet/Tests/FlagTests.cs | 106 ++++++------ dotnet/Tests/U16BitflagSetTests.cs | 152 ------------------ dotnet/Tests/U8BitflagSetTests.cs | 152 ------------------ 15 files changed, 69 insertions(+), 632 deletions(-) delete mode 100644 dotnet/Multiflag/Bitflags/U16BitManipulator.cs delete mode 100644 dotnet/Multiflag/Bitflags/U8BitManipulator.cs delete mode 100644 dotnet/Multiflag/U16BitflagSet.cs delete mode 100644 dotnet/Multiflag/U8BitflagSet.cs delete mode 100644 dotnet/Tests/U16BitflagSetTests.cs delete mode 100644 dotnet/Tests/U8BitflagSetTests.cs diff --git a/README.md b/README.md index 96de7c6..f26a34e 100644 --- a/README.md +++ b/README.md @@ -27,16 +27,13 @@ This covers most of the common needs, but you can subclass `FlagSet` to work wit ## Compatible flag types -| .NET | JS | .NET (v1) | JS (v1) | -|:---------------------------------------------------------:|:----------------------------------------:|:----------:|:------------:| -| `U8BitflagSet`
`EnumBitflagSet` backed by `byte` | `NumberBitflagSet` | `Flag8` | `NumberFlag` | -| `U16BitflagSet`
`EnumBitflagSet` backed by `ushort` | `NumberBitflagSet` | `Flag16` | `NumberFlag` | -| `U32BitflagSet`
`EnumBitflagSet` backed by `uint` | `NumberBitflagSet` | `Flag32` | `NumberFlag` | -| `U64BitflagSet`
`EnumBitflagSet` backed by `ulong` | `DynamicBitflagSet` | `Flag64` | ✗ | -| `DynamicBitflagSet` | `DynamicBitflagSet` | ✗ | ✗ | -| `Base64BitflagSet` | `Base64BitflagSet` | ✗ | ✗ | -| `CollectionFlagSet`
`ListFlagSet` | `CollectionFlagSet`
`ArrayFlagSet` | `FlagSet` | `ArrayFlag` | -| ✗ | `NumberBitflagSet` | `FlagEnum` | `NumberFlag` | +| .NET | JS | .NET (v1) | JS (v1) | +|:---------------------------------------------------------:|:----------------------------------------:|:-------------------------------------:|:------------:| +| `U32BitflagSet`
`EnumBitflagSet` backed by `uint` | `NumberBitflagSet` | `Flag8`
`Flag16`
`Flag32` | `NumberFlag` | +| `U64BitflagSet`
`EnumBitflagSet` backed by `ulong` | `DynamicBitflagSet` | `Flag64` | ✗ | +| `DynamicBitflagSet` | `DynamicBitflagSet` | ✗ | ✗ | +| `Base64BitflagSet` | `Base64BitflagSet` | ✗ | ✗ | +| `CollectionFlagSet`
`ListFlagSet` | `CollectionFlagSet`
`ArrayFlagSet` | `FlagSet` | `ArrayFlag` | ## Why it exists diff --git a/dotnet/Multiflag/Base64BitflagSet.cs b/dotnet/Multiflag/Base64BitflagSet.cs index 73d322a..f5d5c29 100644 --- a/dotnet/Multiflag/Base64BitflagSet.cs +++ b/dotnet/Multiflag/Base64BitflagSet.cs @@ -1,7 +1,5 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Linq; using Multiflag.Base64Format; using Multiflag.Enumerators; diff --git a/dotnet/Multiflag/Bitflags/BigintBitManipulator.cs b/dotnet/Multiflag/Bitflags/BigintBitManipulator.cs index b2714c3..7b5251b 100644 --- a/dotnet/Multiflag/Bitflags/BigintBitManipulator.cs +++ b/dotnet/Multiflag/Bitflags/BigintBitManipulator.cs @@ -1,4 +1,3 @@ -using System; using System.Numerics; namespace Multiflag.Bitflags diff --git a/dotnet/Multiflag/Bitflags/BitManipulator.cs b/dotnet/Multiflag/Bitflags/BitManipulator.cs index f96c8ea..9370245 100644 --- a/dotnet/Multiflag/Bitflags/BitManipulator.cs +++ b/dotnet/Multiflag/Bitflags/BitManipulator.cs @@ -1,5 +1,3 @@ -using System.Numerics; - namespace Multiflag.Bitflags { internal abstract class BitManipulator : IBitManipulator diff --git a/dotnet/Multiflag/Bitflags/U16BitManipulator.cs b/dotnet/Multiflag/Bitflags/U16BitManipulator.cs deleted file mode 100644 index cefa12a..0000000 --- a/dotnet/Multiflag/Bitflags/U16BitManipulator.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace Multiflag.Bitflags -{ - internal class U16BitManipulator : BitManipulator - { - private static U16BitManipulator? current; - - private U16BitManipulator() - { - } - - public static U16BitManipulator Current => current ??= new U16BitManipulator(); - - public override ushort Zero => 0; - - public override ushort One => 1; - - public override bool IsZero(ushort value) => value == 0; - - public override bool IsEven(ushort value) => (value & 1) == 0; - - protected override bool IsPowerOfTwo(ushort value) - { - return value != 0 && (value & value - 1) == 0; - } - - public override ushort ShiftLeft(ushort value) - { - return (ushort)(value << 1); - } - - public override ushort ShiftRight(ushort value) - { - return (ushort)(value >> 1); - } - - public override ushort BitwiseOr(ushort first, ushort second) - { - return (ushort)(first | second); - } - - public override ushort BitwiseAnd(ushort first, ushort second) - { - return (ushort)(first & second); - } - - public override ushort BitwiseAndNot(ushort first, ushort second) - { - return (ushort)(first & ~second); - } - - public override bool BitwiseAndEquals(ushort first, ushort second) - { - return (first & second) == second; - } - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/Bitflags/U8BitManipulator.cs b/dotnet/Multiflag/Bitflags/U8BitManipulator.cs deleted file mode 100644 index 5ec9f6c..0000000 --- a/dotnet/Multiflag/Bitflags/U8BitManipulator.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace Multiflag.Bitflags -{ - internal class U8BitManipulator : BitManipulator - { - private static U8BitManipulator? current; - - private U8BitManipulator() - { - } - - public static U8BitManipulator Current => current ??= new U8BitManipulator(); - - public override byte Zero => 0; - - public override byte One => 1; - - public override bool IsZero(byte value) => value == 0; - - public override bool IsEven(byte value) => (value & 1) == 0; - - protected override bool IsPowerOfTwo(byte value) - { - return value != 0 && (value & value - 1) == 0; - } - - public override byte ShiftLeft(byte value) - { - return (byte)(value << 1); - } - - public override byte ShiftRight(byte value) - { - return (byte)(value >> 1); - } - - public override byte BitwiseOr(byte first, byte second) - { - return (byte)(first | second); - } - - public override byte BitwiseAnd(byte first, byte second) - { - return (byte)(first & second); - } - - public override byte BitwiseAndNot(byte first, byte second) - { - return (byte)(first & ~second); - } - - public override bool BitwiseAndEquals(byte first, byte second) - { - return (first & second) == second; - } - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/EnumBitflagSet.cs b/dotnet/Multiflag/EnumBitflagSet.cs index d28c0a2..1629136 100644 --- a/dotnet/Multiflag/EnumBitflagSet.cs +++ b/dotnet/Multiflag/EnumBitflagSet.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Numerics; using Multiflag.Bitflags; using Multiflag.Enumerators; @@ -32,41 +31,21 @@ public EnumBitflagSet() private static IBitManipulator FindBitManipulator(Type underlyingType) { - if (underlyingType == typeof(sbyte)) - { - throw new UnsupportedEnumTypeException(underlyingType, "byte"); - } - else if (underlyingType == typeof(byte)) - { - return U8BitManipulator.Current; - } - else if (underlyingType == typeof(short)) - { - throw new UnsupportedEnumTypeException(underlyingType, "ushort"); - } - else if (underlyingType == typeof(ushort)) - { - return U16BitManipulator.Current; - } - else if (underlyingType == typeof(int)) - { - throw new UnsupportedEnumTypeException(underlyingType, "uint"); - } - else if (underlyingType == typeof(uint)) + if (underlyingType == typeof(uint)) { return U32BitManipulator.Current; } - else if (underlyingType == typeof(long)) - { - throw new UnsupportedEnumTypeException(underlyingType, "ulong"); - } else if (underlyingType == typeof(ulong)) { return U64BitManipulator.Current; } + else if (underlyingType == typeof(long)) + { + throw new UnsupportedEnumTypeException(underlyingType, "ulong"); + } else { - throw new UnsupportedEnumTypeException(underlyingType); + throw new UnsupportedEnumTypeException(underlyingType, "uint"); } } diff --git a/dotnet/Multiflag/FlagSet.cs b/dotnet/Multiflag/FlagSet.cs index c22f899..32f59bf 100644 --- a/dotnet/Multiflag/FlagSet.cs +++ b/dotnet/Multiflag/FlagSet.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; namespace Multiflag diff --git a/dotnet/Multiflag/U16BitflagSet.cs b/dotnet/Multiflag/U16BitflagSet.cs deleted file mode 100644 index 3f1a498..0000000 --- a/dotnet/Multiflag/U16BitflagSet.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Collections.Generic; -using Multiflag.Bitflags; -using Multiflag.Enumerators; - -namespace Multiflag -{ - /// - /// Provides bitflags based on 16-bit unsigned integers (thus allowing 16 different flags). - /// - public class U16BitflagSet : FlagSet - { - /// - protected override sealed ushort WrapValue(ushort value) - { - U16BitManipulator.Current.CheckPowerOfTwo(value); - return value; - } - - /// - public override sealed ushort Empty() - { - return U16BitManipulator.Current.Zero; - } - - /// - public override sealed ushort Union(ushort first, ushort second) - { - return U16BitManipulator.Current.BitwiseOr(first, second); - } - - /// - public override sealed ushort Intersection(ushort first, ushort second) - { - return U16BitManipulator.Current.BitwiseAnd(first, second); - } - - /// - public override sealed ushort Difference(ushort first, ushort second) - { - return U16BitManipulator.Current.BitwiseAndNot(first, second); - } - - /// - public override sealed bool IsSupersetOf(ushort first, ushort second) - { - return U16BitManipulator.Current.BitwiseAndEquals(first, second); - } - - /// - public override IEnumerable Iterate(ushort flags) - { - return new NumericFlagEnumerator( - U16BitManipulator.Current, - flags - ); - } - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/U8BitflagSet.cs b/dotnet/Multiflag/U8BitflagSet.cs deleted file mode 100644 index 1b754fb..0000000 --- a/dotnet/Multiflag/U8BitflagSet.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Collections.Generic; -using Multiflag.Bitflags; -using Multiflag.Enumerators; - -namespace Multiflag -{ - /// - /// Provides bitflags based on 8-bit unsigned integers (thus allowing 8 different flags). - /// - public class U8BitflagSet : FlagSet - { - /// - protected override sealed byte WrapValue(byte value) - { - U8BitManipulator.Current.CheckPowerOfTwo(value); - return value; - } - - /// - public override sealed byte Empty() - { - return U8BitManipulator.Current.Zero; - } - - /// - public override sealed byte Union(byte first, byte second) - { - return U8BitManipulator.Current.BitwiseOr(first, second); - } - - /// - public override sealed byte Intersection(byte first, byte second) - { - return U8BitManipulator.Current.BitwiseAnd(first, second); - } - - /// - public override sealed byte Difference(byte first, byte second) - { - return U8BitManipulator.Current.BitwiseAndNot(first, second); - } - - /// - public override sealed bool IsSupersetOf(byte first, byte second) - { - return U8BitManipulator.Current.BitwiseAndEquals(first, second); - } - - /// - public override IEnumerable Iterate(byte flags) - { - return new NumericFlagEnumerator( - U8BitManipulator.Current, - flags - ); - } - } -} \ No newline at end of file diff --git a/dotnet/Multiflag/ValueFlag.cs b/dotnet/Multiflag/ValueFlag.cs index b9b1cca..30ea3d9 100644 --- a/dotnet/Multiflag/ValueFlag.cs +++ b/dotnet/Multiflag/ValueFlag.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; namespace Multiflag { diff --git a/dotnet/Tests/FlagSetTests.cs b/dotnet/Tests/FlagSetTests.cs index 76f6467..4e44ec2 100644 --- a/dotnet/Tests/FlagSetTests.cs +++ b/dotnet/Tests/FlagSetTests.cs @@ -5,17 +5,17 @@ public class FlagSetTests [Fact] public void UseFlagFromOtherSetAsParent() { - var flags = new U8BitflagSet(); + var flags = new U32BitflagSet(); var flag = flags.Flag(1); - var otherFlags = new U8BitflagSet(); + var otherFlags = new U32BitflagSet(); Assert.Throws(() => otherFlags.Flag(2, flag)); } [Fact] public void UseSameValueTwice() { - var flags = new U8BitflagSet(); + var flags = new U32BitflagSet(); var flag = flags.Flag(1); Assert.Throws(() => flags.Flag(1, flag)); } diff --git a/dotnet/Tests/FlagTests.cs b/dotnet/Tests/FlagTests.cs index 69a12e6..910c1dd 100644 --- a/dotnet/Tests/FlagTests.cs +++ b/dotnet/Tests/FlagTests.cs @@ -5,81 +5,81 @@ public class FlagTests [Fact] public void AddTo() { - Assert.Equal(1, MyBitflags.Current.FlagA.AddTo(0)); - Assert.Equal(3, MyBitflags.Current.FlagA.AddTo(2)); - Assert.Equal(7, MyBitflags.Current.FlagA.AddTo(7)); + Assert.Equal(1u, MyBitflags.Current.FlagA.AddTo(0)); + Assert.Equal(3u, MyBitflags.Current.FlagA.AddTo(2)); + Assert.Equal(7u, MyBitflags.Current.FlagA.AddTo(7)); - Assert.Equal(2, MyBitflags.Current.FlagB.AddTo(0)); - Assert.Equal(2, MyBitflags.Current.FlagB.AddTo(2)); - Assert.Equal(7, MyBitflags.Current.FlagB.AddTo(7)); + Assert.Equal(2u, MyBitflags.Current.FlagB.AddTo(0)); + Assert.Equal(2u, MyBitflags.Current.FlagB.AddTo(2)); + Assert.Equal(7u, MyBitflags.Current.FlagB.AddTo(7)); - Assert.Equal(3, MyBitflags.Current.FlagC.AddTo(0)); - Assert.Equal(3, MyBitflags.Current.FlagC.AddTo(2)); - Assert.Equal(7, MyBitflags.Current.FlagC.AddTo(7)); + Assert.Equal(3u, MyBitflags.Current.FlagC.AddTo(0)); + Assert.Equal(3u, MyBitflags.Current.FlagC.AddTo(2)); + Assert.Equal(7u, MyBitflags.Current.FlagC.AddTo(7)); - Assert.Equal(7, MyBitflags.Current.FlagD.AddTo(2)); - Assert.Equal(5, MyBitflags.Current.FlagD.AddTo(0)); - Assert.Equal(7, MyBitflags.Current.FlagD.AddTo(7)); + Assert.Equal(7u, MyBitflags.Current.FlagD.AddTo(2)); + Assert.Equal(5u, MyBitflags.Current.FlagD.AddTo(0)); + Assert.Equal(7u, MyBitflags.Current.FlagD.AddTo(7)); } [Fact] public void Addition() { - Assert.Equal(1, 0 + MyBitflags.Current.FlagA); - Assert.Equal(3, 2 + MyBitflags.Current.FlagA); - Assert.Equal(7, 7 + MyBitflags.Current.FlagA); + Assert.Equal(1u, 0 + MyBitflags.Current.FlagA); + Assert.Equal(3u, 2 + MyBitflags.Current.FlagA); + Assert.Equal(7u, 7 + MyBitflags.Current.FlagA); - Assert.Equal(2, 0 + MyBitflags.Current.FlagB); - Assert.Equal(2, 2 + MyBitflags.Current.FlagB); - Assert.Equal(7, 7 + MyBitflags.Current.FlagB); + Assert.Equal(2u, 0 + MyBitflags.Current.FlagB); + Assert.Equal(2u, 2 + MyBitflags.Current.FlagB); + Assert.Equal(7u, 7 + MyBitflags.Current.FlagB); - Assert.Equal(3, 0 + MyBitflags.Current.FlagC); - Assert.Equal(3, 2 + MyBitflags.Current.FlagC); - Assert.Equal(7, 7 + MyBitflags.Current.FlagC); + Assert.Equal(3u, 0 + MyBitflags.Current.FlagC); + Assert.Equal(3u, 2 + MyBitflags.Current.FlagC); + Assert.Equal(7u, 7 + MyBitflags.Current.FlagC); - Assert.Equal(7, 2 + MyBitflags.Current.FlagD); - Assert.Equal(5, 0 + MyBitflags.Current.FlagD); - Assert.Equal(7, 7 + MyBitflags.Current.FlagD); + Assert.Equal(7u, 2 + MyBitflags.Current.FlagD); + Assert.Equal(5u, 0 + MyBitflags.Current.FlagD); + Assert.Equal(7u, 7 + MyBitflags.Current.FlagD); } [Fact] public void RemoveFrom() { - Assert.Equal(0, MyBitflags.Current.FlagA.RemoveFrom(0)); - Assert.Equal(2, MyBitflags.Current.FlagA.RemoveFrom(2)); - Assert.Equal(2, MyBitflags.Current.FlagA.RemoveFrom(7)); + Assert.Equal(0u, MyBitflags.Current.FlagA.RemoveFrom(0)); + Assert.Equal(2u, MyBitflags.Current.FlagA.RemoveFrom(2)); + Assert.Equal(2u, MyBitflags.Current.FlagA.RemoveFrom(7)); - Assert.Equal(0, MyBitflags.Current.FlagB.RemoveFrom(0)); - Assert.Equal(0, MyBitflags.Current.FlagB.RemoveFrom(2)); - Assert.Equal(5, MyBitflags.Current.FlagB.RemoveFrom(7)); + Assert.Equal(0u, MyBitflags.Current.FlagB.RemoveFrom(0)); + Assert.Equal(0u, MyBitflags.Current.FlagB.RemoveFrom(2)); + Assert.Equal(5u, MyBitflags.Current.FlagB.RemoveFrom(7)); - Assert.Equal(0, MyBitflags.Current.FlagC.RemoveFrom(0)); - Assert.Equal(2, MyBitflags.Current.FlagC.RemoveFrom(2)); - Assert.Equal(7, MyBitflags.Current.FlagC.RemoveFrom(7)); + Assert.Equal(0u, MyBitflags.Current.FlagC.RemoveFrom(0)); + Assert.Equal(2u, MyBitflags.Current.FlagC.RemoveFrom(2)); + Assert.Equal(7u, MyBitflags.Current.FlagC.RemoveFrom(7)); - Assert.Equal(2, MyBitflags.Current.FlagD.RemoveFrom(2)); - Assert.Equal(0, MyBitflags.Current.FlagD.RemoveFrom(0)); - Assert.Equal(3, MyBitflags.Current.FlagD.RemoveFrom(7)); + Assert.Equal(2u, MyBitflags.Current.FlagD.RemoveFrom(2)); + Assert.Equal(0u, MyBitflags.Current.FlagD.RemoveFrom(0)); + Assert.Equal(3u, MyBitflags.Current.FlagD.RemoveFrom(7)); } [Fact] public void Subtraction() { - Assert.Equal(0, 0 - MyBitflags.Current.FlagA); - Assert.Equal(2, 2 - MyBitflags.Current.FlagA); - Assert.Equal(2, 7 - MyBitflags.Current.FlagA); + Assert.Equal(0u, 0 - MyBitflags.Current.FlagA); + Assert.Equal(2u, 2 - MyBitflags.Current.FlagA); + Assert.Equal(2u, 7 - MyBitflags.Current.FlagA); - Assert.Equal(0, 0 - MyBitflags.Current.FlagB); - Assert.Equal(0, 2 - MyBitflags.Current.FlagB); - Assert.Equal(5, 7 - MyBitflags.Current.FlagB); + Assert.Equal(0u, 0 - MyBitflags.Current.FlagB); + Assert.Equal(0u, 2 - MyBitflags.Current.FlagB); + Assert.Equal(5u, 7 - MyBitflags.Current.FlagB); - Assert.Equal(0, 0 - MyBitflags.Current.FlagC); - Assert.Equal(2, 2 - MyBitflags.Current.FlagC); - Assert.Equal(7, 7 - MyBitflags.Current.FlagC); + Assert.Equal(0u, 0 - MyBitflags.Current.FlagC); + Assert.Equal(2u, 2 - MyBitflags.Current.FlagC); + Assert.Equal(7u, 7 - MyBitflags.Current.FlagC); - Assert.Equal(0, 0 - MyBitflags.Current.FlagD); - Assert.Equal(2, 2 - MyBitflags.Current.FlagD); - Assert.Equal(3, 7 - MyBitflags.Current.FlagD); + Assert.Equal(0u, 0 - MyBitflags.Current.FlagD); + Assert.Equal(2u, 2 - MyBitflags.Current.FlagD); + Assert.Equal(3u, 7 - MyBitflags.Current.FlagD); } [Fact] @@ -119,7 +119,7 @@ public void IsAbstract() Assert.False(MyBitflags.Current.FlagD.IsAbstract); } - private class MyBitflags : U8BitflagSet + private class MyBitflags : U32BitflagSet { private static MyBitflags? current; @@ -133,9 +133,9 @@ private MyBitflags() public static MyBitflags Current => current ??= new MyBitflags(); - public Flag FlagA { get; } - public Flag FlagB { get; } - public Flag FlagC { get; } - public Flag FlagD { get; } + public Flag FlagA { get; } + public Flag FlagB { get; } + public Flag FlagC { get; } + public Flag FlagD { get; } } } \ No newline at end of file diff --git a/dotnet/Tests/U16BitflagSetTests.cs b/dotnet/Tests/U16BitflagSetTests.cs deleted file mode 100644 index e2de7c0..0000000 --- a/dotnet/Tests/U16BitflagSetTests.cs +++ /dev/null @@ -1,152 +0,0 @@ -namespace Multiflag.Tests; - -public class U16BitflagSetTests -{ - [Fact] - public void ValueNotAPowerOfTwo() - { - var flags = new U16BitflagSet(); - Assert.Throws(() => flags.Flag(0)); - Assert.Throws(() => flags.Flag(11)); - } - - [Fact] - public void Union() - { - var flags = new U16BitflagSet(); - - Assert.Equal(0, flags.Union(0, 0)); - Assert.Equal(1, flags.Union(1, 0)); - Assert.Equal(2, flags.Union(0, 2)); - Assert.Equal(3, flags.Union(1, 2)); - Assert.Equal(7, flags.Union(3, 6)); - } - - [Fact] - public void Difference() { - var flags = new U16BitflagSet(); - - Assert.Equal(0, flags.Difference(0, 0)); - Assert.Equal(1, flags.Difference(1, 0)); - Assert.Equal(1, flags.Difference(3, 6)); - Assert.Equal(4, flags.Difference(6, 3)); - Assert.Equal(8, flags.Difference(8, 17)); - } - - [Fact] - public void Intersection() - { - var flags = new U16BitflagSet(); - - Assert.Equal(0, flags.Intersection(0, 0)); - Assert.Equal(0, flags.Intersection(1, 0)); - Assert.Equal(0, flags.Intersection(1, 2)); - Assert.Equal(1, flags.Intersection(1, 3)); - Assert.Equal(1, flags.Intersection(11, 5)); - Assert.Equal(3, flags.Intersection(11, 7)); - } - - [Fact] - public void Iterate() - { - var flags = new U16BitflagSet(); - - Assert.Equal([], flags.Iterate(0)); - Assert.Equal([1], flags.Iterate(1)); - Assert.Equal([2], flags.Iterate(2)); - Assert.Equal([1, 2], flags.Iterate(3)); - Assert.Equal([1, 2, 8], flags.Iterate(11)); - Assert.Equal([4, 32, 64], flags.Iterate(100)); - } - - [Fact] - public void Minimum() - { - var flags = new U16BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2, flag1); - var flag4 = flags.Flag(4, flag1); - var flag8 = flags.Flag(8, flag4); - - Assert.Equal(0, flags.Minimum(0)); - Assert.Equal(1, flags.Minimum(1)); - Assert.Equal(0, flags.Minimum(2)); - Assert.Equal(3, flags.Minimum(3)); - Assert.Equal(3, flags.Minimum(11)); - Assert.Equal(13, flags.Minimum(13)); - Assert.Equal(1, flags.Minimum(17)); - } - - [Fact] - public void Maximum() - { - var flags = new U16BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2, flag1); - var flag4 = flags.Flag(4, flag1); - var flag8 = flags.Flag(8, flag4); - - Assert.Equal(0, flags.Maximum(0)); - Assert.Equal(1, flags.Maximum(1)); - Assert.Equal(3, flags.Maximum(2)); - Assert.Equal(3, flags.Maximum(3)); - Assert.Equal(15, flags.Maximum(11)); - Assert.Equal(13, flags.Maximum(13)); - Assert.Equal(1, flags.Maximum(17)); - } - - [Fact] - public void Add() - { - var flags = new U16BitflagSet(); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4); - var flags2And4 = flags.Flag(flag2, flag4); - - Assert.Equal(3, 1 + flag2); - Assert.Equal(5, 1 + flag4); - Assert.Equal(7, 1 + flags2And4); - } - - [Fact] - public void Remove() - { - var flags = new U16BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.Equal(2, 7 - flag1); - Assert.Equal(5, 7 - flag2); - Assert.Equal(3, 7 - flag4); - } - - [Fact] - public void IsIn() - { - var flags = new U16BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.True(flag1.IsIn(1)); - Assert.True(flag2.IsIn(3)); - Assert.False(flag4.IsIn(4)); - Assert.True(flag4.IsIn(5)); - } - - [Fact] - public void IsAbstract() - { - var flags = new U16BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flags1And2 = flags.Flag(flag1, flag2); - var flag4 = flags.Flag(4, flags1And2); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.True(flags1And2.IsAbstract); - Assert.False(flag4.IsAbstract); - } -} \ No newline at end of file diff --git a/dotnet/Tests/U8BitflagSetTests.cs b/dotnet/Tests/U8BitflagSetTests.cs deleted file mode 100644 index 84ad1c8..0000000 --- a/dotnet/Tests/U8BitflagSetTests.cs +++ /dev/null @@ -1,152 +0,0 @@ -namespace Multiflag.Tests; - -public class U8BitflagSetTests -{ - [Fact] - public void ValueNotAPowerOfTwo() - { - var flags = new U8BitflagSet(); - Assert.Throws(() => flags.Flag(0)); - Assert.Throws(() => flags.Flag(11)); - } - - [Fact] - public void Union() - { - var flags = new U8BitflagSet(); - - Assert.Equal(0, flags.Union(0, 0)); - Assert.Equal(1, flags.Union(1, 0)); - Assert.Equal(2, flags.Union(0, 2)); - Assert.Equal(3, flags.Union(1, 2)); - Assert.Equal(7, flags.Union(3, 6)); - } - - [Fact] - public void Difference() { - var flags = new U8BitflagSet(); - - Assert.Equal(0, flags.Difference(0, 0)); - Assert.Equal(1, flags.Difference(1, 0)); - Assert.Equal(1, flags.Difference(3, 6)); - Assert.Equal(4, flags.Difference(6, 3)); - Assert.Equal(8, flags.Difference(8, 17)); - } - - [Fact] - public void Intersection() - { - var flags = new U8BitflagSet(); - - Assert.Equal(0, flags.Intersection(0, 0)); - Assert.Equal(0, flags.Intersection(1, 0)); - Assert.Equal(0, flags.Intersection(1, 2)); - Assert.Equal(1, flags.Intersection(1, 3)); - Assert.Equal(1, flags.Intersection(11, 5)); - Assert.Equal(3, flags.Intersection(11, 7)); - } - - [Fact] - public void Iterate() - { - var flags = new U8BitflagSet(); - - Assert.Equal([], flags.Iterate(0)); - Assert.Equal([1], flags.Iterate(1)); - Assert.Equal([2], flags.Iterate(2)); - Assert.Equal([1, 2], flags.Iterate(3)); - Assert.Equal([1, 2, 8], flags.Iterate(11)); - Assert.Equal([4, 32, 64], flags.Iterate(100)); - } - - [Fact] - public void Minimum() - { - var flags = new U8BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2, flag1); - var flag4 = flags.Flag(4, flag1); - var flag8 = flags.Flag(8, flag4); - - Assert.Equal(0, flags.Minimum(0)); - Assert.Equal(1, flags.Minimum(1)); - Assert.Equal(0, flags.Minimum(2)); - Assert.Equal(3, flags.Minimum(3)); - Assert.Equal(3, flags.Minimum(11)); - Assert.Equal(13, flags.Minimum(13)); - Assert.Equal(1, flags.Minimum(17)); - } - - [Fact] - public void Maximum() - { - var flags = new U8BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2, flag1); - var flag4 = flags.Flag(4, flag1); - var flag8 = flags.Flag(8, flag4); - - Assert.Equal(0, flags.Maximum(0)); - Assert.Equal(1, flags.Maximum(1)); - Assert.Equal(3, flags.Maximum(2)); - Assert.Equal(3, flags.Maximum(3)); - Assert.Equal(15, flags.Maximum(11)); - Assert.Equal(13, flags.Maximum(13)); - Assert.Equal(1, flags.Maximum(17)); - } - - [Fact] - public void Add() - { - var flags = new U8BitflagSet(); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4); - var flags2And4 = flags.Flag(flag2, flag4); - - Assert.Equal(3, 1 + flag2); - Assert.Equal(5, 1 + flag4); - Assert.Equal(7, 1 + flags2And4); - } - - [Fact] - public void Remove() - { - var flags = new U8BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.Equal(2, 7 - flag1); - Assert.Equal(5, 7 - flag2); - Assert.Equal(3, 7 - flag4); - } - - [Fact] - public void IsIn() - { - var flags = new U8BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flag4 = flags.Flag(4, flag1); - - Assert.True(flag1.IsIn(1)); - Assert.True(flag2.IsIn(3)); - Assert.False(flag4.IsIn(4)); - Assert.True(flag4.IsIn(5)); - } - - [Fact] - public void IsAbstract() - { - var flags = new U8BitflagSet(); - var flag1 = flags.Flag(1); - var flag2 = flags.Flag(2); - var flags1And2 = flags.Flag(flag1, flag2); - var flag4 = flags.Flag(4, flags1And2); - - Assert.False(flag1.IsAbstract); - Assert.False(flag2.IsAbstract); - Assert.True(flags1And2.IsAbstract); - Assert.False(flag4.IsAbstract); - } -} \ No newline at end of file From 11ad2e21de2915f1193e0e5fb7b9cd894d54224d Mon Sep 17 00:00:00 2001 From: Louis DEVIE Date: Fri, 2 May 2025 22:09:17 +0200 Subject: [PATCH 15/15] test(dotnet): added tests for the new APIs with enums of bigints --- .../Multiflag/UnsupportedEnumTypeException.cs | 6 - dotnet/Tests/DynamicBitflagSetTests.cs | 113 ++++++++++++++-- dotnet/Tests/EnumBitflagSetTests.cs | 127 +++++++++++++----- 3 files changed, 190 insertions(+), 56 deletions(-) diff --git a/dotnet/Multiflag/UnsupportedEnumTypeException.cs b/dotnet/Multiflag/UnsupportedEnumTypeException.cs index 939b0f7..ab2ca24 100644 --- a/dotnet/Multiflag/UnsupportedEnumTypeException.cs +++ b/dotnet/Multiflag/UnsupportedEnumTypeException.cs @@ -9,12 +9,6 @@ namespace Multiflag /// public class UnsupportedEnumTypeException : ArgumentException { - internal UnsupportedEnumTypeException(Type underlyingType) - : base( - $"Enums with an underlying type of {underlyingType} are not supported. Use one of byte, ushort, uint or ulong instead.") - { - } - internal UnsupportedEnumTypeException(Type underlyingType, string suggestedType) : base($"Enums with an underlying type of {underlyingType} are not supported. Use {suggestedType} instead.") { diff --git a/dotnet/Tests/DynamicBitflagSetTests.cs b/dotnet/Tests/DynamicBitflagSetTests.cs index c6fef35..7e64944 100644 --- a/dotnet/Tests/DynamicBitflagSetTests.cs +++ b/dotnet/Tests/DynamicBitflagSetTests.cs @@ -4,7 +4,7 @@ namespace Multiflag.Tests; public class DynamicBitflagSetTests { - private static readonly BigInteger BigPowerOfTwo = new BigInteger(1) << 100; + private static readonly BigInteger bigPowerOfTwo = new BigInteger(1) << 100; [Fact] public void ValueNotAPowerOfTwo() @@ -14,6 +14,91 @@ public void ValueNotAPowerOfTwo() Assert.Throws(() => flags.Flag(11)); } + [Fact] + public void Union() + { + var flags = new DynamicBitflagSet(); + + Assert.Equal(0, flags.Union(0, 0)); + Assert.Equal(1, flags.Union(1, 0)); + Assert.Equal(2, flags.Union(0, 2)); + Assert.Equal(3, flags.Union(1, 2)); + Assert.Equal(7, flags.Union(3, 6)); + } + + [Fact] + public void Difference() { + var flags = new DynamicBitflagSet(); + + Assert.Equal(0, flags.Difference(0, 0)); + Assert.Equal(1, flags.Difference(1, 0)); + Assert.Equal(1, flags.Difference(3, 6)); + Assert.Equal(4, flags.Difference(6, 3)); + Assert.Equal(8, flags.Difference(8, 17)); + } + + [Fact] + public void Intersection() + { + var flags = new DynamicBitflagSet(); + + Assert.Equal(0, flags.Intersection(0, 0)); + Assert.Equal(0, flags.Intersection(1, 0)); + Assert.Equal(0, flags.Intersection(1, 2)); + Assert.Equal(1, flags.Intersection(1, 3)); + Assert.Equal(1, flags.Intersection(11, 5)); + Assert.Equal(3, flags.Intersection(11, 7)); + } + + [Fact] + public void Iterate() + { + var flags = new DynamicBitflagSet(); + + Assert.Equal([], flags.Iterate(0)); + Assert.Equal([1], flags.Iterate(1)); + Assert.Equal([2], flags.Iterate(2)); + Assert.Equal([1, 2], flags.Iterate(3)); + Assert.Equal([1, 2, 8], flags.Iterate(11)); + Assert.Equal([4, 32, 64], flags.Iterate(100)); + } + + [Fact] + public void Minimum() + { + var flags = new DynamicBitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0, flags.Minimum(0)); + Assert.Equal(1, flags.Minimum(1)); + Assert.Equal(0, flags.Minimum(2)); + Assert.Equal(3, flags.Minimum(3)); + Assert.Equal(3, flags.Minimum(11)); + Assert.Equal(13, flags.Minimum(13)); + Assert.Equal(1, flags.Minimum(17)); + } + + [Fact] + public void Maximum() + { + var flags = new DynamicBitflagSet(); + var flag1 = flags.Flag(1); + var flag2 = flags.Flag(2, flag1); + var flag4 = flags.Flag(4, flag1); + var flag8 = flags.Flag(8, flag4); + + Assert.Equal(0, flags.Maximum(0)); + Assert.Equal(1, flags.Maximum(1)); + Assert.Equal(3, flags.Maximum(2)); + Assert.Equal(3, flags.Maximum(3)); + Assert.Equal(15, flags.Maximum(11)); + Assert.Equal(13, flags.Maximum(13)); + Assert.Equal(1, flags.Maximum(17)); + } + [Fact] public void Add() { @@ -21,13 +106,13 @@ public void Add() var flag2 = flags.Flag(2); var flag4 = flags.Flag(4); var flags2And4 = flags.Flag(flag2, flag4); - var flag100 = flags.Flag(BigPowerOfTwo); + var flag100 = flags.Flag(bigPowerOfTwo); - Assert.Equal(3u, 1 + flag2); - Assert.Equal(5u, 1 + flag4); - Assert.Equal(7u, 1 + flags2And4); - Assert.Equal(BigPowerOfTwo + 1, 1 + flag100); - Assert.Equal(BigPowerOfTwo + 2, BigPowerOfTwo + flag2); + Assert.Equal(3, 1 + flag2); + Assert.Equal(5, 1 + flag4); + Assert.Equal(7, 1 + flags2And4); + Assert.Equal(bigPowerOfTwo + 1, 1 + flag100); + Assert.Equal(bigPowerOfTwo + 2, bigPowerOfTwo + flag2); } [Fact] @@ -37,14 +122,14 @@ public void Remove() var flag1 = flags.Flag(1); var flag2 = flags.Flag(2); var flag4 = flags.Flag(4, flag1); - var flag100 = flags.Flag(BigPowerOfTwo); + var flag100 = flags.Flag(bigPowerOfTwo); - Assert.Equal(2u, 7 - flag1); - Assert.Equal(5u, 7 - flag2); - Assert.Equal(3u, 7 - flag4); - Assert.Equal(2, BigPowerOfTwo + 2 - flag100); + Assert.Equal(2, 7 - flag1); + Assert.Equal(5, 7 - flag2); + Assert.Equal(3, 7 - flag4); + Assert.Equal(2, bigPowerOfTwo + 2 - flag100); Assert.Equal(2, 2 - flag100); - Assert.Equal(BigPowerOfTwo - 6, BigPowerOfTwo - 1 - flag1); + Assert.Equal(bigPowerOfTwo - 6, bigPowerOfTwo - 1 - flag1); } [Fact] @@ -59,7 +144,7 @@ public void IsIn() Assert.True(flag2.IsIn(3)); Assert.False(flag4.IsIn(4)); Assert.True(flag4.IsIn(5)); - Assert.False(flag4.IsIn(BigPowerOfTwo + 1)); + Assert.False(flag4.IsIn(bigPowerOfTwo + 1)); } [Fact] diff --git a/dotnet/Tests/EnumBitflagSetTests.cs b/dotnet/Tests/EnumBitflagSetTests.cs index cacccf5..dd33078 100644 --- a/dotnet/Tests/EnumBitflagSetTests.cs +++ b/dotnet/Tests/EnumBitflagSetTests.cs @@ -6,7 +6,9 @@ public class EnumBitflagSetTests public void SignedEnumsAreUnsupported() { Assert.Throws(() => new EnumBitflagSet()); + Assert.Throws(() => new EnumBitflagSet()); Assert.Throws(() => new EnumBitflagSet()); + Assert.Throws(() => new EnumBitflagSet()); Assert.Throws(() => new EnumBitflagSet()); Assert.Throws(() => new EnumBitflagSet()); } @@ -23,46 +25,105 @@ public void ValueNotAPowerOfTwo() public void ValueNotDefined() { var flags = new EnumBitflagSet(); - Assert.Throws(() => flags.Flag((U32Enum)8)); + Assert.Throws(() => flags.Flag((U32Enum)256)); } [Fact] - public void Add() + public void Union() { var flags = new EnumBitflagSet(); - var flagB = flags.Flag(U32Enum.B); - var flagC = flags.Flag(U32Enum.C); - var flags2And4 = flags.Flag(flagB, flagC); - Assert.Equal((U32Enum)3, U32Enum.A + flagB); - Assert.Equal((U32Enum)5, U32Enum.A + flagC); - Assert.Equal((U32Enum)7, U32Enum.A + flags2And4); + Assert.Equal((U32Enum)0, flags.Union(0, 0)); + Assert.Equal(U32Enum.A, flags.Union(U32Enum.A, 0)); + Assert.Equal(U32Enum.B, flags.Union(0, U32Enum.B)); + Assert.Equal((U32Enum)3, flags.Union(U32Enum.A, U32Enum.B)); + Assert.Equal((U32Enum)7, flags.Union((U32Enum)3, (U32Enum)6)); + } + + [Fact] + public void Difference() { + var flags = new EnumBitflagSet(); + + Assert.Equal((U32Enum)0, flags.Difference(0, 0)); + Assert.Equal(U32Enum.A, flags.Difference(U32Enum.A, 0)); + Assert.Equal(U32Enum.A, flags.Difference((U32Enum)3, (U32Enum)6)); + Assert.Equal(U32Enum.C, flags.Difference((U32Enum)6, (U32Enum)3)); + Assert.Equal(U32Enum.D, flags.Difference(U32Enum.D, (U32Enum)17)); } [Fact] - public void Add8Bit() + public void Intersection() { - var flags = new EnumBitflagSet(); - var flagB = flags.Flag(U8Enum.B); - var flagC = flags.Flag(U8Enum.C); - var flags2And4 = flags.Flag(flagB, flagC); + var flags = new EnumBitflagSet(); + + Assert.Equal((U32Enum)0, flags.Intersection(0, 0)); + Assert.Equal((U32Enum)0, flags.Intersection(U32Enum.A, 0)); + Assert.Equal((U32Enum)0, flags.Intersection(U32Enum.A, U32Enum.B)); + Assert.Equal(U32Enum.A, flags.Intersection(U32Enum.A, (U32Enum)3)); + Assert.Equal(U32Enum.A, flags.Intersection((U32Enum)11, (U32Enum)5)); + Assert.Equal((U32Enum)3, flags.Intersection((U32Enum)11, (U32Enum)7)); + } + + [Fact] + public void Iterate() + { + var flags = new EnumBitflagSet(); + + Assert.Equal([], flags.Iterate(0)); + Assert.Equal([U32Enum.A], flags.Iterate(U32Enum.A)); + Assert.Equal([U32Enum.B], flags.Iterate(U32Enum.B)); + Assert.Equal([U32Enum.A, U32Enum.B], flags.Iterate((U32Enum)3)); + Assert.Equal([U32Enum.A, U32Enum.B, U32Enum.D], flags.Iterate((U32Enum)11)); + Assert.Equal([U32Enum.C, U32Enum.F, U32Enum.G], flags.Iterate((U32Enum)100)); + } - Assert.Equal((U8Enum)3, U8Enum.A + flagB); - Assert.Equal((U8Enum)5, U8Enum.A + flagC); - Assert.Equal((U8Enum)7, U8Enum.A + flags2And4); + [Fact] + public void Minimum() + { + var flags = new EnumBitflagSet(); + var flag1 = flags.Flag(U32Enum.A); + var flag2 = flags.Flag(U32Enum.B, flag1); + var flag4 = flags.Flag(U32Enum.C, flag1); + var flag8 = flags.Flag(U32Enum.D, flag4); + + Assert.Equal((U32Enum)0, flags.Minimum(0)); + Assert.Equal(U32Enum.A, flags.Minimum(U32Enum.A)); + Assert.Equal((U32Enum)0, flags.Minimum(U32Enum.B)); + Assert.Equal((U32Enum)3, flags.Minimum((U32Enum)3)); + Assert.Equal((U32Enum)3, flags.Minimum((U32Enum)11)); + Assert.Equal((U32Enum)13, flags.Minimum((U32Enum)13)); + Assert.Equal(U32Enum.A, flags.Minimum((U32Enum)17)); } [Fact] - public void Add16Bit() + public void Maximum() { - var flags = new EnumBitflagSet(); - var flagB = flags.Flag(U16Enum.B); - var flagC = flags.Flag(U16Enum.C); + var flags = new EnumBitflagSet(); + var flag1 = flags.Flag(U32Enum.A); + var flag2 = flags.Flag(U32Enum.B, flag1); + var flag4 = flags.Flag(U32Enum.C, flag1); + var flag8 = flags.Flag(U32Enum.D, flag4); + + Assert.Equal((U32Enum)0, flags.Maximum(0)); + Assert.Equal(U32Enum.A, flags.Maximum(U32Enum.A)); + Assert.Equal((U32Enum)3, flags.Maximum(U32Enum.B)); + Assert.Equal((U32Enum)3, flags.Maximum((U32Enum)3)); + Assert.Equal((U32Enum)15, flags.Maximum((U32Enum)11)); + Assert.Equal((U32Enum)13, flags.Maximum((U32Enum)13)); + Assert.Equal(U32Enum.A, flags.Maximum((U32Enum)17)); + } + + [Fact] + public void Add() + { + var flags = new EnumBitflagSet(); + var flagB = flags.Flag(U32Enum.B); + var flagC = flags.Flag(U32Enum.C); var flags2And4 = flags.Flag(flagB, flagC); - Assert.Equal((U16Enum)3, U16Enum.A + flagB); - Assert.Equal((U16Enum)5, U16Enum.A + flagC); - Assert.Equal((U16Enum)7, U16Enum.A + flags2And4); + Assert.Equal((U32Enum)3, U32Enum.A + flagB); + Assert.Equal((U32Enum)5, U32Enum.A + flagC); + Assert.Equal((U32Enum)7, U32Enum.A + flags2And4); } [Fact] @@ -122,21 +183,11 @@ public void IsAbstract() private enum S8Enum : sbyte; - private enum U8Enum : byte - { - A = 1, - B = 2, - C = 4 - } + private enum U8Enum : byte; private enum S16Enum : short; - private enum U16Enum : ushort - { - A = 1, - B = 2, - C = 4 - } + private enum U16Enum : ushort; private enum S32Enum; @@ -144,7 +195,11 @@ private enum U32Enum : uint { A = 1, B = 2, - C = 4 + C = 4, + D = 8, + E = 16, + F = 32, + G = 64, } private enum S64Enum : long;