diff --git a/src/BizHawk.Common/Extensions/CollectionExtensions.cs b/src/BizHawk.Common/Extensions/CollectionExtensions.cs index ff80ee2192..39f0303ef9 100644 --- a/src/BizHawk.Common/Extensions/CollectionExtensions.cs +++ b/src/BizHawk.Common/Extensions/CollectionExtensions.cs @@ -490,6 +490,42 @@ namespace BizHawk.Common.CollectionExtensions return removed; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool? Unanimity(this IEnumerable lazy) + => lazy is IReadOnlyCollection collection + ? Unanimity(collection) + : Unanimity(lazy as ISet ?? lazy.ToHashSet()); + + /// + public static bool? Unanimity(this IReadOnlyCollection collection) + { + if (collection is bool[] arr) return Unanimity(arr.AsSpan()); + if (collection is List list) + { + return list is [ var first, .. ] && list.IndexOf(!first, index: 1) < 0 ? first : null; + } + var iter = collection.GetEnumerator(); + if (!iter.MoveNext()) return null; + var first1 = iter.Current; + while (iter.MoveNext()) if (iter.Current != first1) return null; + return first1; + } + + /// + /// if all , + /// if all , + /// if mixed (or empty) + /// + public static bool? Unanimity(this ISet set) + => set.Contains(false) + ? set.Contains(true) ? null : false + : set.Contains(true) ? true : null; + + /// + public static bool? Unanimity(this ReadOnlySpan span) + => span is [ var first, .. ] && !span.Slice(start: 1).Contains(!first) ? first : null; + public static bool IsSortedAsc(this IReadOnlyList list) where T : IComparable { diff --git a/src/BizHawk.Tests/Common/CollectionExtensions/CollectionExtensionTests.cs b/src/BizHawk.Tests/Common/CollectionExtensions/CollectionExtensionTests.cs index 83fb2494de..156aa227ff 100644 --- a/src/BizHawk.Tests/Common/CollectionExtensions/CollectionExtensionTests.cs +++ b/src/BizHawk.Tests/Common/CollectionExtensions/CollectionExtensionTests.cs @@ -1,5 +1,7 @@ using System.Collections; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; using BizHawk.Common.CollectionExtensions; @@ -134,5 +136,21 @@ namespace BizHawk.Tests.Common.CollectionExtensions c.RemoveAll(Predicate); Assert.AreEqual(2, c.Count, nameof(CE.RemoveAll) + " failed on (ICollection not IList)"); } + + [DataRow(new bool[0], null)] + [DataRow(new bool[] { true }, true)] + [DataRow(new bool[] { false }, false)] + [DataRow(new bool[] { true, true }, true)] + [DataRow(new bool[] { false, false }, false)] + [DataRow(new bool[] { true, false }, null)] + [DataRow(new bool[] { false, true }, null)] + [TestMethod] + public void TestUnanimity(bool[] array, bool? expected) + { + Assert.AreEqual(expected, ((ISet) array.ToHashSet()).Unanimity(), "ISet"); + Assert.AreEqual(expected, array.Unanimity(), "Span"); + Assert.AreEqual(expected, array.ToList().Unanimity(), "List"); + Assert.AreEqual(expected, ImmutableArray.Create(array).Unanimity(), "IROColl not List"); + } } }