You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/MemoryPools/Collections/Linq/GroupBy.ResultEnumerable.cs

142 lines
4.9 KiB

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

Powered by TurnKey Linux.