// MIT License - Copyright (c) 2025 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE namespace WallstopStudios.UnityHelpers.Core.DataStructure.Adapters { using System; using System.Collections.Generic; using System.Runtime.Serialization; /// /// Sorted set wrapper that keeps ordering intact across Unity, ProtoBuf, and JSON serialization. /// Ideal for deterministic gameplay systems that need sorted iteration but still want to save or inspect data. /// /// /// highscores = new SerializableSortedSet(new[] { 100, 250, 420 }); /// highscores.Add(360); /// foreach (int score in highscores) /// { /// Debug.Log(score); /// } /// ]]> /// [Serializable] public class SerializableSortedSet : SerializableSetBase> where T : IComparable { private sealed class StorageSet : SortedSet { /// /// Initializes an empty storage set using the default comparer. /// public StorageSet() { } /// /// Initializes the storage set with the provided collection. /// /// Elements copied into the sorted set. public StorageSet(IEnumerable collection) : base(collection ?? Array.Empty()) { } /// /// Deserialization constructor used by . /// /// Serialized data describing the set. /// Context describing the serialization source. public StorageSet(SerializationInfo info, StreamingContext context) : base(info, context) { } } /// /// Initializes an empty sorted set that can participate in Unity and ProtoBuf serialization. /// public SerializableSortedSet() : base(new StorageSet()) { } /// /// Initializes the set with the provided items. /// /// Sequence whose elements are copied into the set. public SerializableSortedSet(IEnumerable collection) : base(new StorageSet(collection)) { } /// /// Initializes the set during custom serialization scenarios. /// protected SerializableSortedSet(SerializationInfo info, StreamingContext context) : base( info, context, (serializationInfo, streamingContext) => new StorageSet(serializationInfo, streamingContext) ) { } /// /// Creates a new populated with this set's contents. /// /// A copy of the sorted set's current state. public SortedSet ToSortedSet() { SortedSet copy = new(Set, Set.Comparer); return copy; } /// /// Returns an enumerator that iterates through the set in sorted order. /// /// /// highscores = new SerializableSortedSet(); /// SortedSet.Enumerator enumerator = highscores.GetEnumerator(); /// while (enumerator.MoveNext()) /// { /// Debug.Log(enumerator.Current); /// } /// ]]> /// public SortedSet.Enumerator GetEnumerator() { return Set.GetEnumerator(); } /// /// Gets the smallest value stored in the set. /// public T Min => Set.Min; /// /// Gets the largest value stored in the set. /// public T Max => Set.Max; /// /// Enumerates the set in descending order without allocating a copy. /// /// Lazy enumerable that yields items from greatest to least. /// /// highscores = new SerializableSortedSet(); /// foreach (int score in highscores.Reverse()) /// { /// Debug.Log(score); /// } /// ]]> /// public IEnumerable Reverse() { return Set.Reverse(); } /// /// Produces a view of the set constrained between the provided lower and upper bounds. /// /// Inclusive lower bound. /// Inclusive upper bound. /// A view that reflects mutations made to the underlying set. /// /// highscores = new SerializableSortedSet(new int[] { 100, 250, 420 }); /// SortedSet topScores = highscores.GetViewBetween(200, 500); /// ]]> /// public SortedSet GetViewBetween(T lowerValue, T upperValue) { return Set.GetViewBetween(lowerValue, upperValue); } /// protected override int RemoveWhereInternal(Predicate match) { return Set.RemoveWhere(match); } /// protected override bool TryGetValueCore(T equalValue, out T actualValue) { return Set.TryGetValue(equalValue, out actualValue); } protected override bool SupportsSorting => true; } }