diff --git a/CHANGELOG.md b/CHANGELOG.md
index e4eeb56..f38ab0a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,7 +14,7 @@ Jump to version:
### MLEM
Additions
- Added TokenizedString.Realign
-- Added EnumHelper.GetFlags
+- Added GetFlags and GetUniqueFlags to EnumHelper
- **Added the ability to find paths to one of multiple goals using AStar**
Improvements
@@ -60,7 +60,7 @@ Fixes
Additions
- Added data, from, and copy instructions to DataTextureAtlas
- Added the ability to add additional regions to a RuntimeTexturePacker after packing
-- Added DynamicEnum.GetFlags
+- Added GetFlags, GetUniqueFlags and IsDefined to DynamicEnum
Improvements
- Allow data texture atlas pivots and offsets to be negative
diff --git a/MLEM.Data/DynamicEnum.cs b/MLEM.Data/DynamicEnum.cs
index e22107b..ff8e8dc 100644
--- a/MLEM.Data/DynamicEnum.cs
+++ b/MLEM.Data/DynamicEnum.cs
@@ -134,7 +134,7 @@ namespace MLEM.Data {
/// The newly created enum value
public static T AddValue(string name) where T : DynamicEnum {
BigInteger value = 0;
- while (DynamicEnum.GetStorage(typeof(T)).Values.ContainsKey(value))
+ while (DynamicEnum.IsDefined(typeof(T), value))
value++;
return DynamicEnum.Add(name, value);
}
@@ -149,7 +149,7 @@ namespace MLEM.Data {
/// The newly created enum value
public static T AddFlag(string name) where T : DynamicEnum {
BigInteger value = 1;
- while (DynamicEnum.GetStorage(typeof(T)).Values.ContainsKey(value))
+ while (DynamicEnum.IsDefined(typeof(T), value))
value <<= 1;
return DynamicEnum.Add(name, value);
}
@@ -189,6 +189,27 @@ namespace MLEM.Data {
}
}
+ ///
+ /// Returns all of the defined unique flags from the given dynamic enum type which are contained in .
+ /// Any combined flags (flags that aren't powers of two) which are defined in will not be returned.
+ ///
+ /// The combined flags whose individual flags to return.
+ /// The type of enum.
+ /// All of the unique flags that make up .
+ public static IEnumerable GetUniqueFlags(T combinedFlag) where T : DynamicEnum {
+ // we can't use the same method here as EnumHelper.GetUniqueFlags since DynamicEnum doesn't guarantee sorted values
+ var max = DynamicEnum.GetValues().Max(DynamicEnum.GetValue);
+ var uniqueFlag = BigInteger.One;
+ while (uniqueFlag <= max) {
+ if (DynamicEnum.IsDefined(typeof(T), uniqueFlag)) {
+ var uniqueFlagValue = DynamicEnum.GetEnumValue(uniqueFlag);
+ if (combinedFlag.HasFlag(uniqueFlagValue))
+ yield return uniqueFlagValue;
+ }
+ uniqueFlag <<= 1;
+ }
+ }
+
///
/// Returns the bitwise OR (|) combination of the two dynamic enum values
///
@@ -307,7 +328,8 @@ namespace MLEM.Data {
///
/// Parses the given into a dynamic enum value and returns the result.
/// This method supports defined enum values as well as values combined using the pipe (|) character and any number of spaces.
- /// If no enum value can be parsed, null is returned. ///
+ /// If no enum value can be parsed, null is returned.
+ ///
/// The type of the dynamic enum value to parse
/// The string to parse into a dynamic enum value
/// The parsed enum value, or null if parsing fails
@@ -330,6 +352,27 @@ namespace MLEM.Data {
return cached;
}
+ ///
+ /// Returns whether the given is defined in the given dynamic enum .
+ /// A value counts as explicitly defined if it has been added using , or .
+ ///
+ /// The dynamic enum type to query.
+ /// The value to query.
+ /// Whether the is defined.
+ public static bool IsDefined(Type type, BigInteger value) {
+ return DynamicEnum.GetStorage(type).Values.ContainsKey(value);
+ }
+
+ ///
+ /// Returns whether the given is defined in its dynamic enum type.
+ /// A value counts as explicitly defined if it has been added using , or .
+ ///
+ /// The value to query.
+ /// Whether the is defined.
+ public static bool IsDefined(DynamicEnum value) {
+ return value != null && DynamicEnum.IsDefined(value.GetType(), DynamicEnum.GetValue(value));
+ }
+
private static Storage GetStorage(Type type) {
if (!DynamicEnum.Storages.TryGetValue(type, out var storage)) {
storage = new Storage();
diff --git a/MLEM/Misc/EnumHelper.cs b/MLEM/Misc/EnumHelper.cs
index 34a561b..435be1b 100644
--- a/MLEM/Misc/EnumHelper.cs
+++ b/MLEM/Misc/EnumHelper.cs
@@ -46,5 +46,24 @@ namespace MLEM.Misc {
}
}
+ ///
+ /// Returns all of the defined unique flags from the given enum type which are contained in .
+ /// Any combined flags (flags that aren't powers of two) which are defined in will not be returned.
+ ///
+ /// The combined flags whose individual flags to return.
+ /// The type of enum.
+ /// All of the unique flags that make up .
+ public static IEnumerable GetUniqueFlags(T combinedFlag) where T : struct, Enum {
+ var uniqueFlag = 1;
+ foreach (var flag in EnumHelper.GetValues()) {
+ var flagValue = Convert.ToInt64(flag);
+ // GetValues is always ordered by binary value, so we can be sure that the next flag is bigger than the last
+ while (uniqueFlag < flagValue)
+ uniqueFlag <<= 1;
+ if (flagValue == uniqueFlag && combinedFlag.HasFlag(flag))
+ yield return flag;
+ }
+ }
+
}
}
diff --git a/Tests/DataTests.cs b/Tests/DataTests.cs
index 9e83ee5..d106d4c 100644
--- a/Tests/DataTests.cs
+++ b/Tests/DataTests.cs
@@ -36,33 +36,6 @@ namespace Tests {
Assert.AreEqual(this.testObject, read);
}
- [Test]
- public void TestDynamicEnum() {
- var flags = new TestEnum[100];
- for (var i = 0; i < flags.Length; i++)
- flags[i] = DynamicEnum.AddFlag("Flag" + i);
-
- Assert.AreEqual(DynamicEnum.GetValue(flags[7]), BigInteger.One << 7);
- Assert.AreEqual(DynamicEnum.GetEnumValue(BigInteger.One << 75), flags[75]);
-
- Assert.AreEqual(DynamicEnum.GetValue(DynamicEnum.Or(flags[2], flags[17])), BigInteger.One << 2 | BigInteger.One << 17);
- Assert.AreEqual(DynamicEnum.GetValue(DynamicEnum.And(flags[2], flags[3])), BigInteger.Zero);
- Assert.AreEqual(DynamicEnum.And(DynamicEnum.Or(flags[24], flags[52]), DynamicEnum.Or(flags[52], flags[75])), flags[52]);
- Assert.AreEqual(DynamicEnum.Xor(DynamicEnum.Or(flags[85], flags[73]), flags[73]), flags[85]);
- Assert.AreEqual(DynamicEnum.Xor(DynamicEnum.Or(flags[85], DynamicEnum.Or(flags[73], flags[12])), flags[73]), DynamicEnum.Or(flags[85], flags[12]));
- Assert.AreEqual(DynamicEnum.GetValue(DynamicEnum.Neg(flags[74])), ~(BigInteger.One << 74));
-
- Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasFlag(flags[24]), true);
- Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasAnyFlag(flags[24]), true);
- Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasFlag(DynamicEnum.Or(flags[24], flags[26])), false);
- Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasAnyFlag(DynamicEnum.Or(flags[24], flags[26])), true);
-
- Assert.AreEqual(DynamicEnum.Parse("Flag24"), flags[24]);
- Assert.AreEqual(DynamicEnum.Parse("Flag24 | Flag43"), DynamicEnum.Or(flags[24], flags[43]));
- Assert.AreEqual(flags[24].ToString(), "Flag24");
- Assert.AreEqual(DynamicEnum.Or(flags[24], flags[43]).ToString(), "Flag24 | Flag43");
- }
-
[Test]
public void TestJsonTypeSafety() {
var serializer = new JsonSerializer {TypeNameHandling = TypeNameHandling.Auto};
@@ -109,11 +82,5 @@ namespace Tests {
}
- private class TestEnum : DynamicEnum {
-
- public TestEnum(string name, BigInteger value) : base(name, value) {}
-
- }
-
}
}
diff --git a/Tests/EnumTests.cs b/Tests/EnumTests.cs
new file mode 100644
index 0000000..50430e0
--- /dev/null
+++ b/Tests/EnumTests.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Linq;
+using System.Numerics;
+using MLEM.Data;
+using MLEM.Misc;
+using NUnit.Framework;
+
+namespace Tests;
+
+public class EnumTests {
+
+ [Test]
+ public void TestRegularEnums() {
+ Assert.AreEqual(
+ new[] {TestEnum.One, TestEnum.Two, TestEnum.Eight, TestEnum.Sixteen, TestEnum.EightSixteen},
+ EnumHelper.GetFlags(TestEnum.One | TestEnum.Sixteen | TestEnum.Eight | TestEnum.Two));
+
+ Assert.AreEqual(
+ new[] {TestEnum.One, TestEnum.Two, TestEnum.Eight, TestEnum.Sixteen},
+ EnumHelper.GetUniqueFlags(TestEnum.One | TestEnum.Sixteen | TestEnum.Eight | TestEnum.Two));
+ }
+
+ [Test]
+ public void TestDynamicEnums() {
+ var flags = new TestDynamicEnum[100];
+ for (var i = 0; i < flags.Length; i++)
+ flags[i] = DynamicEnum.AddFlag("Flag" + i);
+ var combined = DynamicEnum.Add("Combined", DynamicEnum.GetValue(DynamicEnum.Or(flags[7], flags[13])));
+
+ Assert.AreEqual(DynamicEnum.GetValue(flags[7]), BigInteger.One << 7);
+ Assert.AreEqual(DynamicEnum.GetEnumValue(BigInteger.One << 75), flags[75]);
+
+ Assert.AreEqual(DynamicEnum.GetValue(DynamicEnum.Or(flags[2], flags[17])), BigInteger.One << 2 | BigInteger.One << 17);
+ Assert.AreEqual(DynamicEnum.GetValue(DynamicEnum.And(flags[2], flags[3])), BigInteger.Zero);
+ Assert.AreEqual(DynamicEnum.And(DynamicEnum.Or(flags[24], flags[52]), DynamicEnum.Or(flags[52], flags[75])), flags[52]);
+ Assert.AreEqual(DynamicEnum.Xor(DynamicEnum.Or(flags[85], flags[73]), flags[73]), flags[85]);
+ Assert.AreEqual(DynamicEnum.Xor(DynamicEnum.Or(flags[85], DynamicEnum.Or(flags[73], flags[12])), flags[73]), DynamicEnum.Or(flags[85], flags[12]));
+ Assert.AreEqual(DynamicEnum.GetValue(DynamicEnum.Neg(flags[74])), ~(BigInteger.One << 74));
+
+ Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasFlag(flags[24]), true);
+ Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasAnyFlag(flags[24]), true);
+ Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasFlag(DynamicEnum.Or(flags[24], flags[26])), false);
+ Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasAnyFlag(DynamicEnum.Or(flags[24], flags[26])), true);
+
+ Assert.AreEqual(DynamicEnum.Parse("Flag24"), flags[24]);
+ Assert.AreEqual(DynamicEnum.Parse("Flag24 | Flag43"), DynamicEnum.Or(flags[24], flags[43]));
+ Assert.AreEqual(flags[24].ToString(), "Flag24");
+ Assert.AreEqual(DynamicEnum.Or(flags[24], flags[43]).ToString(), "Flag24 | Flag43");
+
+ Assert.True(DynamicEnum.IsDefined(flags[27]));
+ Assert.True(DynamicEnum.IsDefined(combined));
+ Assert.False(DynamicEnum.IsDefined(DynamicEnum.Or(flags[17], flags[49])));
+ Assert.False(DynamicEnum.IsDefined(DynamicEnum.Or(combined, flags[49])));
+
+ Assert.AreEqual(
+ new[] {flags[0], flags[7], flags[13], combined},
+ DynamicEnum.GetFlags(DynamicEnum.Or(DynamicEnum.Or(flags[0], flags[13]), flags[7])));
+
+ Assert.AreEqual(
+ new[] {flags[0], flags[7], flags[13]},
+ DynamicEnum.GetUniqueFlags(DynamicEnum.Or(DynamicEnum.Or(flags[0], flags[13]), flags[7])));
+ }
+
+ [Flags]
+ private enum TestEnum {
+
+ One = 1,
+ Two = 2,
+ Eight = 8,
+ Sixteen = 16,
+ EightSixteen = TestEnum.Eight | TestEnum.Sixteen,
+ ThirtyTwo = 32,
+ OneTwentyEight = 128,
+ OneTwentyEightTwoOne = TestEnum.OneTwentyEight | TestEnum.Two | TestEnum.One
+
+ }
+
+ private class TestDynamicEnum : DynamicEnum {
+
+ public TestDynamicEnum(string name, BigInteger value) : base(name, value) {}
+
+ }
+
+}