using System; using System.Collections.Generic; using MemoryPools.Collections.Specialized; namespace MemoryPools.Collections.Linq { internal sealed class GroupedEnumerable : IPoolingEnumerable> { private IPoolingEnumerable _source; private Func _keySelector; private Func _elementSelector; private IEqualityComparer _comparer; private int _count; public GroupedEnumerable Init( IPoolingEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { _source = source ?? throw new ArgumentNullException(nameof(source)); _keySelector = keySelector ?? throw new ArgumentNullException(nameof(keySelector)); _elementSelector = elementSelector ?? throw new ArgumentNullException(nameof(elementSelector)); _comparer = comparer ?? EqualityComparer.Default; _count = 0; return this; } public IPoolingEnumerator> GetEnumerator() { var tmpDict = Pool>.Get().Init(0, _comparer); PoolingGrouping grp; foreach (var item in _source) { var key = _keySelector(item); if (!tmpDict.TryGetValue(key, out grp)) { tmpDict[key] = grp = Pool.Get().Init(key); } grp.InternalList.Add(_elementSelector(item)); } _count++; return Pool.Get().Init(this, tmpDict); } private void Dispose() { if (_count == 0) return; _count--; if (_count == 0) { _comparer = default; _elementSelector = default; _keySelector = default; Pool>.Return(this); } } IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator(); internal class PoolingGroupingEnumerator : IPoolingEnumerator> { private PoolingDictionary _src; private GroupedEnumerable _parent; private IPoolingEnumerator> _enumerator; public PoolingGroupingEnumerator Init( GroupedEnumerable parent, PoolingDictionary src) { _src = src; _parent = parent; _enumerator = _src.GetEnumerator(); return this; } public void Dispose() { // Cleanup contents foreach (var grouping in _src) { grouping.Value.Dispose(); Pool.Return(grouping.Value); } // cleanup collection _src?.Dispose(); Pool>.Return(_src); _src = default; _enumerator?.Dispose(); _enumerator = default; _parent?.Dispose(); _parent = default; Pool.Return(this); } public bool MoveNext() => _enumerator.MoveNext(); public void Reset() => _enumerator.Reset(); public IPoolingGrouping Current => _enumerator.Current.Value; object IPoolingEnumerator.Current => Current; } internal class PoolingGrouping : IPoolingGrouping, IDisposable { private PoolingList _elements; public PoolingGrouping Init(TKey key) { _elements = Pool>.Get().Init(); Key = key; return this; } internal PoolingList InternalList => _elements; public IPoolingEnumerator GetEnumerator() => _elements.GetEnumerator(); IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator(); public TKey Key { get; private set; } public void Dispose() { _elements?.Dispose(); Pool>.Return(_elements); _elements = null; Key = default; } } } }