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
}