using System.Collections; using System.Text.Json; namespace DeepDrftContent.Data.FileDatabase.Utils; /// /// A set implementation that uses structural equality for values by serializing them to JSON. /// This provides the same behavior as the TypeScript StructuralSet. /// Optimized with caching to avoid repeated serialization. /// /// The value type public class StructuralSet : IEnumerable where T : notnull { private readonly Dictionary _innerMap = new(); private readonly Dictionary _valueStringCache = new(); /// /// Converts a value to its string representation for structural comparison /// Uses caching to avoid expensive serialization on repeated lookups /// private string GetValueString(T value) { if (value == null) return "null"; // For reference types, use cache to avoid repeated serialization if (!typeof(T).IsValueType && _valueStringCache.TryGetValue(value, out var cached)) { return cached; } var valueString = value switch { string s => s, int or long or float or double or decimal => value.ToString()!, _ => JsonSerializer.Serialize(value) }; // Cache for reference types only (value types are cheap to convert) if (!typeof(T).IsValueType) { _valueStringCache[value] = valueString; } return valueString; } /// /// Adds a value to the set /// public StructuralSet Add(T value) { var valueString = GetValueString(value); if (!_innerMap.ContainsKey(valueString)) { _innerMap[valueString] = value; } return this; } /// /// Checks if the set contains the specified value /// public bool Has(T value) { var valueString = GetValueString(value); return _innerMap.ContainsKey(valueString); } /// /// Removes a value from the set /// public bool Delete(T value) { var valueString = GetValueString(value); return _innerMap.Remove(valueString); } /// /// Clears all values from the set /// public void Clear() => _innerMap.Clear(); /// /// Gets the number of values in the set /// public int Size => _innerMap.Count; /// /// Enumerates all values in the set /// public IEnumerator GetEnumerator() { return _innerMap.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// /// Gets all values in the set /// public IEnumerable Values => _innerMap.Values; }