// 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;
}
}