using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace TechbloxModdingAPI.Utility { public class WeakDictionary : IDictionary where TValue : class { private readonly Dictionary> _dictionary = new(); public IEnumerator> GetEnumerator() { using var enumerator = _dictionary.GetEnumerator(); while (enumerator.MoveNext()) { if (enumerator.Current.Value.TryGetTarget(out var value)) yield return new KeyValuePair(enumerator.Current.Key, value); } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public void Add(KeyValuePair item) => Add(item.Key, item.Value); public void Clear() => _dictionary.Clear(); public bool Contains(KeyValuePair item) => TryGetValue(item.Key, out var value) && item.Value == value; public void CopyTo(KeyValuePair[] array, int arrayIndex) => throw new System.NotImplementedException(); public bool Remove(KeyValuePair item) => Contains(item) && Remove(item.Key); public int Count => _dictionary.Count; public bool IsReadOnly => false; public bool ContainsKey(TKey key) => TryGetValue(key, out _); public void Add(TKey key, TValue value) => _dictionary.Add(key, new WeakReference(value)); public bool Remove(TKey key) => _dictionary.Remove(key); public bool TryGetValue(TKey key, out TValue value) { value = null; bool ret = _dictionary.TryGetValue(key, out var reference) && reference.TryGetTarget(out value); if (!ret) _dictionary.Remove(key); return ret; } public TValue this[TKey key] { get => TryGetValue(key, out var value) ? value : throw new KeyNotFoundException($"Key {key} not found in WeakDictionary."); set => _dictionary[key] = new WeakReference(value); } public ICollection Keys => new KeyCollection(this); public ICollection Values => new ValueCollection(this); public class KeyCollection : ICollection, IReadOnlyCollection { private readonly WeakDictionary _dictionary; internal KeyCollection(WeakDictionary dictionary) { _dictionary = dictionary; } public IEnumerator GetEnumerator() { using var enumerator = _dictionary.GetEnumerator(); while (enumerator.MoveNext()) yield return enumerator.Current.Key; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public void Add(TKey item) => throw new NotSupportedException("The key collection is read only."); public void Clear() => throw new NotSupportedException("The key collection is read only."); public bool Contains(TKey item) => _dictionary.ContainsKey(item); public void CopyTo(TKey[] array, int arrayIndex) => throw new NotImplementedException(); public bool Remove(TKey item) => throw new NotSupportedException("The key collection is read only."); public int Count => _dictionary.Count; public bool IsReadOnly => true; } public class ValueCollection : ICollection, IReadOnlyCollection { private readonly WeakDictionary _dictionary; internal ValueCollection(WeakDictionary dictionary) { _dictionary = dictionary; } public IEnumerator GetEnumerator() { using var enumerator = _dictionary.GetEnumerator(); while (enumerator.MoveNext()) yield return enumerator.Current.Value; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public void Add(TValue item) => throw new NotSupportedException("The value collection is read only."); public void Clear() => throw new NotSupportedException("The value collection is read only."); public bool Contains(TValue item) => _dictionary.Any(kv => kv.Value == item); public void CopyTo(TValue[] array, int arrayIndex) => throw new NotImplementedException(); public bool Remove(TValue item) => throw new NotSupportedException("The value collection is read only."); public int Count => _dictionary.Count; public bool IsReadOnly => true; } } }