using System.Collections; using System.Diagnostics.CodeAnalysis; using SqrtSpace.SpaceTime.Core; namespace SqrtSpace.SpaceTime.Collections; /// /// Dictionary that automatically adapts its implementation based on size /// public class AdaptiveDictionary : IDictionary, IReadOnlyDictionary where TKey : notnull { private IDictionary _implementation; private readonly AdaptiveStrategy _strategy; private readonly IEqualityComparer _comparer; // Thresholds for switching implementations private const int ArrayThreshold = 16; private const int DictionaryThreshold = 10_000; private const int ExternalThreshold = 1_000_000; /// /// Initializes a new adaptive dictionary /// public AdaptiveDictionary() : this(0, null, AdaptiveStrategy.Automatic) { } /// /// Initializes a new adaptive dictionary with specified capacity /// public AdaptiveDictionary(int capacity, IEqualityComparer? comparer = null, AdaptiveStrategy strategy = AdaptiveStrategy.Automatic) { _comparer = comparer ?? EqualityComparer.Default; _strategy = strategy; _implementation = CreateImplementation(capacity); } /// /// Gets the current implementation type /// public ImplementationType CurrentImplementation { get { return _implementation switch { ArrayDictionary => ImplementationType.Array, Dictionary => ImplementationType.Dictionary, SortedDictionary => ImplementationType.SortedDictionary, ExternalDictionary => ImplementationType.External, _ => ImplementationType.Unknown }; } } /// /// Gets memory usage statistics /// public MemoryStatistics GetMemoryStatistics() { var itemSize = IntPtr.Size * 2; // Rough estimate for key-value pair var totalSize = Count * itemSize; var memoryLevel = MemoryHierarchy.DetectSystem().GetOptimalLevel(totalSize); return new MemoryStatistics { ItemCount = Count, EstimatedMemoryBytes = totalSize, MemoryLevel = memoryLevel, Implementation = CurrentImplementation }; } #region IDictionary Implementation public TValue this[TKey key] { get => _implementation[key]; set { _implementation[key] = value; AdaptIfNeeded(); } } public ICollection Keys => _implementation.Keys; public ICollection Values => _implementation.Values; public int Count => _implementation.Count; public bool IsReadOnly => _implementation.IsReadOnly; IEnumerable IReadOnlyDictionary.Keys => Keys; IEnumerable IReadOnlyDictionary.Values => Values; public void Add(TKey key, TValue value) { _implementation.Add(key, value); AdaptIfNeeded(); } public void Add(KeyValuePair item) { _implementation.Add(item); AdaptIfNeeded(); } public void Clear() { _implementation.Clear(); AdaptIfNeeded(); } public bool Contains(KeyValuePair item) => _implementation.Contains(item); public bool ContainsKey(TKey key) => _implementation.ContainsKey(key); public void CopyTo(KeyValuePair[] array, int arrayIndex) => _implementation.CopyTo(array, arrayIndex); public bool Remove(TKey key) { var result = _implementation.Remove(key); AdaptIfNeeded(); return result; } public bool Remove(KeyValuePair item) { var result = _implementation.Remove(item); AdaptIfNeeded(); return result; } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) => _implementation.TryGetValue(key, out value); public IEnumerator> GetEnumerator() => _implementation.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); #endregion private void AdaptIfNeeded() { if (_strategy != AdaptiveStrategy.Automatic) return; IDictionary? newImplementation = Count switch { <= ArrayThreshold when CurrentImplementation != ImplementationType.Array => new ArrayDictionary(_comparer), > ArrayThreshold and <= DictionaryThreshold when CurrentImplementation == ImplementationType.Array => new Dictionary(_comparer), > DictionaryThreshold and <= ExternalThreshold when CurrentImplementation != ImplementationType.SortedDictionary => new SortedDictionary(Comparer.Create((x, y) => _comparer.GetHashCode(x).CompareTo(_comparer.GetHashCode(y)))), > ExternalThreshold when CurrentImplementation != ImplementationType.External => new ExternalDictionary(_comparer), _ => null }; if (newImplementation != null) { // Copy data to new implementation foreach (var kvp in _implementation) { newImplementation.Add(kvp); } // Dispose old implementation if needed if (_implementation is IDisposable disposable) { disposable.Dispose(); } _implementation = newImplementation; } } private IDictionary CreateImplementation(int capacity) { return capacity switch { <= ArrayThreshold => new ArrayDictionary(_comparer), <= DictionaryThreshold => new Dictionary(capacity, _comparer), <= ExternalThreshold => new SortedDictionary(Comparer.Create((x, y) => _comparer.GetHashCode(x).CompareTo(_comparer.GetHashCode(y)))), _ => new ExternalDictionary(_comparer) }; } } /// /// Array-based dictionary for small collections /// internal class ArrayDictionary : IDictionary where TKey : notnull { private readonly List> _items; private readonly IEqualityComparer _comparer; public ArrayDictionary(IEqualityComparer comparer) { _items = new List>(); _comparer = comparer; } public TValue this[TKey key] { get { var index = FindIndex(key); if (index < 0) throw new KeyNotFoundException(); return _items[index].Value; } set { var index = FindIndex(key); if (index < 0) { _items.Add(new KeyValuePair(key, value)); } else { _items[index] = new KeyValuePair(key, value); } } } public ICollection Keys => _items.Select(kvp => kvp.Key).ToList(); public ICollection Values => _items.Select(kvp => kvp.Value).ToList(); public int Count => _items.Count; public bool IsReadOnly => false; public void Add(TKey key, TValue value) { if (ContainsKey(key)) throw new ArgumentException("Key already exists"); _items.Add(new KeyValuePair(key, value)); } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public void Clear() => _items.Clear(); public bool Contains(KeyValuePair item) { var index = FindIndex(item.Key); return index >= 0 && EqualityComparer.Default.Equals(_items[index].Value, item.Value); } public bool ContainsKey(TKey key) => FindIndex(key) >= 0; public void CopyTo(KeyValuePair[] array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } public bool Remove(TKey key) { var index = FindIndex(key); if (index < 0) return false; _items.RemoveAt(index); return true; } public bool Remove(KeyValuePair item) { return _items.Remove(item); } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { var index = FindIndex(key); if (index < 0) { value = default; return false; } value = _items[index].Value; return true; } public IEnumerator> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); private int FindIndex(TKey key) { for (int i = 0; i < _items.Count; i++) { if (_comparer.Equals(_items[i].Key, key)) return i; } return -1; } } /// /// External dictionary for very large collections /// internal class ExternalDictionary : IDictionary, IDisposable where TKey : notnull { private readonly Dictionary _cache; private readonly ExternalStorage> _storage; private readonly IEqualityComparer _comparer; private readonly int _cacheSize; private int _totalCount; public ExternalDictionary(IEqualityComparer comparer) { _comparer = comparer; _cache = new Dictionary(_comparer); _storage = new ExternalStorage>(); _cacheSize = SpaceTimeCalculator.CalculateSqrtInterval(1_000_000); } public TValue this[TKey key] { get { if (_cache.TryGetValue(key, out var value)) return value; // Search in external storage foreach (var kvp in ReadAllFromStorage()) { if (_comparer.Equals(kvp.Key, key)) return kvp.Value; } throw new KeyNotFoundException(); } set { if (_cache.Count >= _cacheSize) { SpillCacheToDisk(); } _cache[key] = value; _totalCount = Math.Max(_totalCount, _cache.Count); } } public ICollection Keys => throw new NotSupportedException("Keys collection not supported for external dictionary"); public ICollection Values => throw new NotSupportedException("Values collection not supported for external dictionary"); public int Count => _totalCount; public bool IsReadOnly => false; public void Add(TKey key, TValue value) { if (ContainsKey(key)) throw new ArgumentException("Key already exists"); this[key] = value; } public void Add(KeyValuePair item) => Add(item.Key, item.Value); public void Clear() { _cache.Clear(); _storage.Dispose(); _totalCount = 0; } public bool Contains(KeyValuePair item) => ContainsKey(item.Key); public bool ContainsKey(TKey key) => _cache.ContainsKey(key) || ExistsInStorage(key); public void CopyTo(KeyValuePair[] array, int arrayIndex) => throw new NotSupportedException(); public bool Remove(TKey key) => _cache.Remove(key); public bool Remove(KeyValuePair item) => Remove(item.Key); public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { try { value = this[key]; return true; } catch (KeyNotFoundException) { value = default; return false; } } public IEnumerator> GetEnumerator() { foreach (var kvp in _cache) yield return kvp; foreach (var kvp in ReadAllFromStorage()) yield return kvp; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public void Dispose() => _storage.Dispose(); private void SpillCacheToDisk() { _storage.SpillToDiskAsync(_cache).GetAwaiter().GetResult(); _cache.Clear(); } private bool ExistsInStorage(TKey key) { foreach (var kvp in ReadAllFromStorage()) { if (_comparer.Equals(kvp.Key, key)) return true; } return false; } private IEnumerable> ReadAllFromStorage() { // This is simplified - production would be more efficient return Enumerable.Empty>(); } } /// /// Implementation type of adaptive collection /// public enum ImplementationType { Unknown, Array, Dictionary, SortedDictionary, External } /// /// Memory usage statistics /// public class MemoryStatistics { public int ItemCount { get; init; } public long EstimatedMemoryBytes { get; init; } public MemoryLevel MemoryLevel { get; init; } public ImplementationType Implementation { get; init; } } /// /// Strategy for adaptive collections /// public enum AdaptiveStrategy { /// Automatically adapt based on size Automatic, /// Always use array implementation ForceArray, /// Always use dictionary implementation ForceDictionary, /// Always use external implementation ForceExternal }