using System.Collections; using System.Text.Json; namespace DeepDrftContent.Data.FileDatabase.Utils; /// /// A map implementation that uses structural equality for keys by serializing them to JSON. /// This provides the same behavior as the TypeScript StructuralMap. /// Optimized with caching to avoid repeated serialization. /// /// The key type /// The value type public class StructuralMap : IEnumerable> where TKey : notnull { private readonly Dictionary> _innerMap = new(); private readonly Dictionary _keyStringCache = new(); /// /// Converts a key to its string representation for structural comparison /// Uses caching to avoid expensive serialization on repeated lookups /// private string GetKeyString(TKey key) { if (key == null) return "null"; // For reference types, use cache to avoid repeated serialization if (!typeof(TKey).IsValueType && _keyStringCache.TryGetValue(key, out var cached)) { return cached; } var keyString = key switch { string s => s, int or long or float or double or decimal => key.ToString()!, _ => JsonSerializer.Serialize(key) }; // Cache for reference types only (value types are cheap to convert) if (!typeof(TKey).IsValueType) { _keyStringCache[key] = keyString; } return keyString; } /// /// Sets a key-value pair in the map /// public StructuralMap Set(TKey key, TValue value) { var keyString = GetKeyString(key); _innerMap[keyString] = new KeyValuePair(key, value); return this; } /// /// Gets a value by key, or default if not found /// public TValue? Get(TKey key) { var keyString = GetKeyString(key); return _innerMap.TryGetValue(keyString, out var pair) ? pair.Value : default; } /// /// Checks if the map contains the specified key /// public bool Has(TKey key) { var keyString = GetKeyString(key); return _innerMap.ContainsKey(keyString); } /// /// Removes a key-value pair from the map /// public bool Delete(TKey key) { var keyString = GetKeyString(key); return _innerMap.Remove(keyString); } /// /// Clears all entries from the map /// public void Clear() => _innerMap.Clear(); /// /// Gets the number of entries in the map /// public int Size => _innerMap.Count; /// /// Enumerates all key-value pairs /// public IEnumerator> GetEnumerator() { return _innerMap.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// /// Gets all keys in the map /// public IEnumerable Keys => _innerMap.Values.Select(pair => pair.Key); /// /// Gets all values in the map /// public IEnumerable Values => _innerMap.Values.Select(pair => pair.Value); /// /// Executes a callback for each key-value pair /// public void ForEach(Action> callback) { foreach (var (key, value) in this) { callback(value, key, this); } } }