New pools and pool collections implementations

https://github.com/sidristij/memory-pools
pull/1/head
unknown 3 years ago
parent 8947bb5c7d
commit 4c55c887f3

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Threading;
namespace ZeroLevel.Services.Collections
{
public class ConcurrentHashSet<T> : IDisposable
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private readonly HashSet<T> _hashSet = new HashSet<T>();
#region Implementation of ICollection<T> ...ish
public bool Add(T item)
{
_lock.EnterWriteLock();
try
{
return _hashSet.Add(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public void Clear()
{
_lock.EnterWriteLock();
try
{
_hashSet.Clear();
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public bool Contains(T item)
{
_lock.EnterReadLock();
try
{
return _hashSet.Contains(item);
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
public bool Remove(T item)
{
_lock.EnterWriteLock();
try
{
return _hashSet.Remove(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public int Count
{
get
{
_lock.EnterReadLock();
try
{
return _hashSet.Count;
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
}
#endregion
#region Dispose
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
if (_lock != null)
_lock.Dispose();
}
~ConcurrentHashSet()
{
Dispose(false);
}
#endregion
}
}

@ -83,8 +83,8 @@ namespace DOM.DSL.Services
#endregion Private classes #endregion Private classes
private readonly TContainerFactory _factory; private TContainerFactory _factory;
private readonly TRender _render; private TRender _render;
private object _current; private object _current;
public int Index { get; set; } public int Index { get; set; }
@ -136,7 +136,9 @@ namespace DOM.DSL.Services
} }
} }
public TContainer(TContainerFactory factory, TRender render) public TContainer() { }
public void Init(TContainerFactory factory, TRender render)
{ {
this._factory = factory; this._factory = factory;
this._render = render; this._render = render;

@ -1,24 +1,26 @@
using System.Threading; using MemoryPools;
using ZeroLevel.Services.Pools; using System.Threading;
namespace DOM.DSL.Services namespace DOM.DSL.Services
{ {
public class TContainerFactory public class TContainerFactory
{ {
private readonly Pool<TContainer> _pool; private readonly DefaultObjectPool<TContainer> _pool;
private readonly TRender _render;
private static int _get_count = 0; private static int _get_count = 0;
private static int _release_count = 0; private static int _release_count = 0;
internal TContainerFactory(TRender render) internal TContainerFactory(TRender render)
{ {
_pool = new Pool<TContainer>(64, p => new TContainer(this, render)); _render = render;
_pool = new DefaultObjectPool<TContainer>(new DefaultPooledObjectPolicy<TContainer>());
} }
internal TContainer Get(object value) internal TContainer Get(object value)
{ {
Interlocked.Increment(ref _get_count); Interlocked.Increment(ref _get_count);
var c = _pool.Acquire(); var c = _pool.Get();
c.Init(this, _render);
c.Reset(value); c.Reset(value);
return c; return c;
} }
@ -26,7 +28,8 @@ namespace DOM.DSL.Services
internal TContainer Get(object value, int index) internal TContainer Get(object value, int index)
{ {
Interlocked.Increment(ref _get_count); Interlocked.Increment(ref _get_count);
var c = _pool.Acquire(); var c = _pool.Get();
c.Init(this, _render);
c.Reset(value); c.Reset(value);
c.Index = index; c.Index = index;
return c; return c;
@ -37,7 +40,7 @@ namespace DOM.DSL.Services
if (container != null) if (container != null)
{ {
Interlocked.Increment(ref _release_count); Interlocked.Increment(ref _release_count);
_pool.Release(container); _pool.Return(container);
} }
} }

@ -0,0 +1,27 @@
using MemoryPools.Collections.Linq;
using System.Collections.Generic;
/*https://github.com/sidristij/memory-pools/blob/master/MemoryPools.Collections*/
namespace MemoryPools.Collections
{
public interface IPoolingEnumerable
{
// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
IPoolingEnumerator GetEnumerator();
}
public static partial class EnumerableEx
{
public static IPoolingEnumerable<T> AsPooling<T>(this IEnumerable<T> source)
{
return Pool<GenericPoolingEnumerable<T>>.Get().Init(source);
}
public static IEnumerable<T> AsEnumerable<T>(this IPoolingEnumerable<T> source)
{
return Pool<GenericEnumerable<T>>.Get().Init(source);
}
}
}

@ -0,0 +1,11 @@
/*https://github.com/sidristij/memory-pools/blob/master/MemoryPools.Collections*/
namespace MemoryPools.Collections
{
public interface IPoolingEnumerable<out T> : IPoolingEnumerable
{
// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
new IPoolingEnumerator<T> GetEnumerator();
}
}

@ -0,0 +1,22 @@
using System;
/*https://github.com/sidristij/memory-pools/blob/master/MemoryPools.Collections*/
namespace MemoryPools.Collections
{
public interface IPoolingEnumerator : IDisposable
{
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.</returns>
/// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created.</exception>
bool MoveNext();
/// <summary>Sets the enumerator to its initial position, which is before the first element in the collection.</summary>
/// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created.</exception>
void Reset();
// <summary>Gets the element in the collection at the current position of the enumerator.</summary>
/// <returns>The element in the collection at the current position of the enumerator.</returns>
object Current { get; }
}
}

@ -0,0 +1,11 @@
/*https://github.com/sidristij/memory-pools/blob/master/MemoryPools.Collections*/
namespace MemoryPools.Collections
{
public interface IPoolingEnumerator<out T> : IPoolingEnumerator
{
// <summary>Gets the element in the collection at the current position of the enumerator.</summary>
/// <returns>The element in the collection at the current position of the enumerator.</returns>
new T Current { get; }
}
}

@ -0,0 +1,9 @@
/*https://github.com/sidristij/memory-pools/blob/master/MemoryPools.Collections*/
namespace MemoryPools.Collections
{
public interface IPoolingGrouping<out TKey, out TElement> : IPoolingEnumerable<TElement>
{
TKey Key { get; }
}
}

@ -0,0 +1,82 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static TSource Aggregate<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (func == null)
{
throw new ArgumentNullException(nameof(func));
}
using (var enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
var result = enumerator.Current;
while (enumerator.MoveNext())
{
result = func(result, enumerator.Current);
}
return result;
}
}
public static TAccumulate Aggregate<TSource, TAccumulate>(this IPoolingEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (func == null)
{
throw new ArgumentNullException(nameof(func));
}
var result = seed;
foreach (var element in source)
{
result = func(result, element);
}
return result;
}
public static TResult Aggregate<TSource, TAccumulate, TResult>(this IPoolingEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (func == null)
{
throw new ArgumentNullException(nameof(func));
}
if (resultSelector == null)
{
throw new ArgumentNullException(nameof(resultSelector));
}
var result = seed;
foreach (var element in source)
{
result = func(result, element);
}
return resultSelector(result);
}
}
}

@ -0,0 +1,76 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static bool Any<T>(this IPoolingEnumerable<T> source)
{
var enumerator = source.GetEnumerator();
var hasItems = enumerator.MoveNext();
enumerator.Dispose();
return hasItems;
}
public static bool Any<T>(this IPoolingEnumerable<T> source, Func<T, bool> condition)
{
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (condition(enumerator.Current))
{
enumerator.Dispose();
return true;
}
}
enumerator.Dispose();
return false;
}
public static bool Any<T, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, bool> condition)
{
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (condition(context, enumerator.Current))
{
enumerator.Dispose();
return true;
}
}
enumerator.Dispose();
return false;
}
public static bool All<T>(this IPoolingEnumerable<T> source, Func<T, bool> condition)
{
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (!condition(enumerator.Current))
{
enumerator.Dispose();
return false;
}
}
enumerator.Dispose();
return true;
}
public static bool All<T, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, bool> condition)
{
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (!condition(context, enumerator.Current))
{
enumerator.Dispose();
return false;
}
}
enumerator.Dispose();
return true;
}
}
}

@ -0,0 +1,91 @@
namespace MemoryPools.Collections.Linq
{
internal class AppendExprEnumerable<T> : IPoolingEnumerable<T>
{
private int _count;
private IPoolingEnumerable<T> _src;
private T _element;
public AppendExprEnumerable<T> Init(IPoolingEnumerable<T> src, T element)
{
_src = src;
_count = 0;
_element = element;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<AppendExprEnumerator>.Get().Init(_src.GetEnumerator(), this, _element);
}
private void Dispose()
{
if(_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_element = default;
Pool<AppendExprEnumerable<T>>.Return(this);
}
}
internal class AppendExprEnumerator : IPoolingEnumerator<T>
{
private IPoolingEnumerator _src;
private AppendExprEnumerable<T> _parent;
private T _element;
private int _overcount;
public AppendExprEnumerator Init(IPoolingEnumerator src, AppendExprEnumerable<T> parent, T element)
{
_src = src;
_parent = parent;
_element = element;
_overcount = 0;
return this;
}
public bool MoveNext()
{
if (!_src.MoveNext())
{
if (_overcount == 0)
{
_overcount++;
return true;
}
_overcount++;
return false;
}
return true;
}
public void Reset()
{
_overcount = 0;
_src.Reset();
}
object IPoolingEnumerator.Current => Current;
public T Current => _overcount == 1 ? _element : (T) _src.Current;
public void Dispose()
{
_parent?.Dispose();
_parent = null;
_src?.Dispose();
_src = default;
Pool<AppendExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,11 @@
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<T> Prepend<T>(this IPoolingEnumerable<T> source, T element) =>
Pool<PrependExprEnumerable<T>>.Get().Init(source, element);
public static IPoolingEnumerable<T> Append<T>(this IPoolingEnumerable<T> source, T element) =>
Pool<AppendExprEnumerable<T>>.Get().Init(source, element);
}
}

@ -0,0 +1,98 @@
using MemoryPools.Collections.Specialized;
using System;
using System.Collections.Generic;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static PoolingList<T> AsPoolingList<T>(this IEnumerable<T> source)
{
var collection = Pool<PoolingList<T>>.Get().Init();
collection.AddRange(source);
return collection;
}
public static PoolingList<T> AsPoolingList<T>(this IPoolingEnumerable<T> source)
{
var collection = Pool<PoolingList<T>>.Get().Init();
collection.AddRange(source);
return collection;
}
public static PoolingDictionary<TK, TV> AsPoolingDictionary<TK, TV>(this IEnumerable<KeyValuePair<TK, TV>> source)
{
return AsPoolingDictionary(source.AsPooling());
}
public static PoolingDictionary<TK, TV> AsPoolingDictionary<TK, TV>(this IPoolingEnumerable<KeyValuePair<TK, TV>> source)
{
var collection = Pool<PoolingDictionary<TK, TV>>.Get().Init();
collection.AddRange(source);
return collection;
}
public static PoolingDictionary<TKey, TValue> AsPoolingDictionary<TSource, TKey, TValue>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TValue> valueSelector)
{
return AsPoolingDictionary(source.AsPooling(), keySelector, valueSelector);
}
public static PoolingDictionary<TKey, TValue> AsPoolingDictionary<TSource, TKey, TValue>(this IPoolingEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TValue> valueSelector)
{
var collection = Pool<PoolingDictionary<TKey, TValue>>.Get().Init();
collection.AddRange(
source
.Select((keySelector, valueSelector), (ctx, x) => new KeyValuePair<TKey, TValue>(ctx.keySelector(x), ctx.valueSelector(x)))
);
return collection;
}
public static void AddRange<T>(this PoolingList<T> target, IEnumerable<T> src)
{
foreach (var item in src)
{
target.Add(item);
}
}
public static void AddRange<T>(this PoolingList<T> target, IPoolingEnumerable<T> src)
{
foreach (var item in src)
{
target.Add(item);
}
}
public static void AddRange<TK, TV>(this PoolingDictionary<TK, TV> target, IEnumerable<KeyValuePair<TK, TV>> src)
{
foreach (var item in src)
{
target.Add(item.Key, item.Value);
}
}
public static void AddRange<TK, TV>(this PoolingDictionary<TK, TV> target, IPoolingEnumerable<KeyValuePair<TK, TV>> src)
{
foreach (var item in src)
{
target.Add(item.Key, item.Value);
}
}
public static void AddRangeSafe<TK, TV>(this PoolingDictionary<TK, TV> target, IEnumerable<KeyValuePair<TK, TV>> src)
{
foreach (var item in src)
{
target[item.Key] = item.Value;
}
}
public static void AddRangeSafe<TK, TV>(this PoolingDictionary<TK, TV> target, IPoolingEnumerable<KeyValuePair<TK, TV>> src)
{
foreach (var item in src)
{
target[item.Key] = item.Value;
}
}
}
}

@ -0,0 +1,759 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double Average(this IPoolingEnumerable<int> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (var enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
{
// throw new InvalidOperationException("Sequence contains no elements");
}
long sum = enumerator.Current;
long count = 1;
checked
{
while (enumerator.MoveNext())
{
sum += enumerator.Current;
++count;
}
}
return (double)sum / count;
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double? Average(this IPoolingEnumerable<int?> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (var e = source.GetEnumerator())
{
while (e.MoveNext())
{
int? v = e.Current;
if (v.HasValue)
{
long sum = v.GetValueOrDefault();
long count = 1;
checked
{
while (e.MoveNext())
{
v = e.Current;
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
}
return (double)sum / count;
}
}
}
return null;
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double Average(this IPoolingEnumerable<long> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (var e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
long sum = e.Current;
long count = 1;
checked
{
while (e.MoveNext())
{
sum += e.Current;
++count;
}
}
return (double)sum / count;
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double? Average(this IPoolingEnumerable<long?> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (IPoolingEnumerator<long?> e = source.GetEnumerator())
{
while (e.MoveNext())
{
long? v = e.Current;
if (v.HasValue)
{
long sum = v.GetValueOrDefault();
long count = 1;
checked
{
while (e.MoveNext())
{
v = e.Current;
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
}
return (double)sum / count;
}
}
}
return null;
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static float Average(this IPoolingEnumerable<float> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (IPoolingEnumerator<float> e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
double sum = e.Current;
long count = 1;
while (e.MoveNext())
{
sum += e.Current;
++count;
}
return (float)(sum / count);
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static float? Average(this IPoolingEnumerable<float?> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (IPoolingEnumerator<float?> e = source.GetEnumerator())
{
while (e.MoveNext())
{
float? v = e.Current;
if (v.HasValue)
{
double sum = v.GetValueOrDefault();
long count = 1;
checked
{
while (e.MoveNext())
{
v = e.Current;
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
}
return (float)(sum / count);
}
}
}
return null;
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double Average(this IPoolingEnumerable<double> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (IPoolingEnumerator<double> e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
double sum = e.Current;
long count = 1;
while (e.MoveNext())
{
// There is an opportunity to short-circuit here, in that if e.Current is
// ever NaN then the result will always be NaN. Assuming that this case is
// rare enough that not checking is the better approach generally.
sum += e.Current;
++count;
}
return sum / count;
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double? Average(this IPoolingEnumerable<double?> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (IPoolingEnumerator<double?> e = source.GetEnumerator())
{
while (e.MoveNext())
{
double? v = e.Current;
if (v.HasValue)
{
double sum = v.GetValueOrDefault();
long count = 1;
checked
{
while (e.MoveNext())
{
v = e.Current;
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
}
return sum / count;
}
}
}
return null;
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static decimal Average(this IPoolingEnumerable<decimal> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (IPoolingEnumerator<decimal> e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
decimal sum = e.Current;
long count = 1;
while (e.MoveNext())
{
sum += e.Current;
++count;
}
return sum / count;
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static decimal? Average(this IPoolingEnumerable<decimal?> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
using (IPoolingEnumerator<decimal?> e = source.GetEnumerator())
{
while (e.MoveNext())
{
decimal? v = e.Current;
if (v.HasValue)
{
decimal sum = v.GetValueOrDefault();
long count = 1;
while (e.MoveNext())
{
v = e.Current;
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
return sum / count;
}
}
}
return null;
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, int> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (var e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
long sum = selector(e.Current);
long count = 1;
checked
{
while (e.MoveNext())
{
sum += selector(e.Current);
++count;
}
}
return (double)sum / count;
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double? Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, int?> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (var e = source.GetEnumerator())
{
while (e.MoveNext())
{
int? v = selector(e.Current);
if (v.HasValue)
{
long sum = v.GetValueOrDefault();
long count = 1;
checked
{
while (e.MoveNext())
{
v = selector(e.Current);
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
}
return (double)sum / count;
}
}
}
return null;
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, long> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (var e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
long sum = selector(e.Current);
long count = 1;
checked
{
while (e.MoveNext())
{
sum += selector(e.Current);
++count;
}
}
return (double)sum / count;
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double? Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, long?> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (var e = source.GetEnumerator())
{
while (e.MoveNext())
{
long? v = selector(e.Current);
if (v.HasValue)
{
long sum = v.GetValueOrDefault();
long count = 1;
checked
{
while (e.MoveNext())
{
v = selector(e.Current);
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
}
return (double)sum / count;
}
}
}
return null;
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static float Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, float> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (IPoolingEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
double sum = selector(e.Current);
long count = 1;
while (e.MoveNext())
{
sum += selector(e.Current);
++count;
}
return (float)(sum / count);
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static float? Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, float?> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (IPoolingEnumerator<TSource> e = source.GetEnumerator())
{
while (e.MoveNext())
{
float? v = selector(e.Current);
if (v.HasValue)
{
double sum = v.GetValueOrDefault();
long count = 1;
checked
{
while (e.MoveNext())
{
v = selector(e.Current);
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
}
return (float)(sum / count);
}
}
}
return null;
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, double> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (IPoolingEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
double sum = selector(e.Current);
long count = 1;
while (e.MoveNext())
{
// There is an opportunity to short-circuit here, in that if e.Current is
// ever NaN then the result will always be NaN. Assuming that this case is
// rare enough that not checking is the better approach generally.
sum += selector(e.Current);
++count;
}
return sum / count;
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static double? Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, double?> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (IPoolingEnumerator<TSource> e = source.GetEnumerator())
{
while (e.MoveNext())
{
double? v = selector(e.Current);
if (v.HasValue)
{
double sum = v.GetValueOrDefault();
long count = 1;
checked
{
while (e.MoveNext())
{
v = selector(e.Current);
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
}
return sum / count;
}
}
}
return null;
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static decimal Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, decimal> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (IPoolingEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
decimal sum = selector(e.Current);
long count = 1;
while (e.MoveNext())
{
sum += selector(e.Current);
++count;
}
return sum / count;
}
}
/// <summary>
/// Calculates avg of all given numbers. Complexity = O(N)
/// </summary>
public static decimal? Average<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, decimal?> selector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
using (IPoolingEnumerator<TSource> e = source.GetEnumerator())
{
while (e.MoveNext())
{
decimal? v = selector(e.Current);
if (v.HasValue)
{
decimal sum = v.GetValueOrDefault();
long count = 1;
while (e.MoveNext())
{
v = selector(e.Current);
if (v.HasValue)
{
sum += v.GetValueOrDefault();
++count;
}
}
return sum / count;
}
}
}
return null;
}
}
}

@ -0,0 +1,71 @@
namespace MemoryPools.Collections.Linq
{
internal class CastExprEnumerable<T> : IPoolingEnumerable<T>
{
private int _count;
private IPoolingEnumerable _src;
public CastExprEnumerable<T> Init(IPoolingEnumerable src)
{
_src = src;
_count = 0;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<CastExprEnumerator>.Get().Init(_src.GetEnumerator(), this);
}
private void Dispose()
{
if(_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
Pool<CastExprEnumerable<T>>.Return(this);
}
}
internal class CastExprEnumerator : IPoolingEnumerator<T>
{
private IPoolingEnumerator _src;
private CastExprEnumerable<T> _parent;
public CastExprEnumerator Init(IPoolingEnumerator src, CastExprEnumerable<T> parent)
{
_src = src;
_parent = parent;
return this;
}
public bool MoveNext()
{
return _src.MoveNext();
}
public void Reset()
{
_src.Reset();
}
object IPoolingEnumerator.Current => Current;
public T Current => (T)_src.Current;
public void Dispose()
{
_parent?.Dispose();
_parent = null;
_src?.Dispose();
_src = default;
Pool<CastExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,14 @@
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
/// <summary>
/// Casts all elements to the given type. Complexity = O(N)
/// </summary>
public static IPoolingEnumerable<TR> Cast<TR>(this IPoolingEnumerable source)
{
if (source is IPoolingEnumerable<TR> res) return res;
return Pool<CastExprEnumerable<TR>>.Get().Init(source);
}
}
}

@ -0,0 +1,93 @@
namespace MemoryPools.Collections.Linq
{
internal class ConcatExprEnumerable<T> : IPoolingEnumerable<T>
{
private IPoolingEnumerable<T> _src, _second;
private int _count;
public ConcatExprEnumerable<T> Init(IPoolingEnumerable<T> src, IPoolingEnumerable<T> second)
{
_src = src;
_count = 0;
_second = second;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<ConcatExprEnumerator>.Get().Init(this, _src.GetEnumerator(), _second.GetEnumerator());
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_second = default;
Pool<ConcatExprEnumerable<T>>.Return(this);
}
}
internal class ConcatExprEnumerator : IPoolingEnumerator<T>
{
private ConcatExprEnumerable<T> _parent;
private IPoolingEnumerator<T> _src, _second;
private bool _first;
public ConcatExprEnumerator Init(
ConcatExprEnumerable<T> parent, IPoolingEnumerator<T> src, IPoolingEnumerator<T> second)
{
_parent = parent;
_src = src;
_second = second;
_first = true;
return this;
}
public bool MoveNext()
{
if (_first)
{
if (_src.MoveNext())
{
return true;
}
_first = false;
}
return _second.MoveNext();
}
public void Reset()
{
_first = true;
_src.Reset();
_second.Reset();
}
object IPoolingEnumerator.Current => Current;
public T Current => _first ? _src.Current : _second.Current;
public void Dispose()
{
_parent?.Dispose();
_parent = default;
_src?.Dispose();
_src = default;
_second?.Dispose();
_second = default;
Pool<ConcatExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,11 @@
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
/// <summary>
/// Returns all elements from <paramref name="source"/> and all -- from <paramref name="second"/>. Complexity = O(N+M)
/// </summary>
public static IPoolingEnumerable<T> Concat<T>(this IPoolingEnumerable<T> source, IPoolingEnumerable<T> second) =>
Pool<ConcatExprEnumerable<T>>.Get().Init(source, second);
}
}

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
internal class DistinctExprEnumerable<T, TItem> : IPoolingEnumerable<T>
{
private int _count;
private IPoolingEnumerator<T> _parent;
private IEqualityComparer<TItem> _comparer;
private Func<T, TItem> _selector;
public DistinctExprEnumerable<T, TItem> Init(IPoolingEnumerator<T> parent, Func<T, TItem> selector, IEqualityComparer<TItem> comparer = default)
{
_parent = parent;
_selector = selector;
_comparer = comparer;
_count = 0;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<DistinctExprEnumerator>.Get().Init(this, _parent, _selector, _comparer);
}
private void Dispose()
{
if(_count == 0) return;
_count--;
if (_count == 0)
{
_parent?.Dispose();
_parent = default;
_selector = default;
Pool<DistinctExprEnumerable<T, TItem>>.Return(this);
}
}
internal class DistinctExprEnumerator : IPoolingEnumerator<T>
{
private IPoolingEnumerator<T> _src;
private Func<T, TItem> _selector;
private PoolingDictionary<TItem, int> _hashset;
private DistinctExprEnumerable<T, TItem> _parent;
public DistinctExprEnumerator Init(
DistinctExprEnumerable<T, TItem> parent,
IPoolingEnumerator<T> src,
Func<T, TItem> selector,
IEqualityComparer<TItem> comparer)
{
_src = src;
_parent = parent;
_selector = selector;
_hashset = Pool<PoolingDictionary<TItem, int>>.Get().Init(0, comparer ?? EqualityComparer<TItem>.Default);
return this;
}
public bool MoveNext()
{
while (_src.MoveNext())
{
var key = _selector(_src.Current);
if(_hashset.ContainsKey(key)) continue;
_hashset[key] = 1;
return true;
}
return false;
}
public void Reset() => _src.Reset();
object IPoolingEnumerator.Current => Current;
public T Current => _src.Current;
public void Dispose()
{
_parent?.Dispose();
_parent = default;
_hashset?.Dispose();
_hashset = default;
_src = default;
_selector = default;
Pool<DistinctExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
/// <summary>
/// Returns distinct elements from a sequence by using the default equality comparer to compare values. Complexity - O(N)
/// </summary>
public static IPoolingEnumerable<T> Distinct<T>(this IPoolingEnumerable<T> source) =>
Pool<DistinctExprEnumerable<T, T>>.Get().Init(source.GetEnumerator(), x => x);
/// <summary>
/// Returns distinct elements from a sequence by using the default equality comparer to compare values and selector to select key to compare by. Complexity - O(N)
/// </summary>
public static IPoolingEnumerable<T> DistinctBy<T, TItem>(
this IPoolingEnumerable<T> source,
Func<T, TItem> selector) =>
Pool<DistinctExprEnumerable<T, TItem>>.Get().Init(source.GetEnumerator(), selector);
/// <summary>
/// Returns distinct elements from a sequence by using a specified <paramref name="comparer"/> to compare values. Complexity - O(N)
/// </summary>
public static IPoolingEnumerable<T> Distinct<T>(
this IPoolingEnumerable<T> source,
IEqualityComparer<T> comparer) =>
Pool<DistinctExprEnumerable<T, T>>.Get().Init(source.GetEnumerator(), x => x,comparer);
/// <summary>
/// Returns distinct elements from a sequence by using a specified <paramref name="comparer"/> to compare values and selector to select key to compare by. Complexity - O(N)
/// </summary>
public static IPoolingEnumerable<T> DistinctBy<T, TItem>(
this IPoolingEnumerable<T> source,
Func<T, TItem> selector,
IEqualityComparer<TItem> comparer) =>
Pool<DistinctExprEnumerable<T, TItem>>.Get().Init(source.GetEnumerator(), selector, comparer);
}
}

@ -0,0 +1,83 @@
using System.Collections.Generic;
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
internal class ExceptExprEnumerable<T> : IPoolingEnumerable<T>
{
private int _count;
private IPoolingEnumerable<T> _src;
private IEqualityComparer<T> _comparer;
private PoolingDictionary<T, int> _except;
public ExceptExprEnumerable<T> Init(IPoolingEnumerable<T> src, PoolingDictionary<T, int> except, IEqualityComparer<T> comparer = default)
{
_src = src;
_except = except;
_comparer = comparer;
_count = 0;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<ExceptExprEnumerator>.Get().Init(this, _src.GetEnumerator());
}
private void Dispose()
{
if(_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_except?.Dispose();
Pool<PoolingDictionary<T, int>>.Return(_except);
_except = default;
Pool<ExceptExprEnumerable<T>>.Return(this);
}
}
internal class ExceptExprEnumerator : IPoolingEnumerator<T>
{
private ExceptExprEnumerable<T> _parent;
private IPoolingEnumerator<T> _src;
public ExceptExprEnumerator Init(ExceptExprEnumerable<T> parent, IPoolingEnumerator<T> src)
{
_src = src;
_parent = parent;
return this;
}
public bool MoveNext()
{
while (_src.MoveNext())
{
if(_parent._except.ContainsKey(_src.Current)) continue;
return true;
}
return false;
}
public void Reset() => _src.Reset();
object IPoolingEnumerator.Current => Current;
public T Current => _src.Current;
public void Dispose()
{
_src?.Dispose();
_src = null;
_parent?.Dispose();
_parent = default;
Pool<ExceptExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,24 @@
using System.Collections.Generic;
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<T> Except<T>(this IPoolingEnumerable<T> source, IPoolingEnumerable<T> except)
{
var exceptDict = Pool<PoolingDictionary<T, int>>.Get().Init(0);
foreach (var item in except) exceptDict[item] = 1;
return Pool<ExceptExprEnumerable<T>>.Get().Init(source, exceptDict);
}
public static IPoolingEnumerable<T> Except<T>(this IPoolingEnumerable<T> source, IPoolingEnumerable<T> except, IEqualityComparer<T> comparer)
{
var exceptDict = Pool<PoolingDictionary<T, int>>.Get().Init(0);
foreach (var item in except) exceptDict[item] = 1;
return Pool<ExceptExprEnumerable<T>>.Get().Init(source, exceptDict, comparer);
}
}
}

@ -0,0 +1,110 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
/// <summary>
/// Gets first element from sequence. Complexity = O(1)
/// </summary>
public static T First<T>(this IPoolingEnumerable<T> source)
{
var enumerator = source.GetEnumerator();
var hasItems = enumerator.MoveNext();
if (!hasItems)
{
throw new InvalidOperationException("Sequence is empty");
}
var element = enumerator.Current;
enumerator.Dispose();
return element;
}
/// <summary>
/// Gets first element from sequence by given <paramref name="condition"/>. Complexity = O(1) - O(N)
/// </summary>
public static T First<T>(this IPoolingEnumerable<T> source, Func<T, bool> condition)
{
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (condition(enumerator.Current))
{
var item = enumerator.Current;
enumerator.Dispose();
return item;
}
}
enumerator.Dispose();
throw new InvalidOperationException("Sequence is empty");
}
/// <summary>
/// Gets first element from sequence by given <paramref name="condition"/>. Complexity = O(1) - O(N)
/// </summary>
public static T First<T, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, bool> condition)
{
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (!condition(context, enumerator.Current)) continue;
var item = enumerator.Current;
enumerator.Dispose();
return item;
}
enumerator.Dispose();
throw new InvalidOperationException("Sequence is empty");
}
/// <summary>
/// Gets first element from sequence. Complexity = O(1)
/// </summary>
public static T FirstOrDefault<T>(this IPoolingEnumerable<T> source)
{
var enumerator = source.GetEnumerator();
var hasItem = enumerator.MoveNext();
var item= hasItem ? enumerator.Current : default;
enumerator.Dispose();
return item;
}
/// <summary>
/// Gets first element from sequence by given <paramref name="condition"/>. Complexity = O(1) - O(N)
/// </summary>
public static T FirstOrDefault<T>(this IPoolingEnumerable<T> source, Func<T, bool> condition)
{
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (!condition(enumerator.Current)) continue;
var elem = enumerator.Current;
enumerator.Dispose();
return elem;
}
enumerator.Dispose();
return default;
}
/// <summary>
/// Gets first element from sequence by given <paramref name="condition"/>. Complexity = O(1) - O(N)
/// </summary>
public static T FirstOrDefault<T, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, bool> condition)
{
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (!condition(context, enumerator.Current)) continue;
var elem = enumerator.Current;
enumerator.Dispose();
return elem;
}
enumerator.Dispose();
return default;
}
}
}

@ -0,0 +1,52 @@
using System.Collections;
using System.Collections.Generic;
namespace MemoryPools.Collections.Linq
{
internal class GenericPoolingEnumerable<T> : IPoolingEnumerable<T>
{
private IEnumerable<T> _enumerable;
public GenericPoolingEnumerable<T> Init(IEnumerable<T> enumerable)
{
_enumerable = enumerable;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
var enumerator = _enumerable.GetEnumerator();
_enumerable = default;
Pool<GenericPoolingEnumerable<T>>.Return(this);
return Pool<GenericPoolingEnumerator<T>>.Get().Init(enumerator);
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
internal class GenericEnumerable<T> : IEnumerable<T>
{
private IPoolingEnumerable<T> _enumerable;
public GenericEnumerable<T> Init(IPoolingEnumerable<T> enumerable)
{
_enumerable = enumerable;
return this;
}
public IEnumerator<T> GetEnumerator()
{
var enumerator = _enumerable.GetEnumerator();
_enumerable = default;
Pool<GenericEnumerable<T>>.Return(this);
return Pool<GenericEnumerator<T>>.Get().Init(enumerator);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,57 @@
using System.Collections;
using System.Collections.Generic;
namespace MemoryPools.Collections.Linq
{
internal sealed class GenericPoolingEnumerator<T> : IPoolingEnumerator<T>
{
private IEnumerator<T> _source;
public GenericPoolingEnumerator<T> Init(IEnumerator<T> source)
{
_source = source;
return this;
}
public bool MoveNext() => _source.MoveNext();
public void Reset() => _source.Reset();
object IPoolingEnumerator.Current => Current;
public T Current => _source.Current;
public void Dispose()
{
_source.Dispose();
_source = default;
Pool<GenericPoolingEnumerator<T>>.Return(this);
}
}
internal sealed class GenericEnumerator<T> : IEnumerator<T>
{
private IPoolingEnumerator<T> _source;
public GenericEnumerator<T> Init(IPoolingEnumerator<T> source)
{
_source = source;
return this;
}
public bool MoveNext() => _source.MoveNext();
public void Reset() => _source.Reset();
object IEnumerator.Current => Current;
public T Current => _source.Current;
public void Dispose()
{
_source.Dispose();
_source = default;
Pool<GenericEnumerator<T>>.Return(this);
}
}
}

@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
internal sealed class GroupedEnumerable<TSource, TKey, TElement> : IPoolingEnumerable<IPoolingGrouping<TKey, TElement>>
{
private IPoolingEnumerable<TSource> _source;
private Func<TSource, TKey> _keySelector;
private Func<TSource, TElement> _elementSelector;
private IEqualityComparer<TKey> _comparer;
private int _count;
public GroupedEnumerable<TSource, TKey, TElement> Init(
IPoolingEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> 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<TKey>.Default;
_count = 0;
return this;
}
public IPoolingEnumerator<IPoolingGrouping<TKey, TElement>> 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(_elementSelector(item));
}
_count++;
return Pool<PoolingGroupingEnumerator>.Get().Init(this, tmpDict);
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_comparer = default;
_elementSelector = default;
_keySelector = default;
Pool<GroupedEnumerable<TSource, TKey, TElement>>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
internal class PoolingGroupingEnumerator : IPoolingEnumerator<IPoolingGrouping<TKey, TElement>>
{
private PoolingDictionary<TKey, PoolingGrouping> _src;
private GroupedEnumerable<TSource, TKey, TElement> _parent;
private IPoolingEnumerator<KeyValuePair<TKey, PoolingGrouping>> _enumerator;
public PoolingGroupingEnumerator Init(
GroupedEnumerable<TSource, TKey, TElement> 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<PoolingGroupingEnumerator>.Return(this);
}
public bool MoveNext() => _enumerator.MoveNext();
public void Reset() => _enumerator.Reset();
public IPoolingGrouping<TKey, TElement> Current => _enumerator.Current.Value;
object IPoolingEnumerator.Current => Current;
}
internal class PoolingGrouping : IPoolingGrouping<TKey, TElement>, IDisposable
{
private PoolingList<TElement> _elements;
public PoolingGrouping Init(TKey key)
{
_elements = Pool<PoolingList<TElement>>.Get().Init();
Key = key;
return this;
}
internal PoolingList<TElement> InternalList => _elements;
public IPoolingEnumerator<TElement> GetEnumerator() => _elements.GetEnumerator();
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
public TKey Key { get; private set; }
public void Dispose()
{
_elements?.Dispose();
Pool<PoolingList<TElement>>.Return(_elements);
_elements = null;
Key = default;
}
}
}
}

@ -0,0 +1,142 @@
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;
}
}
}
}

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<IPoolingGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IPoolingEnumerable<TSource> source, Func<TSource, TKey> keySelector) =>
Pool<GroupedEnumerable<TSource, TKey, TSource>>.Get().Init(source, keySelector, x => x, null);
public static IPoolingEnumerable<IPoolingGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IPoolingEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer) =>
Pool<GroupedEnumerable<TSource, TKey, TSource>>.Get().Init(source, keySelector, x => x, comparer);
public static IPoolingEnumerable<IPoolingGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IPoolingEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector) =>
Pool<GroupedEnumerable<TSource, TKey, TElement>>.Get().Init(source, keySelector, elementSelector, null);
public static IPoolingEnumerable<IPoolingGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IPoolingEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer) =>
Pool<GroupedEnumerable<TSource, TKey, TElement>>.Get().Init(source, keySelector, elementSelector, comparer);
public static IPoolingEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IPoolingEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IPoolingEnumerable<TSource>, TResult> resultSelector) =>
Pool<GroupedResultEnumerable<TSource, TKey, TResult>>.Get().Init(source, keySelector, resultSelector, null);
// public static IPoolingEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector) =>
// new GroupedResultEnumerable<TSource, TKey, TElement, TResult>(source, keySelector, elementSelector, resultSelector, null);
public static IPoolingEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IPoolingEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IPoolingEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer) =>
Pool<GroupedResultEnumerable<TSource, TKey, TResult>>.Get().Init(source, keySelector, resultSelector, comparer);
// public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey> comparer) =>
// new GroupedResultEnumerable<TSource, TKey, TElement, TResult>(source, keySelector, elementSelector, resultSelector, comparer);
}
}

@ -0,0 +1,98 @@
using System.Collections.Generic;
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
internal class IntersectExprEnumerable<T> : IPoolingEnumerable<T>
{
private int _count;
private IPoolingEnumerable<T> _src;
private IEqualityComparer<T> _comparer;
private PoolingDictionary<T, int> _second;
public IntersectExprEnumerable<T> Init(
IPoolingEnumerable<T> src,
PoolingDictionary<T, int> second,
IEqualityComparer<T> comparer = default)
{
_src = src;
_count = 0;
_second = second;
_comparer = comparer ?? EqualityComparer<T>.Default;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<IntersectExprEnumerator>.Get().Init(this, _src.GetEnumerator(), _comparer);
}
private void Dispose()
{
if(_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_second?.Dispose();
Pool<PoolingDictionary<T, int>>.Return(_second);
_second = default;
Pool<IntersectExprEnumerable<T>>.Return(this);
}
}
internal class IntersectExprEnumerator : IPoolingEnumerator<T>
{
private IntersectExprEnumerable<T> _parent;
private IPoolingEnumerator<T> _src;
private PoolingDictionary<T, int> _alreadyDoneItems;
public IntersectExprEnumerator Init(IntersectExprEnumerable<T> parent, IPoolingEnumerator<T> src, IEqualityComparer<T> comparer)
{
_src = src;
_parent = parent;
_alreadyDoneItems = Pool<PoolingDictionary<T, int>>.Get().Init(0, comparer);
return this;
}
public bool MoveNext()
{
while (_src.MoveNext())
{
if (_parent._second.ContainsKey(_src.Current) &&
!_alreadyDoneItems.ContainsKey(_src.Current))
{
_alreadyDoneItems[_src.Current] = 1;
return true;
}
}
return false;
}
public void Reset() => _src.Reset();
object IPoolingEnumerator.Current => Current;
public T Current => _src.Current;
public void Dispose()
{
_src?.Dispose();
_src = null;
_alreadyDoneItems?.Dispose();
Pool<PoolingDictionary<T, int>>.Return(_alreadyDoneItems);
_alreadyDoneItems = default;
_parent?.Dispose();
_parent = default;
Pool<IntersectExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,24 @@
using System.Collections.Generic;
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<T> Intersect<T>(this IPoolingEnumerable<T> source, IPoolingEnumerable<T> intersectWith)
{
var second = Pool<PoolingDictionary<T, int>>.Get().Init(0);
foreach (var item in intersectWith) second[item] = 1;
return Pool<IntersectExprEnumerable<T>>.Get().Init(source, second);
}
public static IPoolingEnumerable<T> Intersect<T>(this IPoolingEnumerable<T> source, IPoolingEnumerable<T> intersectWith, IEqualityComparer<T> comparer)
{
var second = Pool<PoolingDictionary<T, int>>.Get().Init(0);
foreach (var item in intersectWith) second[item] = 1;
return Pool<IntersectExprEnumerable<T>>.Get().Init(source, second, comparer);
}
}
}

@ -0,0 +1,112 @@
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
// public static IPoolingEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
// this IPoolingEnumerable<TOuter> outer,
// IPoolingEnumerable<TInner> inner,
// Func<TOuter, TKey> outerKeySelector,
// Func<TInner, TKey> innerKeySelector,
// Func<TOuter, TInner, TResult> resultSelector)
// {
// if (outer == null)
// {
// throw new ArgumentNullException(nameof(outer));
// }
//
// if (inner == null)
// {
// throw new ArgumentNullException(nameof(inner));
// }
//
// if (outerKeySelector == null)
// {
// throw new ArgumentNullException(nameof(outerKeySelector));
// }
//
// if (innerKeySelector == null)
// {
// throw new ArgumentNullException(nameof(innerKeySelector));
// }
//
// if (resultSelector == null)
// {
// throw new ArgumentNullException(nameof(resultSelector));
// }
//
// return JoinIterator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, null);
// }
//
// public static IPoolingEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
// this IEnumerable<TOuter> outer,
// IEnumerable<TInner> inner,
// Func<TOuter, TKey> outerKeySelector,
// Func<TInner, TKey> innerKeySelector,
// Func<TOuter, TInner, TResult> resultSelector,
// IEqualityComparer<TKey> comparer)
// {
// if (outer == null)
// {
// throw new ArgumentNullException(nameof(outer));
// }
//
// if (inner == null)
// {
// throw new ArgumentNullException(nameof(inner));
// }
//
// if (outerKeySelector == null)
// {
// throw new ArgumentNullException(nameof(outerKeySelector));
// }
//
// if (innerKeySelector == null)
// {
// throw new ArgumentNullException(nameof(innerKeySelector));
// }
//
// if (resultSelector == null)
// {
// throw new ArgumentNullException(nameof(resultSelector));
// }
//
// return JoinIterator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
// }
// private static IPoolingEnumerable<TResult> JoinIterator<TOuter, TInner, TKey, TResult>(
// IPoolingEnumerable<TOuter> outer,
// IEnumerable<TInner> inner,
// Func<TOuter, TKey> outerKeySelector,
// Func<TInner, TKey> innerKeySelector,
// Func<TOuter, TInner, TResult> resultSelector,
// IEqualityComparer<TKey> comparer)
// {
// using (var e = outer.GetEnumerator())
// {
// var dict = InternalPool<PoolingDictionary<TOuter, TKey>>.Get();
// if (e.MoveNext())
// {
// Lookup<TKey, TInner> lookup = Lookup<TKey, TInner>.CreateForJoin(inner, innerKeySelector, comparer);
// if (lookup.Count != 0)
// {
// do
// {
// TOuter item = e.Current;
// Grouping<TKey, TInner> g = lookup.GetGrouping(outerKeySelector(item), create: false);
// if (g != null)
// {
// int count = g._count;
// TInner[] elements = g._elements;
// for (int i = 0; i != count; ++i)
// {
// yield return resultSelector(item, elements[i]);
// }
// }
// }
// while (e.MoveNext());
// }
// }
// }
// }
}
}

@ -0,0 +1,99 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static T Last<T>(this IPoolingEnumerable<T> source)
{
var enumerator = source.GetEnumerator();
T element = default;
var hasItems = false;
while (enumerator.MoveNext())
{
element = enumerator.Current;
hasItems = true;
}
enumerator.Dispose();
return hasItems ? element : throw new InvalidOperationException("Sequence is empty");
}
public static T Last<T>(this IPoolingEnumerable<T> source, Func<T, bool> condition)
{
var enumerator = source.GetEnumerator();
T element = default;
var hasItems = false;
while (enumerator.MoveNext())
{
if (!condition(enumerator.Current)) continue;
element = enumerator.Current;
hasItems = true;
}
enumerator.Dispose();
return hasItems ? element : throw new InvalidOperationException("Sequence is empty");
}
public static T Last<T, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, bool> condition)
{
var enumerator = source.GetEnumerator();
T element = default;
var hasItems = false;
while (enumerator.MoveNext())
{
if (!condition(context, enumerator.Current)) continue;
element = enumerator.Current;
hasItems = true;
}
enumerator.Dispose();
return hasItems ? element : throw new InvalidOperationException("Sequence is empty");
}
public static T LastOrDefault<T>(this IPoolingEnumerable<T> source)
{
var enumerator = source.GetEnumerator();
T element = default;
var hasItems = false;
while (enumerator.MoveNext())
{
element = enumerator.Current;
hasItems = true;
}
enumerator.Dispose();
return hasItems ? element : default;
}
public static T LastOrDefault<T>(this IPoolingEnumerable<T> source, Func<T, bool> condition)
{
var enumerator = source.GetEnumerator();
T element = default;
var hasItems = false;
while (enumerator.MoveNext())
{
if (!condition(enumerator.Current)) continue;
element = enumerator.Current;
hasItems = true;
}
enumerator.Dispose();
return hasItems ? element : default;
}
public static T LastOrDefault<T, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, bool> condition)
{
var enumerator = source.GetEnumerator();
T element = default;
var hasItems = false;
while (enumerator.MoveNext())
{
if (!condition(context, enumerator.Current)) continue;
element = enumerator.Current;
hasItems = true;
}
enumerator.Dispose();
return hasItems ? element : default;
}
}
}

@ -0,0 +1,410 @@
using System;
using System.Collections.Generic;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static int Min(this IPoolingEnumerable<int> source)
{
if (source == null) throw new ArgumentNullException(nameof(source));
int value = 0;
bool hasValue = false;
foreach (int x in source) {
if (hasValue) {
if (x < value) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static int? Min(this IPoolingEnumerable<int?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
int? value = null;
foreach (int? x in source) {
if (value == null || x < value)
value = x;
}
return value;
}
public static long Min(this IPoolingEnumerable<long> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
long value = 0;
bool hasValue = false;
foreach (long x in source) {
if (hasValue) {
if (x < value) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static long? Min(this IPoolingEnumerable<long?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
long? value = null;
foreach (long? x in source) {
if (value == null || x < value) value = x;
}
return value;
}
public static float Min(this IPoolingEnumerable<float> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
float value = 0;
bool hasValue = false;
foreach (float x in source) {
if (hasValue) {
// Normally NaN < anything is false, as is anything < NaN
// However, this leads to some irksome outcomes in Min and Max.
// If we use those semantics then Min(NaN, 5.0) is NaN, but
// Min(5.0, NaN) is 5.0! To fix this, we impose a total
// ordering where NaN is smaller than every value, including
// negative infinity.
if (x < value || System.Single.IsNaN(x)) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static float? Min(this IPoolingEnumerable<float?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
float? value = null;
foreach (float? x in source) {
if (x == null) continue;
if (value == null || x < value || System.Single.IsNaN((float)x)) value = x;
}
return value;
}
public static double Min(this IPoolingEnumerable<double> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
double value = 0;
bool hasValue = false;
foreach (double x in source) {
if (hasValue) {
if (x < value || Double.IsNaN(x)) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static double? Min(this IPoolingEnumerable<double?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
double? value = null;
foreach (double? x in source) {
if (x == null) continue;
if (value == null || x < value || Double.IsNaN((double)x)) value = x;
}
return value;
}
public static decimal Min(this IPoolingEnumerable<decimal> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
decimal value = 0;
bool hasValue = false;
foreach (decimal x in source) {
if (hasValue) {
if (x < value) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static decimal? Min(this IPoolingEnumerable<decimal?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
decimal? value = null;
foreach (decimal? x in source) {
if (value == null || x < value) value = x;
}
return value;
}
public static TSource Min<TSource>(this IPoolingEnumerable<TSource> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
var comparer = Comparer<TSource>.Default;
var value = default(TSource);
if (value == null) {
foreach (var x in source) {
if (x != null && (value == null || comparer.Compare(x, value) < 0))
value = x;
}
return value;
}
bool hasValue = false;
foreach (TSource x in source) {
if (hasValue) {
if (comparer.Compare(x, value) < 0)
value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static int Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, int> selector) {
return source.Select(selector).Min();
}
public static int? Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, int?> selector) {
return source.Select(selector).Min();
}
public static long Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, long> selector) {
return source.Select(selector).Min();
}
public static long? Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, long?> selector) {
return source.Select(selector).Min();
}
public static float Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, float> selector) {
return source.Select(selector).Min();
}
public static float? Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, float?> selector) {
return source.Select(selector).Min();
}
public static double Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, double> selector) {
return source.Select(selector).Min();
}
public static double? Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, double?> selector) {
return source.Select(selector).Min();
}
public static decimal Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, decimal> selector) {
return source.Select(selector).Min();
}
public static decimal? Min<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, decimal?> selector) {
return source.Select(selector).Min();
}
public static TResult Min<TSource, TResult>(this IPoolingEnumerable<TSource> source, Func<TSource, TResult> selector) {
return source.Select(selector).Min();
}
public static int Max(this IPoolingEnumerable<int> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
int value = 0;
bool hasValue = false;
foreach (int x in source) {
if (hasValue) {
if (x > value) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static int? Max(this IPoolingEnumerable<int?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
int? value = null;
foreach (int? x in source) {
if (value == null || x > value) value = x;
}
return value;
}
public static long Max(this IPoolingEnumerable<long> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
long value = 0;
bool hasValue = false;
foreach (long x in source) {
if (hasValue) {
if (x > value) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static long? Max(this IPoolingEnumerable<long?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
long? value = null;
foreach (long? x in source) {
if (value == null || x > value) value = x;
}
return value;
}
public static double Max(this IPoolingEnumerable<double> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
double value = 0;
bool hasValue = false;
foreach (double x in source) {
if (hasValue) {
if (x > value || Double.IsNaN(value)) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static double? Max(this IPoolingEnumerable<double?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
double? value = null;
foreach (double? x in source) {
if (x == null) continue;
if (value == null || x > value || Double.IsNaN((double)value)) value = x;
}
return value;
}
public static float Max(this IPoolingEnumerable<float> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
float value = 0;
bool hasValue = false;
foreach (float x in source) {
if (hasValue) {
if (x > value || Double.IsNaN(value)) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static float? Max(this IPoolingEnumerable<float?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
float? value = null;
foreach (float? x in source) {
if (x == null) continue;
if (value == null || x > value || System.Single.IsNaN((float)value)) value = x;
}
return value;
}
public static decimal Max(this IPoolingEnumerable<decimal> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
decimal value = 0;
bool hasValue = false;
foreach (decimal x in source) {
if (hasValue) {
if (x > value) value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static decimal? Max(this IPoolingEnumerable<decimal?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
decimal? value = null;
foreach (decimal? x in source) {
if (value == null || x > value) value = x;
}
return value;
}
public static TSource Max<TSource>(this IPoolingEnumerable<TSource> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
Comparer<TSource> comparer = Comparer<TSource>.Default;
TSource value = default;
if (value == null) {
foreach (TSource x in source) {
if (x != null && (value == null || comparer.Compare(x, value) > 0))
value = x;
}
return value;
}
bool hasValue = false;
foreach (TSource x in source) {
if (hasValue) {
if (comparer.Compare(x, value) > 0)
value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw new InvalidOperationException("Sequence contains no elements");
}
public static int Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, int> selector) =>
Max(source.Select(selector));
public static int? Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, int?> selector) =>
Max(source.Select(selector));
public static long Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, long> selector) =>
Max(source.Select(selector));
public static long? Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, long?> selector) =>
Max(source.Select(selector));
public static float Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, float> selector) =>
Max(source.Select(selector));
public static float? Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, float?> selector) =>
Max(source.Select(selector));
public static double Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, double> selector) =>
Max(source.Select(selector));
public static double? Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, double?> selector) => Max(source.Select(selector));
public static decimal Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, decimal> selector) =>
source.Select(selector).Max();
public static decimal? Max<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, decimal?> selector) =>
source.Select(selector).Max();
public static TResult Max<TSource, TResult>(this IPoolingEnumerable<TSource> source, Func<TSource, TResult> selector) =>
source.Select(selector).Max();
}
}

@ -0,0 +1,77 @@
namespace MemoryPools.Collections.Linq
{
internal class OfTypeExprEnumerable<T> : IPoolingEnumerable<T>
{
private int _count;
private IPoolingEnumerable _src;
public OfTypeExprEnumerable<T> Init(IPoolingEnumerable src)
{
_src = src;
_count = 0;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<OfTypeExprEnumerator>.Get().Init(_src.GetEnumerator(), this);
}
private void Dispose()
{
if(_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
Pool<OfTypeExprEnumerable<T>>.Return(this);
}
}
internal class OfTypeExprEnumerator : IPoolingEnumerator<T>
{
private IPoolingEnumerator _src;
private OfTypeExprEnumerable<T> _parent;
public OfTypeExprEnumerator Init(IPoolingEnumerator src, OfTypeExprEnumerable<T> parent)
{
_src = src;
_parent = parent;
return this;
}
public bool MoveNext()
{
do
{
var next = _src.MoveNext();
if (!next) return false;
} while (!(_src.Current is T));
return true;
}
public void Reset()
{
_src.Reset();
}
object IPoolingEnumerator.Current => Current;
public T Current => (T)_src.Current;
public void Dispose()
{
_parent?.Dispose();
_parent = null;
_src?.Dispose();
_src = default;
Pool<OfTypeExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,11 @@
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<TR> OfType<TR>(this IPoolingEnumerable source)
{
if (source is IPoolingEnumerable<TR> res) return res;
return Pool<OfTypeExprEnumerable<TR>>.Get().Init(source);
}
}
}

@ -0,0 +1,88 @@
namespace MemoryPools.Collections.Linq
{
internal class PrependExprEnumerable<T> : IPoolingEnumerable<T>
{
private int _count;
private IPoolingEnumerable<T> _src;
private T _element;
public PrependExprEnumerable<T> Init(IPoolingEnumerable<T> src, T element)
{
_src = src;
_count = 0;
_element = element;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<PrependExprEnumerator>.Get().Init(_src.GetEnumerator(), this, _element);
}
private void Dispose()
{
if(_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_element = default;
Pool<PrependExprEnumerable<T>>.Return(this);
}
}
internal class PrependExprEnumerator : IPoolingEnumerator<T>
{
private IPoolingEnumerator _src;
private PrependExprEnumerable<T> _parent;
private T _element;
private bool _first, _shouldReturnElement;
public PrependExprEnumerator Init(IPoolingEnumerator src, PrependExprEnumerable<T> parent, T element)
{
_src = src;
_parent = parent;
_element = element;
_first = true;
_shouldReturnElement = true;
return this;
}
public bool MoveNext()
{
if (_first)
{
_first = false;
return true;
}
_shouldReturnElement = false;
return _src.MoveNext();
}
public void Reset()
{
_first = true;
_src.Reset();
}
object IPoolingEnumerator.Current => Current;
public T Current => _shouldReturnElement ? _element : (T) _src.Current;
public void Dispose()
{
_parent?.Dispose();
_parent = null;
_src?.Dispose();
_src = default;
_first = _shouldReturnElement = false;
Pool<PrependExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,76 @@
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
internal class ReverseExprEnumerable<T> : IPoolingEnumerable<T>
{
private int _count;
private PoolingList<T> _src;
public ReverseExprEnumerable<T> Init(PoolingList<T> src)
{
_src = src;
_count = 0;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<ReverseExprEnumerator>.Get().Init(_src, this);
}
private void Dispose()
{
if(_count == 0) return;
_count--;
if (_count == 0)
{
_src?.Dispose();
Pool<PoolingList<T>>.Return(_src);
_src = default;
Pool<ReverseExprEnumerable<T>>.Return(this);
}
}
internal class ReverseExprEnumerator : IPoolingEnumerator<T>
{
private PoolingList<T> _src;
private ReverseExprEnumerable<T> _parent;
private int _position;
public ReverseExprEnumerator Init(PoolingList<T> src, ReverseExprEnumerable<T> parent)
{
_position = src.Count;
_src = src;
_parent = parent;
return this;
}
public bool MoveNext()
{
if (_position == 0) return false;
_position--;
return true;
}
public void Reset() => _position = _src.Count;
object IPoolingEnumerator.Current => Current;
public T Current => _src[_position];
public void Dispose()
{
_parent?.Dispose();
_parent = default;
_src = default;
_position = default;
Pool<ReverseExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,20 @@
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
/// <summary>
/// Returns sequence with backward direction. Complexity = 2 * O(N) (collect + return)
/// </summary>
public static IPoolingEnumerable<T> Reverse<T>(this IPoolingEnumerable<T> source)
{
var list = Pool<PoolingList<T>>.Get().Init();
foreach (var item in source)
{
list.Add(item);
}
return Pool<ReverseExprEnumerable<T>>.Get().Init(list);
}
}
}

@ -0,0 +1,75 @@
using System;
namespace MemoryPools.Collections.Linq
{
internal class SelectExprEnumerable<T, TR> : IPoolingEnumerable<TR>
{
private IPoolingEnumerable<T> _src;
private Func<T, TR> _mutator;
private int _count;
public SelectExprEnumerable<T, TR> Init(IPoolingEnumerable<T> src, Func<T, TR> mutator)
{
_src = src;
_count = 0;
_mutator = mutator;
return this;
}
public IPoolingEnumerator<TR> GetEnumerator()
{
_count++;
return Pool<SelectExprEnumerator>.Get().Init(this, _src.GetEnumerator(), _mutator);
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_count = 0;
_mutator = default;
Pool<SelectExprEnumerable<T, TR>>.Return(this);
}
}
internal class SelectExprEnumerator : IPoolingEnumerator<TR>
{
private Func<T, TR> _mutator;
private SelectExprEnumerable<T, TR> _parent;
private IPoolingEnumerator<T> _src;
public SelectExprEnumerator Init(SelectExprEnumerable<T, TR> parent, IPoolingEnumerator<T> src, Func<T, TR> mutator)
{
_src = src;
_parent = parent;
_mutator = mutator;
return this;
}
public bool MoveNext() => _src.MoveNext();
public void Reset() => _src.Reset();
object IPoolingEnumerator.Current => Current;
public TR Current => _mutator( _src.Current);
public void Dispose()
{
_parent?.Dispose();
_parent = default;
_src?.Dispose();
_src = default;
Pool<SelectExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,85 @@
using System;
namespace MemoryPools.Collections.Linq
{
internal class SelectExprWithContextEnumerable<T, TR, TContext> : IPoolingEnumerable<TR>
{
private IPoolingEnumerable<T> _src;
private Func<TContext, T, TR> _condition;
private TContext _context;
private int _count;
public SelectExprWithContextEnumerable<T, TR, TContext> Init(IPoolingEnumerable<T> src, TContext context, Func<TContext, T, TR> condition)
{
_src = src;
_count = 0;
_context = context;
_condition = condition;
return this;
}
public IPoolingEnumerator<TR> GetEnumerator()
{
_count++;
return Pool<SelectExprWithContextEnumerator>.Get().Init(this, _src.GetEnumerator(), _context, _condition);
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_context = default;
_condition = default;
Pool<SelectExprWithContextEnumerable<T, TR, TContext>>.Return(this);
}
}
internal class SelectExprWithContextEnumerator : IPoolingEnumerator<TR>
{
private TContext _context;
private Func<TContext, T, TR> _condition;
private IPoolingEnumerator<T> _src;
private SelectExprWithContextEnumerable<T, TR, TContext> _parent;
public SelectExprWithContextEnumerator Init(
SelectExprWithContextEnumerable<T, TR, TContext> parent,
IPoolingEnumerator<T> src,
TContext context,
Func<TContext, T, TR> condition)
{
_src = src;
_parent = parent;
_context = context;
_condition = condition;
return this;
}
public bool MoveNext() => _src.MoveNext();
public void Reset() => _src.Reset();
object IPoolingEnumerator.Current => Current;
public TR Current => _condition(_context, _src.Current);
public void Dispose()
{
_parent?.Dispose();
_parent = default;
_src?.Dispose();
_src = default;
_context = default;
Pool<SelectExprWithContextEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,17 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<TR> Select<T, TR>(this IPoolingEnumerable<T> source, Func<T, TR> mutator)
{
return Pool<SelectExprEnumerable<T, TR>>.Get().Init(source, mutator);
}
public static IPoolingEnumerable<TR> Select<T, TR, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, TR> mutator)
{
return Pool<SelectExprWithContextEnumerable<T, TR, TContext>>.Get().Init(source, context, mutator);
}
}
}

@ -0,0 +1,117 @@
using System;
namespace MemoryPools.Collections.Linq
{
internal class SelectManyExprEnumerable<T, TR> : IPoolingEnumerable<TR>
{
private IPoolingEnumerable<T> _src;
private Func<T, IPoolingEnumerable<TR>> _mutator;
private int _count;
public SelectManyExprEnumerable<T, TR> Init(IPoolingEnumerable<T> src, Func<T, IPoolingEnumerable<TR>> mutator)
{
_src = src;
_count = 0;
_mutator = mutator;
return this;
}
public IPoolingEnumerator<TR> GetEnumerator()
{
_count++;
return Pool<SelectManyExprEnumerator>.Get().Init(this, _src.GetEnumerator(), _mutator);
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_count = 0;
_mutator = default;
Pool<SelectManyExprEnumerable<T, TR>>.Return(this);
}
}
internal class SelectManyExprEnumerator : IPoolingEnumerator<TR>
{
private Func<T, IPoolingEnumerable<TR>> _mutator;
private SelectManyExprEnumerable<T, TR> _parent;
private IPoolingEnumerator<T> _src;
private IPoolingEnumerator<TR> _currentEnumerator;
private bool _finished;
public SelectManyExprEnumerator Init(
SelectManyExprEnumerable<T, TR> parent,
IPoolingEnumerator<T> src,
Func<T, IPoolingEnumerable<TR>> mutator)
{
_src = src;
_finished = false;
_parent = parent;
_mutator = mutator;
_currentEnumerator = default;
return this;
}
public bool MoveNext()
{
if (_finished) return false;
if (_currentEnumerator == default)
{
if (!_src.MoveNext())
{
_finished = true;
return false;
}
_currentEnumerator = _mutator(_src.Current).GetEnumerator();
}
do
{
var hasValue = _currentEnumerator.MoveNext();
if (hasValue) return true;
if (!_src.MoveNext())
{
_finished = true;
return false;
}
_currentEnumerator?.Dispose();
_currentEnumerator = _mutator(_src.Current).GetEnumerator();
} while (true);
}
public void Reset()
{
_currentEnumerator?.Dispose();
_currentEnumerator = default;
_src.Reset();
}
object IPoolingEnumerator.Current => Current;
public TR Current => _currentEnumerator.Current;
public void Dispose()
{
_currentEnumerator?.Dispose();
_currentEnumerator = default;
_parent?.Dispose();
_parent = default;
_src.Dispose();
_src = default;
Pool<SelectManyExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,126 @@
using System;
namespace MemoryPools.Collections.Linq
{
internal class SelectManyExprWithContextEnumerable<T, TR, TContext> : IPoolingEnumerable<TR>
{
private IPoolingEnumerable<T> _src;
private Func<T, TContext, IPoolingEnumerable<TR>> _mutator;
private int _count;
private TContext _context;
public SelectManyExprWithContextEnumerable<T, TR, TContext> Init(
IPoolingEnumerable<T> src,
Func<T, TContext, IPoolingEnumerable<TR>> mutator,
TContext context)
{
_src = src;
_count = 0;
_context = context;
_mutator = mutator;
return this;
}
public IPoolingEnumerator<TR> GetEnumerator()
{
_count++;
return Pool<SelectManyExprWithContextEnumerator>.Get().Init(this, _src.GetEnumerator(), _mutator, _context);
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_count = 0;
_context = default;
_mutator = default;
Pool<SelectManyExprWithContextEnumerable<T, TR, TContext>>.Return(this);
}
}
internal class SelectManyExprWithContextEnumerator : IPoolingEnumerator<TR>
{
private TContext _context;
private Func<T, TContext, IPoolingEnumerable<TR>> _mutator;
private SelectManyExprWithContextEnumerable<T, TR, TContext> _parent;
private IPoolingEnumerator<T> _src;
private IPoolingEnumerator<TR> _currentEnumerator;
private bool _finished;
public SelectManyExprWithContextEnumerator Init(
SelectManyExprWithContextEnumerable<T, TR, TContext> parent,
IPoolingEnumerator<T> src,
Func<T, TContext, IPoolingEnumerable<TR>> mutator,
TContext context)
{
_src = src;
_finished = false;
_parent = parent;
_mutator = mutator;
_context = context;
_currentEnumerator = default;
return this;
}
public bool MoveNext()
{
if (_finished) return false;
if (_currentEnumerator == default)
{
if (!_src.MoveNext())
{
_finished = true;
return false;
}
_currentEnumerator = _mutator(_src.Current, _context).GetEnumerator();
}
do
{
var hasValue = _currentEnumerator.MoveNext();
if (hasValue) return true;
if (!_src.MoveNext())
{
_finished = true;
return false;
}
_currentEnumerator?.Dispose();
_currentEnumerator = _mutator(_src.Current, _context).GetEnumerator();
} while (true);
}
public void Reset()
{
_currentEnumerator?.Dispose();
_currentEnumerator = default;
_src.Reset();
}
object IPoolingEnumerator.Current => Current;
public TR Current => _currentEnumerator.Current;
public void Dispose()
{
_currentEnumerator?.Dispose();
_currentEnumerator = default;
_parent?.Dispose();
_parent = default;
_src.Dispose();
_src = default;
Pool<SelectManyExprWithContextEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,22 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<TR> SelectMany<T, TR>(
this IPoolingEnumerable<T> source,
Func<T, IPoolingEnumerable<TR>> mutator)
{
return Pool<SelectManyExprEnumerable<T, TR>>.Get().Init(source, mutator);
}
public static IPoolingEnumerable<TR> SelectMany<T, TR, TContext>(
this IPoolingEnumerable<T> source,
TContext context,
Func<T, TContext, IPoolingEnumerable<TR>> mutator)
{
return Pool<SelectManyExprWithContextEnumerable<T, TR, TContext>>.Get().Init(source, mutator, context);
}
}
}

@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<T> Empty<T>() => Range(0,0).Select(x => (T)(object)x);
public static IPoolingEnumerable<int> Range(int startIndex, int count)
{
return Pool<RangeExprEnumerable>.Get().Init(startIndex, count);
}
public static IPoolingEnumerable<int> Range(int count)
{
return Pool<RangeExprEnumerable>.Get().Init(0, count);
}
public static IPoolingEnumerable<T> Repeat<T>(T element, int count) => Range(0, count).Select(element, (item, x) => item);
public static bool Contains<T>(this IPoolingEnumerable<T> self, T element)
{
foreach (var item in self)
{
if (item.Equals(element)) return true;
}
return false;
}
public static int Count<T>(this IPoolingEnumerable<T> self)
{
var count = 0;
foreach (var _ in self)
{
count++;
}
return count;
}
public static long LongCount<T>(this IPoolingEnumerable<T> self)
{
long count = 0;
foreach (var _ in self)
{
count++;
}
return count;
}
public static T ElementAt<T>(this IPoolingEnumerable<T> self, int position)
{
var i = 0;
foreach (var item in self)
{
if (i == position) return item;
i++;
}
throw new InvalidOperationException("Sequence is too small. Index not found");
}
public static bool SequenceEqual<T>(this IPoolingEnumerable<T> self, IPoolingEnumerable<T> other)
{
var comparer = EqualityComparer<T>.Default;
using (var left = self.GetEnumerator())
using (var right = other.GetEnumerator())
{
bool equals, leftHas, rightHas;
do
{
leftHas = left.MoveNext();
rightHas = right.MoveNext();
equals = comparer.Equals(left.Current, right.Current);
if (leftHas != rightHas || !equals) return false;
} while (leftHas && rightHas);
return !leftHas && !rightHas;
}
}
}
internal class RangeExprEnumerable : IPoolingEnumerable<int>
{
private int _start;
private int _workCount;
private int _count;
public RangeExprEnumerable Init(int start, int count)
{
_start = start;
_workCount = count;
_count = 0;
return this;
}
public IPoolingEnumerator<int> GetEnumerator()
{
_count++;
return Pool<RangeExprEnumerator>.Get().Init(this, _start, _workCount);
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_start = _workCount = 0;
_count = 0;
Pool<RangeExprEnumerable>.Return(this);
}
}
internal class RangeExprEnumerator : IPoolingEnumerator<int>
{
private int _start;
private int _current;
private int _workCount;
private RangeExprEnumerable _parent;
public RangeExprEnumerator Init(RangeExprEnumerable parent, int start, int workCount)
{
_current = -1;
_start = start;
_workCount = workCount;
_parent = parent;
return this;
}
public bool MoveNext()
{
if (_current == 0) return false;
if (_current == -1)
{
_current = _workCount;
return _workCount != 0;
}
_current--;
return _current != 0;
}
public void Reset() => _current = _start;
object IPoolingEnumerator.Current => _current;
public int Current => _start + (_workCount - _current);
public void Dispose()
{
_current = -1;
_parent?.Dispose();
_parent = default;
Pool<RangeExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,139 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static T Single<T>(this IPoolingEnumerable<T> source)
{
var wasFound = false;
var element = default(T);
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (wasFound)
{
enumerator.Dispose();
throw new InvalidOperationException("Sequence should contain only one element");
}
wasFound = true;
element = enumerator.Current;
}
enumerator.Dispose();
return element;
}
public static T Single<T>(this IPoolingEnumerable<T> source, Func<T, bool> condition)
{
var wasFound = false;
var element = default(T);
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (condition(enumerator.Current))
{
if (wasFound)
{
enumerator.Dispose();
throw new InvalidOperationException("Sequence should contain only one element");
}
wasFound = true;
element = enumerator.Current;
}
}
enumerator.Dispose();
return element;
}
public static T Single<T, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, bool> condition)
{
var wasFound = false;
var element = default(T);
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (condition(context, enumerator.Current))
{
if (wasFound)
{
enumerator.Dispose();
throw new InvalidOperationException("Sequence should contain only one element");
}
wasFound = true;
element = enumerator.Current;
}
}
enumerator.Dispose();
return element;
}
public static T SingleOrDefault<T>(this IPoolingEnumerable<T> source)
{
var wasFound = false;
var element = default(T);
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (wasFound)
{
enumerator.Dispose();
return default;
}
wasFound = true;
element = enumerator.Current;
}
enumerator.Dispose();
return element;
}
public static T SingleOrDefault<T>(this IPoolingEnumerable<T> source, Func<T, bool> condition)
{
var wasFound = false;
var element = default(T);
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (condition(enumerator.Current))
{
if (wasFound)
{
enumerator.Dispose();
return default;
}
wasFound = true;
element = enumerator.Current;
}
}
enumerator.Dispose();
return element;
}
public static T SingleOrDefault<T, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, bool> condition)
{
var wasFound = false;
var element = default(T);
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
if (condition(context, enumerator.Current))
{
if (wasFound)
{
enumerator.Dispose();
return default;
}
wasFound = true;
element = enumerator.Current;
}
}
enumerator.Dispose();
return element;
}
}
}

@ -0,0 +1,99 @@
namespace MemoryPools.Collections.Linq
{
internal sealed class SkipTakeExprPoolingEnumerable<T> : IPoolingEnumerable<T>
{
private bool _take;
private int _workCount;
private int _count;
private IPoolingEnumerable<T> _source;
public SkipTakeExprPoolingEnumerable<T> Init(IPoolingEnumerable<T> source, bool take, int count)
{
_count = 0;
_workCount = count;
_source = source;
_take = take;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<SkipTakeExprPoolingEnumerator>.Get().Init(this, _source.GetEnumerator(), _take, _workCount);
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_source = null;
_take = default;
Pool<SkipTakeExprPoolingEnumerable<T>>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
internal sealed class SkipTakeExprPoolingEnumerator : IPoolingEnumerator<T>
{
private IPoolingEnumerator<T> _source;
private SkipTakeExprPoolingEnumerable<T> _parent;
private bool _take;
private int _pos, _workCount;
public SkipTakeExprPoolingEnumerator Init(SkipTakeExprPoolingEnumerable<T> parent, IPoolingEnumerator<T> source, bool take, int workCount)
{
_pos = 0;
_take = take;
_source = source;
_parent = parent;
_workCount = workCount;
return this;
}
public bool MoveNext()
{
if (_take)
{
if (_pos < _workCount)
{
_pos++;
return _source.MoveNext();
}
return false;
}
while (_pos < _workCount)
{
_pos++;
_source.MoveNext();
}
return _source.MoveNext();
}
public void Reset()
{
_pos = 0;
_source.Reset();
}
object IPoolingEnumerator.Current => Current;
public T Current => _source.Current;
public void Dispose()
{
_parent?.Dispose();
_parent = default;
_source?.Dispose();
_source = default;
Pool<SkipTakeExprPoolingEnumerator>.Return(this);
}
}
}
}

@ -0,0 +1,15 @@
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<T> Skip<T>(this IPoolingEnumerable<T> source, int count)
{
return Pool<SkipTakeExprPoolingEnumerable<T>>.Get().Init(source, false, count);
}
public static IPoolingEnumerable<T> Take<T>(this IPoolingEnumerable<T> source, int count)
{
return Pool<SkipTakeExprPoolingEnumerable<T>>.Get().Init(source, true, count);
}
}
}

@ -0,0 +1,126 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static int Sum(this IPoolingEnumerable<int> source)
{
if (source == null) throw new ArgumentNullException(nameof(source));
int sum = 0;
checked {
foreach (var v in source) sum += v;
}
return sum;
}
public static int? Sum(this IPoolingEnumerable<int?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
int sum = 0;
checked {
foreach (var v in source) {
if (v != null) sum += v.GetValueOrDefault();
}
}
return sum;
}
public static long Sum(this IPoolingEnumerable<long> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
long sum = 0;
checked {
foreach (long v in source) sum += v;
}
return sum;
}
public static long? Sum(this IPoolingEnumerable<long?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
long sum = 0;
checked {
foreach (var v in source) {
if (v != null) sum += v.GetValueOrDefault();
}
}
return sum;
}
public static float Sum(this IPoolingEnumerable<float> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
double sum = 0;
foreach (var v in source) sum += v;
return (float)sum;
}
public static float? Sum(this IPoolingEnumerable<float?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
double sum = 0;
foreach (var v in source) {
if (v != null) sum += v.GetValueOrDefault();
}
return (float)sum;
}
public static double Sum(this IPoolingEnumerable<double> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
double sum = 0;
foreach (var v in source) sum += v;
return sum;
}
public static double? Sum(this IPoolingEnumerable<double?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
double sum = 0;
foreach (var v in source) {
if (v != null) sum += v.GetValueOrDefault();
}
return sum;
}
public static decimal Sum(this IPoolingEnumerable<decimal> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
decimal sum = 0;
foreach (var v in source) sum += v;
return sum;
}
public static decimal? Sum(this IPoolingEnumerable<decimal?> source) {
if (source == null) throw new ArgumentNullException(nameof(source));
decimal sum = 0;
foreach (var v in source) {
if (v != null) sum += v.GetValueOrDefault();
}
return sum;
}
public static int Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, int> selector) =>
Sum(source.Select(selector));
public static int? Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, int?> selector) =>
Sum(source.Select(selector));
public static long Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, long> selector) =>
Sum(source.Select(selector));
public static long? Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, long?> selector) =>
Sum(source.Select(selector));
public static float Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, float> selector) =>
Sum(source.Select(selector));
public static float? Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, float?> selector) =>
Sum(source.Select(selector));
public static double Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, double> selector) =>
Sum(source.Select(selector));
public static double? Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, double?> selector) =>
Sum(source.Select(selector));
public static decimal Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, decimal> selector) =>
Sum(source.Select(selector));
public static decimal? Sum<TSource>(this IPoolingEnumerable<TSource> source, Func<TSource, decimal?> selector) =>
Sum(source.Select(selector));
}
}

@ -0,0 +1,70 @@
using System.Collections.Generic;
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
internal class UnionExprEnumerable<T> : IPoolingEnumerable<T>
{
private int _count;
private PoolingDictionary<T, int> _src;
public UnionExprEnumerable<T> Init(PoolingDictionary<T, int> src)
{
_src = src;
_count = 0;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<UnionExprEnumerator>.Get().Init(this, _src.GetEnumerator());
}
private void Dispose()
{
if(_count == 0) return;
_count--;
if (_count == 0)
{
_src?.Dispose();
Pool<PoolingDictionary<T, int>>.Return(_src);
_src = default;
Pool<UnionExprEnumerable<T>>.Return(this);
}
}
internal class UnionExprEnumerator : IPoolingEnumerator<T>
{
private UnionExprEnumerable<T> _parent;
private IPoolingEnumerator<KeyValuePair<T, int>> _src;
public UnionExprEnumerator Init(UnionExprEnumerable<T> parent, IPoolingEnumerator<KeyValuePair<T, int>> src)
{
_src = src;
_parent = parent;
return this;
}
public bool MoveNext() => _src.MoveNext();
public void Reset() => _src.Reset();
object IPoolingEnumerator.Current => Current;
public T Current => _src.Current.Key;
public void Dispose()
{
_src?.Dispose();
_src = null;
_parent?.Dispose();
_parent = default;
Pool<UnionExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,26 @@
using System.Collections.Generic;
using MemoryPools.Collections.Specialized;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<T> Union<T>(this IPoolingEnumerable<T> source, IPoolingEnumerable<T> second)
{
var set = Pool<PoolingDictionary<T, int>>.Get().Init(0);
foreach (var item in source) set[item] = 1;
foreach (var item in second) set[item] = 1;
return Pool<UnionExprEnumerable<T>>.Get().Init(set);
}
public static IPoolingEnumerable<T> Union<T>(this IPoolingEnumerable<T> source, IPoolingEnumerable<T> second, IEqualityComparer<T> comparer)
{
var set = Pool<PoolingDictionary<T, int>>.Get().Init(0, comparer);
foreach (var item in source) set[item] = 1;
foreach (var item in second) set[item] = 1;
return Pool<UnionExprEnumerable<T>>.Get().Init(set);
}
}
}

@ -0,0 +1,88 @@
using System;
namespace MemoryPools.Collections.Linq
{
internal class WhereExprEnumerable<T> : IPoolingEnumerable<T>
{
private int _count;
private IPoolingEnumerable<T> _src;
private Func<T, bool> _condition;
public WhereExprEnumerable<T> Init(IPoolingEnumerable<T> src, Func<T, bool> condition)
{
_count = 0;
_src = src;
_condition = condition;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<WhereExprEnumerator>.Get().Init(_src.GetEnumerator(), this, _condition);
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_condition = default;
Pool<WhereExprEnumerable<T>>.Return(this);
}
}
internal class WhereExprEnumerator : IPoolingEnumerator<T>
{
private Func<T, bool> _mutator;
private IPoolingEnumerator<T> _src;
private WhereExprEnumerable<T> _parent;
public WhereExprEnumerator Init(IPoolingEnumerator<T> src, WhereExprEnumerable<T> parent, Func<T, bool> mutator)
{
_src = src;
_mutator = mutator;
_parent = parent;
return this;
}
public bool MoveNext()
{
do
{
var next = _src.MoveNext();
if (!next) return false;
} while (!_mutator(_src.Current));
return true;
}
public void Reset()
{
_src.Reset();
}
object IPoolingEnumerator.Current => Current;
public T Current => _src.Current;
public void Dispose()
{
_parent?.Dispose();
_parent = default;
_src?.Dispose();
_src = default;
Pool<WhereExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,94 @@
using System;
namespace MemoryPools.Collections.Linq
{
internal class WhereExprWithContextEnumerable<T, TContext> : IPoolingEnumerable<T>
{
private int _count;
private IPoolingEnumerable<T> _src;
private Func<TContext, T, bool> _condition;
private TContext _context;
public WhereExprWithContextEnumerable<T, TContext> Init(IPoolingEnumerable<T> src, TContext context, Func<TContext, T, bool> condition)
{
_count = 0;
_src = src;
_context = context;
_condition = condition;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<WhereExprWithContextEnumerator>.Get().Init(_src.GetEnumerator(), this, _context, _condition);
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
(_condition, _context, _src) = (default, default, default);
Pool<WhereExprWithContextEnumerable<T, TContext>>.Return(this);
}
}
internal class WhereExprWithContextEnumerator : IPoolingEnumerator<T>
{
private TContext _context;
private Func<TContext, T, bool> _condition;
private IPoolingEnumerator<T> _src;
private WhereExprWithContextEnumerable<T, TContext> _parent;
public WhereExprWithContextEnumerator Init(
IPoolingEnumerator<T> src,
WhereExprWithContextEnumerable<T, TContext> parent,
TContext context,
Func<TContext, T, bool> condition)
{
_src = src;
_parent = parent;
_context = context;
_condition = condition;
return this;
}
public bool MoveNext()
{
do
{
var next = _src.MoveNext();
if (!next) return false;
} while (!_condition(_context, _src.Current));
return true;
}
public void Reset()
{
_src.Reset();
}
object IPoolingEnumerator.Current => Current;
public T Current => _src.Current;
public void Dispose()
{
_parent?.Dispose();
_parent = null;
_src?.Dispose();
_src = default;
_context = default;
Pool<WhereExprWithContextEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,13 @@
using System;
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<T> Where<T>(this IPoolingEnumerable<T> source, Func<T, bool> condition) =>
Pool<WhereExprEnumerable<T>>.Get().Init(source, condition);
public static IPoolingEnumerable<T> Where<T, TContext>(this IPoolingEnumerable<T> source, TContext context, Func<TContext, T, bool> condition) =>
Pool<WhereExprWithContextEnumerable<T, TContext>>.Get().Init(source, context, condition);
}
}

@ -0,0 +1,83 @@
namespace MemoryPools.Collections
{
internal class ZipExprEnumerable<T> : IPoolingEnumerable<(T, T)>
{
private IPoolingEnumerable<T> _src, _second;
private int _count;
public ZipExprEnumerable<T> Init(IPoolingEnumerable<T> src, IPoolingEnumerable<T> second)
{
_src = src;
_count = 0;
_second = second;
return this;
}
public IPoolingEnumerator<(T, T)> GetEnumerator()
{
_count++;
return Pool<ZipExprEnumerator>.Get().Init(this, _src.GetEnumerator(), _second.GetEnumerator());
}
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_src = default;
_second = default;
Pool<ZipExprEnumerable<T>>.Return(this);
}
}
internal class ZipExprEnumerator : IPoolingEnumerator<(T, T)>
{
private ZipExprEnumerable<T> _parent;
private IPoolingEnumerator<T> _src, _second;
private bool _hasResult;
public ZipExprEnumerator Init(
ZipExprEnumerable<T> parent, IPoolingEnumerator<T> src, IPoolingEnumerator<T> second)
{
_parent = parent;
_src = src;
_second = second;
_hasResult = false;
return this;
}
public bool MoveNext()
{
_hasResult = _src.MoveNext() && _second.MoveNext();
return _hasResult;
}
public void Reset()
{
_src.Reset();
_second.Reset();
}
object IPoolingEnumerator.Current => Current;
public (T, T) Current => _hasResult ? ( _src.Current, _second.Current) : default;
public void Dispose()
{
_parent?.Dispose();
_parent = default;
_src?.Dispose();
_src = default;
_second?.Dispose();
_second = default;
Pool<ZipExprEnumerator>.Return(this);
}
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,8 @@
namespace MemoryPools.Collections.Linq
{
public static partial class PoolingEnumerable
{
public static IPoolingEnumerable<(T, T)> Zip<T>(this IPoolingEnumerable<T> source, IPoolingEnumerable<T> second) =>
Pool<ZipExprEnumerable<T>>.Get().Init(source, second);
}
}

@ -0,0 +1,70 @@
namespace MemoryPools.Collections.Specialized
{
public static partial class AsSingleQueryList
{
private class EnumerableShared<T> : IPoolingEnumerable<T> where T : class
{
private PoolingListCanon<T> _src;
private int _count;
public IPoolingEnumerable<T> Init(PoolingListCanon<T> src)
{
_src = src;
_count = 0;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
_count++;
return Pool<EnumeratorRef>.Get().Init(this, _src);
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
private void Dispose()
{
if (_count == 0) return;
_count--;
if (_count == 0)
{
_src?.Dispose();
_src = default;
Pool<EnumerableShared<T>>.Return(this);
}
}
private class EnumeratorRef : IPoolingEnumerator<T>
{
private IPoolingEnumerator<T> _enumerator;
private EnumerableShared<T> _parent;
public IPoolingEnumerator<T> Init(EnumerableShared<T> parent, IPoolingEnumerable<T> src)
{
_parent = parent;
_enumerator = src.GetEnumerator();
return this;
}
public bool MoveNext() => _enumerator.MoveNext();
public void Reset() => _enumerator.Reset();
public T Current => _enumerator.Current;
object IPoolingEnumerator.Current => Current;
public void Dispose()
{
_enumerator?.Dispose();
_enumerator = default;
_parent?.Dispose();
_parent = default;
Pool<EnumeratorRef>.Return(this);
}
}
}
}
}

@ -0,0 +1,60 @@
namespace MemoryPools.Collections.Specialized
{
public static partial class AsSingleQueryList
{
private class EnumerableTyped<T> : IPoolingEnumerable<T>
{
private PoolingList<T> _src;
public IPoolingEnumerable<T> Init(PoolingList<T> src)
{
_src = src;
return this;
}
public IPoolingEnumerator<T> GetEnumerator()
{
var src = _src;
_src = default;
Pool<EnumerableTyped<T>>.Return(this);
return Pool<EnumeratorVal>.Get().Init(src);
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
private class EnumeratorVal : IPoolingEnumerator<T>
{
private PoolingList<T> _src;
private IPoolingEnumerator<T> _enumerator;
public IPoolingEnumerator<T> Init(PoolingList<T> src)
{
_src = src;
_enumerator = _src.GetEnumerator();
return this;
}
public bool MoveNext() => _enumerator.MoveNext();
public void Reset()
{
_enumerator?.Dispose();
_enumerator = _src.GetEnumerator();
}
public T Current => _enumerator.Current;
object IPoolingEnumerator.Current => Current;
public void Dispose()
{
_enumerator?.Dispose();
_src?.Dispose();
Pool<PoolingList<T>>.Return(_src);
Pool<EnumeratorVal>.Return(this);
_src = default;
}
}
}
}
}

@ -0,0 +1,91 @@
using System;
using System.Diagnostics.Contracts;
namespace MemoryPools.Collections.Specialized.Helpers
{
internal static class HashHelpers
{
private const int HashPrime = 101;
public const int HashCollisionThreshold = 100;
// Table of prime numbers to use as hash table sizes.
// A typical resize algorithm would pick the smallest prime number in this array
// that is larger than twice the previous capacity.
// Suppose our Hashtable currently has capacity x and enough elements are added
// such that a resize needs to occur. Resizing first computes 2x then finds the
// first prime in the table greater than 2x, i.e. if primes are ordered
// p_1, p_2, ..., p_i, ..., it finds p_n such that p_n-1 < 2x < p_n.
// Doubling is important for preserving the asymptotic complexity of the
// hashtable operations such as add. Having a prime guarantees that double
// hashing does not lead to infinite loops. IE, your hash function will be
// h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime.
public static readonly int[] Primes =
{
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369
};
public static bool IsPrime(int candidate)
{
if ((candidate & 1) != 0)
{
int limit = (int) Math.Sqrt(candidate);
for (int divisor = 3; divisor <= limit; divisor += 2)
{
if ((candidate % divisor) == 0)
return false;
}
return true;
}
return (candidate == 2);
}
public static int GetPrime(int min)
{
for (int i = 0; i < Primes.Length; i++)
{
int prime = Primes[i];
if (prime >= min) return prime;
}
//outside of our predefined table.
//compute the hard way.
for (int i = (min | 1); i < Int32.MaxValue; i += 2)
{
if (IsPrime(i) && ((i - 1) % HashPrime != 0))
return i;
}
return min;
}
public static int GetMinPrime()
{
return Primes[0];
}
// Returns size of hashtable to grow to.
public static int ExpandPrime(int oldSize)
{
var newSize = oldSize + 1;
// Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
if ((uint) newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
{
Contract.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
return MaxPrimeArrayLength;
}
return GetPrime(newSize);
}
// This is the maximum prime smaller than Array.MaxArrayLength
public const int MaxPrimeArrayLength = 0x7FEFFFFD;
}
}

@ -0,0 +1,15 @@
using System;
namespace MemoryPools.Collections.Specialized
{
public interface IPoolingNode<T> : IDisposable
{
public IPoolingNode<T> Next { get; set; }
T this[int index] { get; set; }
IPoolingNode<T> Init(int capacity);
void Clear();
}
}

@ -0,0 +1,60 @@
using System;
namespace MemoryPools.Collections.Specialized
{
/// <summary>
/// Represents ideal dictionary with extra fast access to its items. Items should inherit IdealHashObjectBase to be
/// able to set hashcode.
/// </summary>
/// <typeparam name="TK">Key of dictionary</typeparam>
/// <typeparam name="TV">Corresponding Value</typeparam>
public class IdealHashDictionary<TK, TV> :
IDisposable
where TK : IdealHashObjectBase
where TV : class
{
readonly PoolingListCanon<TV> _list = Pool<PoolingListCanon<TV>>.Get().Init();
readonly PoolingQueue<int> _freeNodes = new PoolingQueueVal<int>();
public TV this[TK key]
{
get
{
var hc = key.IdealHashCode;
if(hc >= _list.Count)
throw new ArgumentOutOfRangeException(nameof(key));
return _list[hc];
}
}
public void Add(TK key, TV value)
{
var index = AcquireHashCode(value);
key.IdealHashCode = index;
}
public bool Remove(TK key)
{
var index = key.IdealHashCode;
_freeNodes.Enqueue(index);
_list[index] = default;
return true;
}
private int AcquireHashCode(TV value)
{
if(_freeNodes.Count > 0)
{
return _freeNodes.Dequeue();
}
_list.Add(value);
return _list.Count - 1;
}
public void Dispose()
{
_list.Clear();
_freeNodes.Clear();
}
}
}

@ -0,0 +1,9 @@
namespace MemoryPools.Collections.Specialized
{
public abstract class IdealHashObjectBase
{
internal int IdealHashCode { get; set; }
public override int GetHashCode() => IdealHashCode;
}
}

@ -0,0 +1,280 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace MemoryPools.Collections.Specialized
{
/// <summary>
/// Use this class when you need to store 1 or 2 items in class fields and in very rare scenarios
/// more then 2 items. In super-rare scenarios - to pass it as IList, ICollection or as IEnumerable.
/// </summary>
public struct LocalList<T> : IList<T>
{
private static readonly EqualityComparer<T> ItemComparer = EqualityComparer<T>.Default;
private (T, T) _items;
private IList<T> _other;
// Static lists to store real length (-1 field in struct)
private static readonly IList<T> LengthIs1 = new List<T> {default};
private static readonly IList<T> LengthIs2 = new List<T> {default, default};
private const int DefaultListCapacity = 8;
public const int LocalStoreCapacity = 2;
public IEnumerator<T> GetEnumerator()
{
// empty
if (_other == null) yield break;
if (_other.Count <= LocalStoreCapacity)
{
yield return _items.Item1;
if (ReferenceEquals(_other, LengthIs2)) yield return _items.Item2;
yield break;
}
using(var enumerator = _other.GetEnumerator())
{
while (enumerator.MoveNext()) yield return enumerator.Current;
}
}
public void Add(T item)
{
// empty
if (_other == null)
{
_items.Item1 = item;
_other = LengthIs1;
}
// count=1
else if (ReferenceEquals(_other, LengthIs1))
{
_items.Item2 = item;
_other = LengthIs2;
}
// count=2
else
{
if (ReferenceEquals(_other, LengthIs2))
{
_other = new List<T>(DefaultListCapacity);
_other.Add(_items.Item1);
_items.Item1 = default;
_other.Add(_items.Item2);
_items.Item2 = default;
}
_other.Add(item);
}
}
public void Clear()
{
_other = null;
_items.Item1 = default;
_items.Item2 = default;
}
public bool Contains(T item)
{
return IndexOf(item) >= 0;
}
public void CopyTo(T[] array, int arrayIndex)
{
if (_other == null) return;
if (_other.Count > LocalStoreCapacity)
{
_other.CopyTo(array, arrayIndex);
}
else
{
if (_other.Count > 0) array[arrayIndex++] = _items.Item1;
if (_other.Count > 1) array[arrayIndex] = _items.Item2;
}
}
/// <summary>
/// Removes first occurrence of given item
/// </summary>
public bool Remove(T item)
{
if (_other == null) return false;
if (_other.Count > LocalStoreCapacity)
{
var done = _other.Remove(item);
if (done && _other.Count == 2)
{
_items.Item1 = _other[0];
_items.Item2 = _other[1];
_other = LengthIs2;
}
return done;
}
if (ReferenceEquals(_other, LengthIs1) && ItemComparer.Equals(_items.Item1, item))
{
_items.Item1 = default;
_other = null;
return true;
}
if (ReferenceEquals(_other, LengthIs2))
{
var done = false;
if (ItemComparer.Equals(_items.Item2, item))
{
_items.Item2 = default;
_other = LengthIs1;
return true;
}
if (ItemComparer.Equals(_items.Item1, item))
{
_items.Item1 = _items.Item2;
_other = LengthIs1;
return true;
}
}
return false;
}
public int Count => _other?.Count ?? 0;
public bool IsReadOnly => false;
public int IndexOf(T item)
{
if (_other == null)
return -1;
if (_other.Count > LocalStoreCapacity) return _other.IndexOf(item);
if (_other.Count > 0 && ItemComparer.Equals(_items.Item1, item)) return 0;
if (_other.Count > 1 && ItemComparer.Equals(_items.Item2, item)) return 1;
return -1;
}
public void Insert(int index, T item)
{
// 2nd of 1, 3rd of 2, 4th of 3..
if (index == Count)
{
Add(item);
return;
}
// Asked non-first when empty
if (_other == null) throw new IndexOutOfRangeException();
// If list already created
if (_other.Count > LocalStoreCapacity) _other.Insert(index, item);
if (index == 0)
{
if (ReferenceEquals(_other, LengthIs1))
{
_items = (item, _items.Item1);
_other = LengthIs2;
}
else
{
(_items.Item1, _items.Item2, item) = (item, _items.Item1, _items.Item2);
Add(item);
}
return;
}
// (item0, item1), list(nothing) ->> (def, def), list(item0, item ,item1)
if (index == 1)
{
(_items.Item2, item) = (item, _items.Item2);
Add(item);
}
}
public void RemoveAt(int index)
{
if (_other == null || _other.Count <= index || index < 0)
throw new IndexOutOfRangeException();
if (_other.Count < LocalStoreCapacity)
{
if (index == 0)
{
_items.Item1 = _items.Item2;
_other = ReferenceEquals(_other, LengthIs1) ? null : LengthIs1;
}
else
{
_items.Item2 = default;
_other = LengthIs1;
}
}
else
{
_other.RemoveAt(index);
if (_other.Count == 2)
{
_items.Item1 = _other[0];
_items.Item2 = _other[1];
_other = LengthIs2;
}
}
}
public T this[int index]
{
get
{
if (_other == null || index >= Count || index < 0)
throw new IndexOutOfRangeException();
if (_other?.Count > LocalStoreCapacity) return _other[index];
if (_other.Count > 0 && index == 0) return _items.Item1;
if (_other.Count > 1 && index == 1) return _items.Item2;
throw new InvalidOperationException("Uncovered branch");
}
set
{
if (_other == null || index >= Count || index < 0)
throw new IndexOutOfRangeException();
if (_other.Count > LocalStoreCapacity) _other[index] = value;
if (_other.Count > 0 && index == 0) _items.Item1 = value;
if (_other.Count > 1 && index == 1) _items.Item2 = value;
throw new InvalidOperationException("Uncovered branch");
}
}
public override int GetHashCode()
{
return (_items.GetHashCode() * 37) & _other.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is LocalList<T> other && Equals(other);
}
public bool Equals(LocalList<T> other)
{
return _items.Equals(other._items) && Equals(_other, other._other);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
namespace MemoryPools.Collections.Specialized
{
/// <summary>
/// Contains 8 elements as struct fields as Maximum. Use it when you have guaranteed count of elements <= 8
/// </summary>
public struct LongLocalList<T>
{
private static readonly EqualityComparer<T> ItemComparer = EqualityComparer<T>.Default;
private (T, T, T, T, T, T, T, T) _items;
public const int Capacity = 8;
public void Add(T item)
{
Count++;
if (Count >= Capacity) throw new ArgumentOutOfRangeException();
this[Count - 1] = item;
}
public void Clear()
{
Count = 0;
_items = default;
}
public bool Contains(T item)
{
return IndexOf(item) >= 0;
}
public void CopyTo(T[] array, int arrayIndex)
{
for (var i = 0; i < Capacity; i++) array[i] = this[i];
}
public bool Remove(T item)
{
var i = 0;
var j = 0;
for (; i < Capacity; i++)
{
if (ItemComparer.Equals(this[i], item) != true) j++;
else continue;
this[j] = this[i];
}
return j != i;
}
public int Count { get; private set; }
public bool IsReadOnly => false;
public int IndexOf(T item)
{
for (var i = 0; i < Capacity; i++)
if (ItemComparer.Equals(this[i], item))
return i;
return -1;
}
public T this[int index]
{
get
{
if (index < 0 || index >= Count)
throw new IndexOutOfRangeException();
switch (index)
{
case 0: return _items.Item1;
case 1: return _items.Item2;
case 2: return _items.Item3;
case 3: return _items.Item4;
case 4: return _items.Item5;
case 5: return _items.Item6;
case 6: return _items.Item7;
case 7: return _items.Item8;
default: throw new IndexOutOfRangeException();
}
}
set
{
if (index < 0 || index >= Count)
throw new IndexOutOfRangeException();
switch (index)
{
case 0:
_items.Item1 = value;
break;
case 1:
_items.Item2 = value;
break;
case 2:
_items.Item3 = value;
break;
case 3:
_items.Item4 = value;
break;
case 4:
_items.Item5 = value;
break;
case 5:
_items.Item6 = value;
break;
case 6:
_items.Item7 = value;
break;
case 7:
_items.Item8 = value;
break;
default: throw new IndexOutOfRangeException();
}
}
}
public override int GetHashCode()
{
return _items.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is LongLocalList<T> other && Equals(other);
}
public bool Equals(LongLocalList<T> other)
{
return _items.Equals(other._items);
}
}
}

@ -0,0 +1,85 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace MemoryPools.Collections.Specialized
{
public partial class PoolingDictionary<TKey, TValue>
{
internal class KeysCollection : ICollection<TKey>
{
private PoolingDictionary<TKey, TValue> _src;
public KeysCollection Init(PoolingDictionary<TKey, TValue> src)
{
_src = src;
return this;
}
public IEnumerator<TKey> GetEnumerator()
{
return Pool<Enumerator>.Get().Init(_src);
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Add(TKey item) => throw new NotImplementedException();
public void Clear() => throw new NotImplementedException();
public bool Contains(TKey item) => _src.FindEntry(item) >= 0;
public void CopyTo(TKey[] array, int arrayIndex)
{
if (array.Length - arrayIndex < _src._entries.Count)
{
throw new IndexOutOfRangeException("Cannot copy keys into array. Target array is too small.");
}
for (var index = 0; index < _src._entries.Count; index++)
{
var entry = _src._entries[index];
array[arrayIndex + index] = entry.key;
}
}
public bool Remove(TKey item) => throw new NotImplementedException("Removal ops are disallowed.");
public int Count => _src.Count;
public bool IsReadOnly => _src.IsReadOnly;
private class Enumerator : IEnumerator<TKey>
{
private PoolingDictionary<TKey, TValue> _src;
private int _pos;
public Enumerator Init(PoolingDictionary<TKey, TValue> src)
{
_pos = -1;
_src = src;
return this;
}
public bool MoveNext()
{
if (_pos >= _src.Count) return false;
_pos++;
return _pos < _src.Count;
}
public void Reset()
{
_pos = -1;
}
public TKey Current => _src._entries[_pos].key;
object IEnumerator.Current => Current;
public void Dispose()
{
_src = default;
Pool<Enumerator>.Return(this);
}
}
}
}
}

@ -0,0 +1,94 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace MemoryPools.Collections.Specialized
{
public partial class PoolingDictionary<TKey, TValue>
{
internal class ValuesCollection : ICollection<TValue>
{
private PoolingDictionary<TKey, TValue> _src;
public ValuesCollection Init(PoolingDictionary<TKey, TValue> src)
{
_src = src;
return this;
}
public IEnumerator<TValue> GetEnumerator()
{
return Pool<Enumerator>.Get().Init(_src);
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Add(TValue item) => throw new NotImplementedException();
public void Clear() => throw new NotImplementedException();
public bool Contains(TValue item)
{
foreach (var entry in _src._entries)
{
if (entry.Equals(item)) return true;
}
return false;
}
public void CopyTo(TValue[] array, int arrayIndex)
{
if (array.Length - arrayIndex < _src._entries.Count)
{
throw new IndexOutOfRangeException("Cannot copy keys into array. Target array is too small.");
}
for (var index = 0; index < _src._entries.Count; index++)
{
var entry = _src._entries[index];
array[arrayIndex + index] = entry.value;
}
}
public bool Remove(TValue item) => throw new NotImplementedException("Removal ops are disallowed.");
public int Count => _src.Count;
public bool IsReadOnly => _src.IsReadOnly;
private class Enumerator : IEnumerator<TValue>
{
private PoolingDictionary<TKey, TValue> _src;
private int _pos;
public Enumerator Init(PoolingDictionary<TKey, TValue> src)
{
_pos = -1;
_src = src;
return this;
}
public bool MoveNext()
{
if (_pos >= _src.Count) return false;
_pos++;
return _pos < _src.Count;
}
public void Reset()
{
_pos = -1;
}
public TValue Current => _src._entries[_pos].value;
object IEnumerator.Current => Current;
public void Dispose()
{
_src = default;
Pool<Enumerator>.Return(this);
}
}
}
}
}

@ -0,0 +1,365 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using MemoryPools.Collections.Specialized.Helpers;
namespace MemoryPools.Collections.Specialized
{
/// <summary>
/// Pooling dictionary contains two PoolingLists and should be disposed at end of life.
/// Disallowed: removing elements and getting non-generic IEnumerable.
/// When get IEnumerable[TKey, TValue], you need to dispose it (foreach Expr do it automatically).
/// You can safe add any count of elements to dispose them: all collections stores data in 128-sized chunks.
/// These chunks are reusable btw all Pooling* collections. All operations have O(1) complexity.
/// Primary rets IPoolingEnumerable. But you can cast to IEnumerable to work in common manner.
/// </summary>
public partial class PoolingDictionary<TKey, TValue> :
IDictionary<TKey, TValue>,
IReadOnlyDictionary<TKey, TValue>,
IPoolingEnumerable<KeyValuePair<TKey, TValue>>,
IDisposable
{
[DebuggerDisplay("Key: {key}, Value: {value}")]
private struct Entry {
public int hashCode; // Lower 31 bits of hash code, -1 if unused
public int next; // Index of next entry, -1 if last
public TKey key; // Key of entry
public TValue value; // Value of entry
}
private IEqualityComparer<TKey> _comparer;
private PoolingList<int> _buckets;
private PoolingList<Entry> _entries;
private int _freeList;
private int _version;
private int _freeCount;
private int _count;
private int _complexity;
private bool _refType;
private const int EndOfChain = -1;
public PoolingDictionary() => Init();
public PoolingDictionary<TKey, TValue> Init(int capacity = 0, IEqualityComparer<TKey> comparer = default)
{
if (_buckets != default)
{
return this;
}
_refType = typeof(TKey).IsClass;
var size = HashHelpers.GetPrime(capacity);
_buckets = Pool<PoolingList<int>>.Get().Init();
for (var i = 0; i < size; i++)
{
_buckets.Add(EndOfChain);
}
_entries = Pool<PoolingList<Entry>>.Get().Init();
_freeList = EndOfChain;
_comparer = comparer ?? EqualityComparer<TKey>.Default;
return this;
}
public bool TryGetValue(TKey key, out TValue value)
{
var i = FindEntry(key);
if (i >= 0)
{
value = _entries[i].value;
return true;
}
value = default;
return false;
}
public TValue this[TKey key]
{
get {
var i = FindEntry(key);
if (i >= 0) return _entries[i].value;
throw new KeyNotFoundException();
}
set => Insert(key, value, false);
}
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
public ICollection<TKey> Keys => throw new NotImplementedException(); // _keys ??= Pool<KeysCollection>.Get().Init(this);
public ICollection<TValue> Values => throw new NotImplementedException(); // _values ??= Pool<ValuesCollection>.Get().Init(this);
private int FindEntry(TKey key)
{
if(_refType && key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (_buckets == null) return -1;
var hashCode = key.GetHashCode() & 0x7FFFFFFF;
for (var i = _buckets[hashCode % _buckets.Count]; i >= 0; i = _entries[i].next)
{
if (_entries[i].hashCode == hashCode && _comparer.Equals(_entries[i].key, key)) return i;
}
return -1;
}
public int Complexity => _complexity;
public void Add(TKey key, TValue value) => Insert(key, value, true);
public bool ContainsKey(TKey key) => FindEntry(key) >= 0;
public bool Remove(TKey key)
{
throw new NotImplementedException();
}
private void Insert(TKey key, TValue value, bool add) {
if (_refType && key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (_buckets == null) Init(PoolsDefaults.DefaultPoolBucketSize);
var hashCode = key.GetHashCode() & 0x7FFFFFFF;
var targetBucket = hashCode % _buckets.Count;
var complexity = 0;
for (var i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
{
if (_entries[i].hashCode == hashCode && _comparer.Equals(_entries[i].key, key))
{
if (add) {
throw new ArgumentException("Duplicating key found in dictionary");
}
var entrym = _entries[i];
entrym.value = value;
_entries[i] = entrym;
unchecked
{
_version++;
}
return;
}
complexity++;
}
int index;
if (_freeCount > 0)
{
index = _freeList;
_freeList = _entries[index].next;
_freeCount--;
}
else
{
if (_count == _entries.Count)
{
Resize();
targetBucket = hashCode % _buckets.Count;
}
index = _count;
_count++;
}
var entry = _entries[index];
entry.hashCode = hashCode;
entry.next = _buckets[targetBucket];
entry.key = key;
entry.value = value;
_entries[index] = entry;
_buckets[targetBucket] = index;
unchecked
{
_version++;
}
_complexity = Math.Max(_complexity, complexity);
}
private void Resize()
{
Resize(HashHelpers.ExpandPrime(_count), false);
}
private void Resize(int newSize, bool forceNewHashCodes)
{
var newBuckets = Pool<PoolingList<int>>.Get().Init();
while(newBuckets.Count < newSize) newBuckets.Add(EndOfChain);
while(_entries.Count < newSize) _entries.Add(new Entry {hashCode = EndOfChain, next = EndOfChain});
if (forceNewHashCodes)
{
for (var i = 0; i < _count; i++)
{
if (_entries[i].hashCode != -1)
{
var entry = _entries[i];
entry.hashCode = _entries[i].key.GetHashCode() & 0x7FFFFFFF;
_entries[i] = entry;
}
}
}
for (int i = 0; i < newSize; i++) {
if (_entries[i].hashCode >= 0) {
int bucket = _entries[i].hashCode % newSize;
var entry = _entries[i];
entry.next = newBuckets[bucket];
_entries[i] = entry;
newBuckets[bucket] = i;
}
}
_buckets.Dispose();
Pool<PoolingList<int>>.Return(_buckets);
_buckets = newBuckets;
}
public void Dispose()
{
unchecked
{
_version++;
}
_buckets?.Dispose();
Pool<PoolingList<int>>.Return(_buckets);
_entries?.Dispose();
Pool<PoolingList<Entry>>.Return(_entries);
_buckets = default;
_entries = default;
_comparer = default;
_complexity = _count = _version = _freeCount = _freeList = default;
}
public void Add(KeyValuePair<TKey, TValue> item) =>
Insert(item.Key, item.Value, true);
public void Clear()
{
_buckets.Clear();
_entries.Clear();
_complexity = 0;
_count = _freeList = _freeCount = 0;
unchecked
{
_version++;
}
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
var keyHash = item.Key.GetHashCode() & 0x7FFFFFFF;
for (var i = 0; i < _entries.Count; i++)
{
if(_entries[i].hashCode == keyHash && _comparer.Equals(_entries[i].key, item.Key) &&
_entries[i].value.Equals(item.Value))
{
return true;
}
}
return false;
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
if (array.Length - arrayIndex < _entries.Count)
{
throw new IndexOutOfRangeException("Dictionary size bigger than array");
}
for (var i = 0; i < _entries.Count; i++)
{
array[arrayIndex + i] = new KeyValuePair<TKey, TValue>(_entries[i].key, _entries[i].value);
}
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
throw new NotImplementedException();
}
public int Count => _count;
public bool IsReadOnly => false;
internal class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IPoolingEnumerator<KeyValuePair<TKey, TValue>>
{
private PoolingDictionary<TKey, TValue> _src;
private int _pos;
private int _ver;
public Enumerator Init(PoolingDictionary<TKey, TValue> src)
{
_pos = -1;
_src = src;
_ver = _src._version;
return this;
}
public bool MoveNext()
{
if (_pos >= _src.Count) return false;
if (_ver != _src._version)
{
throw new InvalidOperationException("Version of collection was changed while enumeration");
}
_pos++;
return _pos < _src._count;
}
public void Reset()
{
_ver = _src._version;
_pos = -1;
}
object IPoolingEnumerator.Current => Current;
public KeyValuePair<TKey, TValue> Current
{
get
{
if (_ver != _src._version)
{
throw new InvalidOperationException("Version of collection was changed while enumeration");
}
return new KeyValuePair<TKey, TValue>(_src._entries[_pos].key, _src._entries[_pos].value);
}
}
object IEnumerator.Current => throw new InvalidOperationException("Boxing disallowed");
public void Dispose()
{
Pool<Enumerator>.Return(this);
}
}
public IPoolingEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() =>
Pool<Enumerator>.Get().Init(this);
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() =>
(IEnumerator<KeyValuePair<TKey, TValue>>)GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => (IEnumerator)GetEnumerator();
IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
}

@ -0,0 +1,46 @@
using System.Collections.Generic;
namespace MemoryPools.Collections.Specialized
{
public static partial class AsSingleQueryList
{
public static IPoolingEnumerable<T> AsSingleEnumerableList<T>(this IEnumerable<T> src)
{
var list = Pool<PoolingList<T>>.Get().Init();
foreach (var item in src)
{
list.Add(item);
}
return Pool<EnumerableTyped<T>>.Get().Init(list);
}
public static IPoolingEnumerable<T> AsSingleEnumerableSharedList<T>(this IEnumerable<T> src) where T : class
{
var list = Pool<PoolingListCanon<T>>.Get().Init();
foreach (var item in src)
{
list.Add(item);
}
return Pool<EnumerableShared<T>>.Get().Init(list);
}
public static IPoolingEnumerable<T> AsSingleEnumerableList<T>(this IPoolingEnumerable<T> src)
{
var list = Pool<PoolingList<T>>.Get().Init();
foreach (var item in src)
{
list.Add(item);
}
return Pool<EnumerableTyped<T>>.Get().Init(list);
}
public static IPoolingEnumerable<T> AsSingleEnumerableSharedList<T>(this IPoolingEnumerable<T> src) where T : class
{
var list = Pool<PoolingListCanon<T>>.Get().Init();
foreach (var item in src)
{
list.Add(item);
}
return Pool<EnumerableShared<T>>.Get().Init(list);
}
}
}

@ -0,0 +1,19 @@
namespace MemoryPools.Collections.Specialized
{
public sealed class PoolingList<T> : PoolingListBase<T>
{
public PoolingList() => Init();
public PoolingList<T> Init()
{
_root = Pool.GetBuffer<IPoolingNode<T>>(PoolsDefaults.DefaultPoolBucketSize);
_ver = 0;
return this;
}
protected override IPoolingNode<T> CreateNodeHolder()
{
return Pool<PoolingNode<T>>.Get().Init(PoolsDefaults.DefaultPoolBucketSize);
}
}
}

@ -0,0 +1,314 @@
using System;
using System.Buffers;
namespace MemoryPools.Collections.Specialized
{
public abstract class PoolingListBase<T> : IDisposable, IPoolingEnumerable<T>
{
protected IMemoryOwner<IPoolingNode<T>> _root;
protected int _count;
protected int _ver;
public IPoolingEnumerator<T> GetEnumerator()
{
return Pool<Enumerator>.Get().Init(this);
}
IPoolingEnumerator IPoolingEnumerable.GetEnumerator()
{
return GetEnumerator();
}
protected abstract IPoolingNode<T> CreateNodeHolder();
public void Add(T item)
{
var bn = _count >> PoolsDefaults.DefaultPoolBucketDegree;
var bi = _count & PoolsDefaults.DefaultPoolBucketMask;
_root.Memory.Span[bn] ??= CreateNodeHolder();
_root.Memory.Span[bn][bi] = item;
_count++;
unchecked
{
_ver++;
}
}
public void Clear()
{
for (int i = 0, len = _root.Memory.Span.Length; i < len; i++)
{
if (_root.Memory.Span[i] == null) break;
_root.Memory.Span[i].Clear();
_root.Memory.Span[i].Dispose();
_root.Memory.Span[i] = default;
}
_count = default;
unchecked
{
_ver++;
}
}
public bool Contains(T item) => IndexOf(item) != -1;
public void CopyTo(T[] array, int arrayIndex)
{
var len = 0;
for (var i = 0; i <= PoolsDefaults.DefaultPoolBucketSize; i++)
for (var j = 0; j < PoolsDefaults.DefaultPoolBucketSize && len < _count; j++, len++)
{
array[len] = _root.Memory.Span[i][j];
}
}
public bool Remove(T item)
{
int i, j;
for (i = 0, j = 0; i < _count; i++)
{
var bfn = i >> PoolsDefaults.DefaultPoolBucketDegree;
var bfi = i & PoolsDefaults.DefaultPoolBucketMask;
var btn = j >> PoolsDefaults.DefaultPoolBucketDegree;
var bti = j & PoolsDefaults.DefaultPoolBucketMask;
if (!_root.Memory.Span[bfn][bfi].Equals(item))
{
_root.Memory.Span[btn][bti] = _root.Memory.Span[bfn][bfi];
j++;
}
else
{
_count--;
}
}
unchecked
{
_ver++;
}
return i != j && i != 0;
}
public int Count => _count;
public bool IsReadOnly => false;
public int IndexOf(T item)
{
var len = 0;
for (var i = 0; i <= PoolsDefaults.DefaultPoolBucketSize; i++)
for (var j = 0; j < PoolsDefaults.DefaultPoolBucketSize && len < _count; j++, len++)
{
if (item.Equals(_root.Memory.Span[i][j])) return len;
}
return -1;
}
public void Insert(int index, T item)
{
if (index < _count)
{
throw new IndexOutOfRangeException(nameof(index));
}
for (var i = index; i <= _count; i++)
{
var j = i + 1;
var bn = i >> PoolsDefaults.DefaultPoolBucketDegree;
var bi = i & PoolsDefaults.DefaultPoolBucketMask;
var bjn = j >> PoolsDefaults.DefaultPoolBucketDegree;
var bji = j & PoolsDefaults.DefaultPoolBucketMask;
var copy = _root.Memory.Span[bn][bi];
_root.Memory.Span[bjn][bji] = item;
item = copy;
}
_count++;
unchecked
{
_ver++;
}
}
public void RemoveAt(int index)
{
if (index >= _count)
{
throw new IndexOutOfRangeException(nameof(index));
}
for (int i = index, j = i + 1; i <= _count; i++)
{
var bn = i >> PoolsDefaults.DefaultPoolBucketDegree;
var bi = i & PoolsDefaults.DefaultPoolBucketMask;
var bjn = j >> PoolsDefaults.DefaultPoolBucketDegree;
var bji = j & PoolsDefaults.DefaultPoolBucketMask;
_root.Memory.Span[bn][bi] = _root.Memory.Span[bjn][bji];
}
_count--;
unchecked
{
_ver++;
}
}
public void Resize(int size)
{
if (size == _count) return;
if (size < _count)
{
var cbn = _count >> PoolsDefaults.DefaultPoolBucketDegree;
var sbn = size >> PoolsDefaults.DefaultPoolBucketDegree;
var sbi = size & PoolsDefaults.DefaultPoolBucketMask;
for (var bn = sbn + 1; bn <= cbn; bn++)
{
_root.Memory.Span[bn].Dispose();
_root.Memory.Span[bn] = default;
}
var span = _root.Memory.Span[sbn];
for (var i = sbi; i <= PoolsDefaults.DefaultPoolBucketSize; i++)
{
span[i] = default;
}
_count = size;
}
else
{
var cbn = _count >> PoolsDefaults.DefaultPoolBucketDegree;
var sbn = size >> PoolsDefaults.DefaultPoolBucketDegree;
for (var bn = cbn + 1; bn <= sbn; bn++)
{
_root.Memory.Span[bn] = CreateNodeHolder();
}
_count = size;
}
}
public T this[int index]
{
get
{
if (index >= _count)
{
throw new IndexOutOfRangeException(nameof(index));
}
var bn = index >> PoolsDefaults.DefaultPoolBucketDegree;
var bi = index & PoolsDefaults.DefaultPoolBucketMask;
return _root.Memory.Span[bn][bi];
}
set
{
if (index >= _count)
{
throw new IndexOutOfRangeException(nameof(index));
}
var bn = index >> PoolsDefaults.DefaultPoolBucketDegree;
var bi = index & PoolsDefaults.DefaultPoolBucketMask;
_root.Memory.Span[bn][bi] = value;
unchecked
{
_ver++;
}
}
}
public void Dispose()
{
Clear();
_root?.Dispose();
_root = default;
}
private class Enumerator : IPoolingEnumerator<T>
{
private PoolingListBase<T> _src;
private int _bucket, _index, _ver;
public Enumerator Init(PoolingListBase<T> src)
{
_bucket = 0;
_index = -1;
_src = src;
_ver = _src._ver;
return this;
}
public bool MoveNext()
{
if (_index >= _src.Count) return false;
if (_ver != _src._ver)
{
throw new InvalidOperationException("Collection was changed while enumeration");
}
_index++;
var tb = _src._count >> PoolsDefaults.DefaultPoolBucketDegree;
var ti = _src._count & PoolsDefaults.DefaultPoolBucketMask;
if (_index == PoolsDefaults.DefaultPoolBucketSize)
{
_index = 0;
_bucket++;
}
if ((_bucket < tb && _index < PoolsDefaults.DefaultPoolBucketSize) ||
(_bucket == tb && _index < ti))
{
return true;
}
return false;
}
public void Reset()
{
_index = -1;
_bucket = 0;
_ver = _src._ver;
}
public T Current
{
get
{
if (_ver != _src._ver)
{
throw new InvalidOperationException("Collection was changed while enumeration");
}
return _src._root.Memory.Span[_bucket][_index];
}
}
object IPoolingEnumerator.Current => Current;
public void Dispose()
{
Pool<Enumerator>.Return(this);
}
}
}
}

@ -0,0 +1,24 @@
namespace MemoryPools.Collections.Specialized
{
/// <summary>
/// List of elements (should be disposed to avoid memory traffic). Max size = 128*128 = 16,384 elements.
/// The best for scenarios, where you need to collect list of elements, use them and forget (w/out removal or inserts).
/// Add: O(1), Insert, Removal: O(N)
/// </summary>
public sealed class PoolingListCanon<T> : PoolingListBase<T> where T : class
{
public PoolingListCanon() => Init();
public PoolingListCanon<T> Init()
{
_root = Pool.GetBuffer<IPoolingNode<T>>(PoolsDefaults.DefaultPoolBucketSize);
_ver = 0;
return this;
}
protected override IPoolingNode<T> CreateNodeHolder()
{
return (IPoolingNode<T>) Pool<PoolingNodeCanon<T>>.Get().Init(PoolsDefaults.DefaultPoolBucketSize);
}
}
}

@ -0,0 +1,18 @@
namespace MemoryPools.Collections.Specialized
{
internal sealed class PoolingNode<T> : PoolingNodeBase<T>
{
public override void Dispose()
{
base.Dispose();
Pool<PoolingNode<T>>.Return(this);
}
public override IPoolingNode<T> Init(int capacity)
{
Next = null;
_buf = Pool.GetBuffer<T>(capacity);
return this;
}
}
}

@ -0,0 +1,33 @@
using System.Buffers;
namespace MemoryPools.Collections.Specialized
{
internal abstract class PoolingNodeBase<T> : IPoolingNode<T>
{
protected IMemoryOwner<T> _buf;
public int Length => _buf.Memory.Length;
public virtual T this[int index]
{
get => _buf.Memory.Span[index];
set => _buf.Memory.Span[index] = value;
}
public virtual void Dispose()
{
_buf.Dispose();
_buf = null;
Next = null;
}
public IPoolingNode<T> Next { get; set; }
public abstract IPoolingNode<T> Init(int capacity);
public void Clear()
{
_buf.Memory.Span.Clear();
}
}
}

@ -0,0 +1,36 @@
namespace MemoryPools.Collections.Specialized
{
internal sealed class PoolingNodeCanon<T> : PoolingNodeBase<object>, IPoolingNode<T> where T : class
{
IPoolingNode<T> IPoolingNode<T>.Next
{
get => (IPoolingNode<T>) Next;
set => Next = (IPoolingNode<object>) value;
}
T IPoolingNode<T>.this[int index]
{
get => (T)_buf.Memory.Span[index];
set => _buf.Memory.Span[index] = value;
}
IPoolingNode<T> IPoolingNode<T>.Init(int capacity)
{
this.Init(capacity);
return this;
}
public override void Dispose()
{
base.Dispose();
Pool<PoolingNodeCanon<T>>.Return(this);
}
public override IPoolingNode<object> Init(int capacity)
{
Next = null;
_buf = Pool.GetBuffer<object>(capacity);
return this;
}
}
}

@ -0,0 +1,128 @@
using System;
using System.Runtime.CompilerServices;
namespace MemoryPools.Collections.Specialized
{
public abstract class PoolingQueue<T> : IDisposable
{
private IPoolingNode<T> _enqueueTo;
private IPoolingNode<T> _dequeueFrom;
private int _enqueueIndex, _dequeueIndex;
protected PoolingQueue()
{
Count = 0;
_enqueueIndex = 0;
_dequeueIndex = 0;
_enqueueTo = _dequeueFrom = null;
}
public bool IsEmpty => Count == 0;
public int Count { get; private set; }
public void Dispose()
{
Clear();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Enqueue(T obj)
{
if (Count == 0 && _enqueueTo == null)
_enqueueTo = _dequeueFrom = CreateNodeHolder();
_enqueueTo[_enqueueIndex] = obj;
_enqueueIndex++;
Count++;
if (_enqueueIndex == PoolsDefaults.DefaultPoolBucketSize)
{
var enqueue = _enqueueTo;
_enqueueTo = CreateNodeHolder();
enqueue.Next = _enqueueTo;
_enqueueIndex = 0;
}
}
protected abstract IPoolingNode<T> CreateNodeHolder();
/// <summary>
/// Tries to return queue element if any available via `val` parameter.
/// </summary>
/// <returns>
/// true if element found or false otherwise
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryDequeue(out T val)
{
if (IsEmpty)
{
val = default;
return false;
}
val = Dequeue();
return true;
}
/// <summary>
/// Returns queue element
/// </summary>
/// <returns>
/// Returns element or throws IndexOutOfRangeException if no element found
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Dequeue()
{
if (IsEmpty) throw new IndexOutOfRangeException();
var obj = _dequeueFrom[_dequeueIndex];
_dequeueFrom[_dequeueIndex] = default;
_dequeueIndex++;
Count--;
if (_dequeueIndex == PoolsDefaults.DefaultPoolBucketSize)
{
var dequeue = _dequeueFrom;
_dequeueFrom = _dequeueFrom.Next;
_dequeueIndex = 0;
dequeue.Dispose();
}
if (Count == 0)
{
// return back to pool
if (_enqueueTo != _dequeueFrom)
{
var empty = _dequeueFrom;
_dequeueFrom = _dequeueFrom.Next;
_dequeueIndex = 0;
empty.Dispose();
}
else
// reset to pool start
{
_enqueueIndex = 0;
_dequeueIndex = 0;
}
}
return obj;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
while (_enqueueTo != null)
{
var next = _enqueueTo.Next;
_enqueueTo.Dispose();
_enqueueTo = next;
}
_dequeueFrom = null;
}
}
}

@ -0,0 +1,10 @@
namespace MemoryPools.Collections.Specialized
{
public sealed class PoolingQueueRef<T> : PoolingQueue<T> where T : class
{
protected override IPoolingNode<T> CreateNodeHolder()
{
return (IPoolingNode<T>) Pool<PoolingNodeCanon<T>>.Get().Init(PoolsDefaults.DefaultPoolBucketSize);
}
}
}

@ -0,0 +1,17 @@
namespace MemoryPools.Collections.Specialized
{
/// <summary>
/// Poolinq queue stores items in buckets of 256 size, who linked with linked list.
/// Nodes of this list and storage (array[256])
/// ** NOT THREAD SAFE **
/// Enqueue, dequeue: O(1).
/// </summary>
/// <typeparam name="T">Items should be classes because underlying collection stores object type</typeparam>
public sealed class PoolingQueueVal<T> : PoolingQueue<T> where T : struct
{
protected override IPoolingNode<T> CreateNodeHolder()
{
return Pool<PoolingNode<T>>.Get().Init(PoolsDefaults.DefaultPoolBucketSize);
}
}
}

@ -0,0 +1,10 @@
namespace MemoryPools.Collections.Specialized
{
public class PoolingStack<T> : PoolingStackBase<T>
{
protected override IPoolingNode<T> CreateNodeHolder()
{
return Pool<PoolingNode<T>>.Get().Init(PoolsDefaults.DefaultPoolBucketSize);
}
}
}

@ -0,0 +1,108 @@
using System;
using System.Runtime.CompilerServices;
namespace MemoryPools.Collections.Specialized
{
public abstract class PoolingStackBase<T> : IDisposable
{
private IPoolingNode<T> _top;
private int _topIndex;
protected PoolingStackBase()
{
Count = 0;
_topIndex = 0;
_top = null;
}
public bool IsEmpty => Count == 0;
public int Count { get; private set; }
public void Dispose()
{
Clear();
}
protected abstract IPoolingNode<T> CreateNodeHolder();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Push(T obj)
{
if (Count == 0 && _top == null)
_top = CreateNodeHolder();
_top[_topIndex] = obj;
_topIndex++;
Count++;
if (_topIndex == PoolsDefaults.DefaultPoolBucketSize)
{
var top = _top;
_top = CreateNodeHolder();
_top.Next = top;
_topIndex = 0;
}
}
/// <summary>
/// Tries to return queue element if any available via `val` parameter.
/// </summary>
/// <returns>
/// true if element found or false otherwise
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T val)
{
if (IsEmpty)
{
val = default;
return false;
}
val = Pop();
return true;
}
/// <summary>
/// Returns queue element
/// </summary>
/// <returns>
/// Returns element or throws IndexOutOfRangeException if no element found
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Pop()
{
if (IsEmpty) throw new IndexOutOfRangeException();
_topIndex--;
if (_topIndex < 0)
{
_topIndex = PoolsDefaults.DefaultPoolBucketSize - 1;
var oldTop = _top;
_top = _top.Next;
oldTop.Dispose();
}
var obj = _top[_topIndex];
_top[_topIndex] = default;
Count--;
return obj;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
while (_top != null)
{
var next = _top.Next;
_top.Dispose();
_top = next;
}
}
}
}

@ -0,0 +1,13 @@
namespace MemoryPools.Collections.Specialized
{
/// <summary>
/// Collection, which is working on shared btw all Pooling* collections buckets
/// </summary>
public class PoolingStackCanon<T> : PoolingStackBase<T> where T : class
{
protected override IPoolingNode<T> CreateNodeHolder()
{
return (IPoolingNode<T>) Pool<PoolingNodeCanon<T>>.Get().Init(PoolsDefaults.DefaultPoolBucketSize);
}
}
}

@ -0,0 +1,9 @@
namespace MemoryPools.Collections.Specialized
{
public static class PoolsDefaults
{
public const int DefaultPoolBucketDegree = 7;
public const int DefaultPoolBucketSize = 1 << DefaultPoolBucketDegree;
public const int DefaultPoolBucketMask = DefaultPoolBucketSize - 1;
}
}

@ -0,0 +1,101 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading;
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
/// <summary>
/// Default implementation of <see cref="ObjectPool{T}"/>.
/// </summary>
/// <typeparam name="T">The type to pool objects for.</typeparam>
/// <remarks>This implementation keeps a cache of retained objects. This means that if objects are returned when the pool has already reached "maximumRetained" objects they will be available to be Garbage Collected.</remarks>
public class DefaultObjectPool<T> : ObjectPool<T> where T : class
{
private protected readonly ObjectWrapper[] _items;
private protected readonly IPooledObjectPolicy<T> _policy;
private protected readonly bool _isDefaultPolicy;
private protected T? _firstItem;
// This class was introduced in 2.1 to avoid the interface call where possible
private protected readonly PooledObjectPolicy<T>? _fastPolicy;
/// <summary>
/// Creates an instance of <see cref="DefaultObjectPool{T}"/>.
/// </summary>
/// <param name="policy">The pooling policy to use.</param>
public DefaultObjectPool(IPooledObjectPolicy<T> policy)
: this(policy, Environment.ProcessorCount * 2)
{
}
/// <summary>
/// Creates an instance of <see cref="DefaultObjectPool{T}"/>.
/// </summary>
/// <param name="policy">The pooling policy to use.</param>
/// <param name="maximumRetained">The maximum number of objects to retain in the pool.</param>
public DefaultObjectPool(IPooledObjectPolicy<T> policy, int maximumRetained)
{
_policy = policy ?? throw new ArgumentNullException(nameof(policy));
_fastPolicy = policy as PooledObjectPolicy<T>;
_isDefaultPolicy = IsDefaultPolicy();
// -1 due to _firstItem
_items = new ObjectWrapper[maximumRetained - 1];
bool IsDefaultPolicy()
{
var type = policy.GetType();
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(DefaultPooledObjectPolicy<>);
}
}
/// <inheritdoc />
public override T Get()
{
var item = _firstItem;
if (item == null || Interlocked.CompareExchange(ref _firstItem, null, item) != item)
{
var items = _items;
for (var i = 0; i < items.Length; i++)
{
item = items[i].Element;
if (item != null && Interlocked.CompareExchange(ref items[i].Element, null, item) == item)
{
return item;
}
}
item = Create();
}
return item;
}
// Non-inline to improve its code quality as uncommon path
[MethodImpl(MethodImplOptions.NoInlining)]
private T Create() => _fastPolicy?.Create() ?? _policy.Create();
/// <inheritdoc />
public override void Return(T obj)
{
if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj)))
{
if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null)
{
var items = _items;
for (var i = 0; i < items.Length && Interlocked.CompareExchange(ref items[i].Element, obj, null) != null; ++i)
{
}
}
}
}
private protected struct ObjectWrapper
{
public T? Element;
}
}
}

@ -0,0 +1,34 @@
using System;
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
/// <summary>
/// The default <see cref="ObjectPoolProvider"/>.
/// </summary>
public class DefaultObjectPoolProvider
: ObjectPoolProvider
{
/// <summary>
/// The maximum number of objects to retain in the pool.
/// </summary>
public int MaximumRetained { get; set; } = Environment.ProcessorCount * 2;
/// <inheritdoc/>
public override ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy)
{
if (policy == null)
{
throw new ArgumentNullException(nameof(policy));
}
if (typeof(IDisposable).IsAssignableFrom(typeof(T)))
{
return new DisposableObjectPool<T>(policy, MaximumRetained);
}
return new DefaultObjectPool<T>(policy, MaximumRetained);
}
}
}

@ -0,0 +1,26 @@
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
/// <summary>
/// Default implementation for <see cref="PooledObjectPolicy{T}"/>.
/// </summary>
/// <typeparam name="T">The type of object which is being pooled.</typeparam>
public class DefaultPooledObjectPolicy<T>
: PooledObjectPolicy<T> where T : class, new()
{
/// <inheritdoc />
public override T Create()
{
return new T();
}
/// <inheritdoc />
public override bool Return(T obj)
{
// DefaultObjectPool<T> doesn't call 'Return' for the default policy.
// So take care adding any logic to this method, as it might require changes elsewhere.
return true;
}
}
}

@ -0,0 +1,92 @@
using System;
using System.Threading;
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
internal sealed class DisposableObjectPool<T>
: DefaultObjectPool<T>, IDisposable where T : class
{
private volatile bool _isDisposed;
public DisposableObjectPool(IPooledObjectPolicy<T> policy)
: base(policy)
{
}
public DisposableObjectPool(IPooledObjectPolicy<T> policy, int maximumRetained)
: base(policy, maximumRetained)
{
}
public override T Get()
{
if (_isDisposed)
{
ThrowObjectDisposedException();
}
return base.Get();
void ThrowObjectDisposedException()
{
throw new ObjectDisposedException(GetType().Name);
}
}
public override void Return(T obj)
{
// When the pool is disposed or the obj is not returned to the pool, dispose it
if (_isDisposed || !ReturnCore(obj))
{
DisposeItem(obj);
}
}
private bool ReturnCore(T obj)
{
bool returnedTooPool = false;
if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj)))
{
if (_firstItem == null && Interlocked.CompareExchange(ref _firstItem, obj, null) == null)
{
returnedTooPool = true;
}
else
{
var items = _items;
for (var i = 0; i < items.Length && !(returnedTooPool = Interlocked.CompareExchange(ref items[i].Element, obj, null) == null); i++)
{
}
}
}
return returnedTooPool;
}
public void Dispose()
{
_isDisposed = true;
DisposeItem(_firstItem);
_firstItem = null;
ObjectWrapper[] items = _items;
for (var i = 0; i < items.Length; i++)
{
DisposeItem(items[i].Element);
items[i].Element = null;
}
}
private static void DisposeItem(T? item)
{
if (item is IDisposable disposable)
{
disposable.Dispose();
}
}
}
}

@ -0,0 +1,24 @@
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
/// <summary>
/// Represents a policy for managing pooled objects.
/// </summary>
/// <typeparam name="T">The type of object which is being pooled.</typeparam>
public interface IPooledObjectPolicy<T> where T : notnull
{
/// <summary>
/// Create a <typeparamref name="T"/>.
/// </summary>
/// <returns>The <typeparamref name="T"/> which was created.</returns>
T Create();
/// <summary>
/// Runs some processing when an object was returned to the pool. Can be used to reset the state of an object and indicate if the object should be returned to the pool.
/// </summary>
/// <param name="obj">The object to return to the pool.</param>
/// <returns><see langword="true" /> if the object should be returned to the pool. <see langword="false" /> if it's not possible/desirable for the pool to keep the object.</returns>
bool Return(T obj);
}
}

@ -0,0 +1,18 @@
using MemoryPools.Memory;
using System.Runtime.CompilerServices;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools
{
public class JetPool<T> where T : class, new()
{
private readonly JetStack<T> _freeObjectsQueue = new JetStack<T>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Get() => _freeObjectsQueue.Count > 0 ? _freeObjectsQueue.Pop() : new T();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Return(T instance) => _freeObjectsQueue.Push(instance);
}
}

@ -0,0 +1,81 @@
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools.Memory
{
/// <summary>
/// Encapsulates manual memory management mechanism. Holds
/// IMemoryOwner instance goes to GC (link = null) only when
/// all owning entities called Dispose() method. This means,
/// that only this mechanism should be used for covering
/// managed instances.
/// </summary>
public sealed class CountdownMemoryOwner<T> : IMemoryOwner<T>
{
private int _length;
private int _offset;
private int _owners;
private T[] _arr;
private CountdownMemoryOwner<T> _parent;
private Memory<T> _memory;
public Memory<T> Memory
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _memory;
private set => _memory = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal CountdownMemoryOwner<T> Init(CountdownMemoryOwner<T> parent, int offset, int length, bool defaultOwner = true)
{
_owners = defaultOwner ? 1 : 0;
_offset = offset;
_length = length;
_parent = parent;
_parent.AddOwner();
Memory = _parent.Memory.Slice(_offset, _length);
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal CountdownMemoryOwner<T> Init(T[] array, int length)
{
_owners = 1;
_offset = 0;
_length = length;
_parent = default;
_arr = array;
Memory = _arr.AsMemory(0, _length);
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddOwner() => _owners++;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
_owners--;
if (_owners > 0)
{
return;
}
if (_parent != default)
{
_parent.Dispose();
_parent = null;
}
else
{
ArrayPool<T>.Shared.Return(_arr);
}
Pool<CountdownMemoryOwner<T>>.Return(this);
}
}
}

@ -0,0 +1,36 @@
using MemoryPools.Memory.Pooling;
using System;
using System.Runtime.CompilerServices;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools.Memory
{
internal sealed class InternalArraysPool
{
private const int MinBufferSize = 128;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CountdownMemoryOwner<byte> Rent(int length)
{
return Rent<byte>(length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CountdownMemoryOwner<T> Rent<T>(int length, bool noDefaultOwner = false)
{
var realLength = length;
var allocLength = length > MinBufferSize ? length : MinBufferSize;
var owner = BucketsBasedCrossThreadsMemoryPool<T>.Shared.Rent(allocLength);
return owner.AsCountdown(0, realLength, noDefaultOwner);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CountdownMemoryOwner<T> RentFrom<T>(ReadOnlySpan<T> source, bool noDefaultOwner = false)
{
var mem = Rent<T>(source.Length, noDefaultOwner);
source.CopyTo(mem.Memory.Span);
return mem;
}
}
}

@ -0,0 +1,90 @@
using System;
using System.Runtime.CompilerServices;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools.Memory
{
internal class JetStack<T>
{
private ObjectWrapper[] _array;
private int _size;
private T _firstItem;
private const int DefaultCapacity = 4;
public JetStack()
{
_array = new ObjectWrapper[DefaultCapacity];
}
// Create a stack with a specific initial capacity. The initial capacity
// must be a non-negative number.
public JetStack(int capacity)
{
_array = new ObjectWrapper[capacity];
}
public int Count => _size;
// Removes all Objects from the Stack.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
Array.Clear(_array, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
_size = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Peek() => _array[_size - 1].Element;
// Pops an item from the top of the stack. If the stack is empty, Pop
// throws an InvalidOperationException.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Pop()
{
var item = _firstItem;
if (_firstItem != null)
{
_firstItem = default;
return item;
}
return _array[--_size].Element;
}
// Pushes an item to the top of the stack.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Push(T item)
{
if (_firstItem == null)
{
_firstItem = item;
return;
}
if (_size >= _array.Length)
{
PushWithResize(item);
}
else
{
_array[_size++].Element = item;
}
}
// Non-inline from Stack.Push to improve its code quality as uncommon path
[MethodImpl(MethodImplOptions.NoInlining)]
private void PushWithResize(T item)
{
Array.Resize(ref _array, _array.Length << 1);
_array[_size].Element = item;
_size++;
}
// PERF: the struct wrapper avoids array-covariance-checks from the runtime when assigning to elements of the array.
private struct ObjectWrapper
{
public T Element;
}
}
}

@ -0,0 +1,35 @@
using System.Buffers;
using System.Runtime.CompilerServices;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools.Memory
{
public static class MemoryEx
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Length<T>(this IMemoryOwner<T> that) =>
that.Memory.Length;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CountdownMemoryOwner<T> AsCountdown<T>(this CountdownMemoryOwner<T> that, bool noDefaultOwner = false) =>
Pool<CountdownMemoryOwner<T>>.Get().Init(that, 0, that.Memory.Length, noDefaultOwner);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CountdownMemoryOwner<T> AsCountdown<T>(this CountdownMemoryOwner<T> that, int offset,
bool noDefaultOwner = false) =>
Pool<CountdownMemoryOwner<T>>.Get().Init(that, offset, that.Memory.Length - offset, noDefaultOwner);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CountdownMemoryOwner<T> AsCountdown<T>(this CountdownMemoryOwner<T> that, int offset, int length, bool noDefaultOwner = false) =>
Pool<CountdownMemoryOwner<T>>.Get().Init(that, offset, length, noDefaultOwner);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IMemoryOwner<T> Slice<T>(this CountdownMemoryOwner<T> that, int offset) =>
Slice(that, offset, that.Memory.Length - offset);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IMemoryOwner<T> Slice<T>(this CountdownMemoryOwner<T> that, int offset, int length) =>
that.AsCountdown(offset, length);
}
}

@ -0,0 +1,25 @@
using System;
using System.Buffers;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools.Memory
{
public class MemoryOwner<T>
: IMemoryOwner<T>
{
public static MemoryOwner<T> Empty = new MemoryOwner<T>(Memory<T>.Empty);
protected MemoryOwner(Memory<T> memory)
{
Memory = memory;
}
public void Dispose()
{
Memory = Memory<T>.Empty;
}
public Memory<T> Memory { get; set; }
}
}

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools.Memory.Pooling
{
public sealed class BucketsBasedCrossThreadsArrayPool<T>
{
[ThreadStatic]
private static BucketsBasedCrossThreadsArrayPool<T> _shared;
private static readonly Queue<T[]>[] _pool = new Queue<T[]>[24];
static BucketsBasedCrossThreadsArrayPool()
{
for (var i = 0; i < _pool.Length; i++) _pool[i] = new Queue<T[]>();
}
public static BucketsBasedCrossThreadsArrayPool<T> Shared => _shared ??= new BucketsBasedCrossThreadsArrayPool<T>();
public T[] Rent(int minimumLength)
{
var queueIndex = Utilities.GetBucket(minimumLength);
var queue = _pool[queueIndex];
T[] arr;
if (queue.Count == 0)
{
var length = Utilities.GetMaxSizeForBucket(queueIndex);
arr = new T[length];
return arr;
}
arr = queue.Dequeue();
return arr;
}
public void Return(T[] array)
{
_pool[Utilities.GetBucket(array.Length)].Enqueue(array);
}
}
}

@ -0,0 +1,51 @@
using System;
using System.Runtime.CompilerServices;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools.Memory.Pooling
{
/// <summary>
/// This pool returns NEW instance if pool is empty and old if non-empty.
/// When got, user can return instance back to pool. If not returned, GC will collect it
/// This means, that if you want to detect 'leaks', you should:
/// 1) add [CallerFilePath], [CallerLineNumber] to your Init() method parameters
/// 2) make finalizer in your type and log saved fileName and lineNumber from (1).
/// </summary>
/// <code>
/// MyType Init(int arg0, string arg1
/// #if DEBUG
/// , [CallerFilePath] string fileName = default, [CallerLineNumber] int lineNumber = default
/// #endif
/// )
/// {
/// #if DEBUG
/// _fileName = fileName;
/// _lineNumber = lineNumber;
/// #endif
/// }
/// #if DEBUG
/// ~MyType()
/// {
/// Console.WriteLine($" - {_fileName}:{_lineNumber}");
/// }
/// #endif
/// </code>
public sealed class BucketsBasedCrossThreadsMemoryPool<T>
{
private BucketsBasedCrossThreadsArrayPool<T> _pool;
[ThreadStatic]
private static BucketsBasedCrossThreadsMemoryPool<T> _mempool;
internal BucketsBasedCrossThreadsArrayPool<T> _arraysPool => _pool ??= new BucketsBasedCrossThreadsArrayPool<T>();
public static BucketsBasedCrossThreadsMemoryPool<T> Shared => _mempool ??= new BucketsBasedCrossThreadsMemoryPool<T>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CountdownMemoryOwner<T> Rent(int minBufferSize = -1)
{
return Pool<CountdownMemoryOwner<T>>.Get().Init(_arraysPool.Rent(minBufferSize), minBufferSize);
}
}
}

@ -0,0 +1,26 @@
using System.Runtime.CompilerServices;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools.Memory.Pooling
{
internal static class Utilities
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int GetMaxSizeForBucket(int binIndex) => 16 << binIndex;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int GetBucket(int size)
{
if (size == 128 /*default chunk size*/) return 7;
size--;
var length = 0;
while (size >= 16)
{
length++;
size = size >> 1;
}
return length;
}
}
}

@ -0,0 +1,32 @@
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
public abstract class ObjectPool<T> where T : class
{
/// <summary>
/// Gets an object from the pool if one is available, otherwise creates one.
/// </summary>
/// <returns>A <typeparamref name="T"/>.</returns>
public abstract T Get();
/// <summary>
/// Return an object to the pool.
/// </summary>
/// <param name="obj">The object to add to the pool.</param>
public abstract void Return(T obj);
}
/// <summary>
/// Methods for creating <see cref="ObjectPool{T}"/> instances.
/// </summary>
public static class ObjectPool
{
/// <inheritdoc />
public static ObjectPool<T> Create<T>(IPooledObjectPolicy<T>? policy = null) where T : class, new()
{
var provider = new DefaultObjectPoolProvider();
return provider.Create(policy ?? new DefaultPooledObjectPolicy<T>());
}
}
}

@ -0,0 +1,25 @@
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
/// <summary>
/// A provider of <see cref="ObjectPool{T}"/> instances.
/// </summary>
public abstract class ObjectPoolProvider
{
/// <summary>
/// Creates an <see cref="ObjectPool"/>.
/// </summary>
/// <typeparam name="T">The type to create a pool for.</typeparam>
public ObjectPool<T> Create<T>() where T : class, new()
{
return Create<T>(new DefaultPooledObjectPolicy<T>());
}
/// <summary>
/// Creates an <see cref="ObjectPool"/> with the given <see cref="IPooledObjectPolicy{T}"/>.
/// </summary>
/// <typeparam name="T">The type to create a pool for.</typeparam>
public abstract ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy) where T : class;
}
}

@ -0,0 +1,52 @@
using MemoryPools.Memory;
using System;
using System.Runtime.CompilerServices;
/*https://github.com/sidristij/memory-pools*/
namespace MemoryPools
{
public static class Pool<T> where T : class, new()
{
private static readonly DefaultObjectPool<T> _freeObjectsQueue = new DefaultObjectPool<T>(new DefaultPooledObjectPolicy<T>());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Get()
{
return _freeObjectsQueue.Get();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Return<T1>(T1 instance) where T1 : T
{
_freeObjectsQueue.Return(instance);
}
}
public static class Pool
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Get<T>() where T : class, new()
{
return Pool<T>.Get();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Return<T>(T instance) where T : class, new()
{
Pool<T>.Return(instance);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CountdownMemoryOwner<T> GetBuffer<T>(int size)
{
return InternalArraysPool.Rent<T>(size, false);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CountdownMemoryOwner<T> GetBufferFrom<T>(ReadOnlySpan<T> source)
{
return InternalArraysPool.RentFrom(source, false);
}
}
}

@ -0,0 +1,17 @@
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
/// <summary>
/// A base type for <see cref="IPooledObjectPolicy{T}"/>.
/// </summary>
/// <typeparam name="T">The type of object which is being pooled.</typeparam>
public abstract class PooledObjectPolicy<T> : IPooledObjectPolicy<T> where T : notnull
{
/// <inheritdoc />
public abstract T Create();
/// <inheritdoc />
public abstract bool Return(T obj);
}
}

@ -1,4 +1,5 @@
using System; using MemoryPools;
using System;
using System.Threading; using System.Threading;
using ZeroLevel.Services.Pools; using ZeroLevel.Services.Pools;
@ -6,23 +7,29 @@ namespace ZeroLevel.Network
{ {
public static class ExchangeExtension public static class ExchangeExtension
{ {
static Pool<AutoResetEvent> _mrePool = new Pool<AutoResetEvent>(16, (p) => new AutoResetEvent(false)); private static DefaultObjectPool<ManualResetEventSlim> _mrePool;
static ExchangeExtension()
{
_mrePool = new DefaultObjectPool<ManualResetEventSlim>(new DefaultPooledObjectPolicy<ManualResetEventSlim>());
}
public static Tresponse Request<Tresponse>(this IClientSet exchange, string alias, TimeSpan timeout) public static Tresponse Request<Tresponse>(this IClientSet exchange, string alias, TimeSpan timeout)
{ {
Tresponse response = default; Tresponse response = default;
var ev = _mrePool.Acquire(); var ev = _mrePool.Get();
ev.Reset();
try try
{ {
if (exchange.Request<Tresponse>(alias, if (exchange.Request<Tresponse>(alias,
_response => { response = _response; ev.Set(); })) _response => { response = _response; ev.Set(); }))
{ {
ev.WaitOne(timeout); ev.Wait(timeout);
} }
} }
finally finally
{ {
_mrePool.Release(ev); _mrePool.Return(ev);
} }
return response; return response;
} }
@ -30,7 +37,8 @@ namespace ZeroLevel.Network
public static Tresponse Request<Tresponse>(this IClientSet exchange, string alias, string inbox, TimeSpan timeout) public static Tresponse Request<Tresponse>(this IClientSet exchange, string alias, string inbox, TimeSpan timeout)
{ {
Tresponse response = default; Tresponse response = default;
var ev = _mrePool.Acquire(); var ev = _mrePool.Get();
ev.Reset();
try try
{ {
if (exchange.Request<Tresponse>(alias, inbox, if (exchange.Request<Tresponse>(alias, inbox,
@ -39,12 +47,12 @@ namespace ZeroLevel.Network
ev.Set(); ev.Set();
})) }))
{ {
ev.WaitOne(timeout); ev.Wait(timeout);
} }
} }
finally finally
{ {
_mrePool.Release(ev); _mrePool.Return(ev);
} }
return response; return response;
} }
@ -52,18 +60,19 @@ namespace ZeroLevel.Network
public static Tresponse Request<Trequest, Tresponse>(this IClientSet exchange, string alias, Trequest request, TimeSpan timeout) public static Tresponse Request<Trequest, Tresponse>(this IClientSet exchange, string alias, Trequest request, TimeSpan timeout)
{ {
Tresponse response = default; Tresponse response = default;
var ev = _mrePool.Acquire(); var ev = _mrePool.Get();
ev.Reset();
try try
{ {
if (exchange.Request<Trequest, Tresponse>(alias, request, if (exchange.Request<Trequest, Tresponse>(alias, request,
_response => { response = _response; ev.Set(); })) _response => { response = _response; ev.Set(); }))
{ {
ev.WaitOne(timeout); ev.Wait(timeout);
} }
} }
finally finally
{ {
_mrePool.Release(ev); _mrePool.Return(ev);
} }
return response; return response;
} }
@ -72,18 +81,19 @@ namespace ZeroLevel.Network
, Trequest request, TimeSpan timeout) , Trequest request, TimeSpan timeout)
{ {
Tresponse response = default; Tresponse response = default;
var ev = _mrePool.Acquire(); var ev = _mrePool.Get();
ev.Reset();
try try
{ {
if (exchange.Request<Trequest, Tresponse>(alias, inbox, request, if (exchange.Request<Trequest, Tresponse>(alias, inbox, request,
_response => { response = _response; ev.Set(); })) _response => { response = _response; ev.Set(); }))
{ {
ev.WaitOne(timeout); ev.Wait(timeout);
} }
} }
finally finally
{ {
_mrePool.Release(ev); _mrePool.Return(ev);
} }
return response; return response;
} }
@ -91,18 +101,19 @@ namespace ZeroLevel.Network
public static Tresponse Request<Tresponse>(this IClientSet exchange, string alias) public static Tresponse Request<Tresponse>(this IClientSet exchange, string alias)
{ {
Tresponse response = default; Tresponse response = default;
var ev = _mrePool.Acquire(); var ev = _mrePool.Get();
ev.Reset();
try try
{ {
if (exchange.Request<Tresponse>(alias, if (exchange.Request<Tresponse>(alias,
_response => { response = _response; ev.Set(); })) _response => { response = _response; ev.Set(); }))
{ {
ev.WaitOne(Network.BaseSocket.MAX_REQUEST_TIME_MS); ev.Wait(Network.BaseSocket.MAX_REQUEST_TIME_MS);
} }
} }
finally finally
{ {
_mrePool.Release(ev); _mrePool.Return(ev);
} }
return response; return response;
} }
@ -110,7 +121,8 @@ namespace ZeroLevel.Network
public static Tresponse Request<Tresponse>(this IClientSet exchange, string alias, string inbox) public static Tresponse Request<Tresponse>(this IClientSet exchange, string alias, string inbox)
{ {
Tresponse response = default; Tresponse response = default;
var ev = _mrePool.Acquire(); var ev = _mrePool.Get();
ev.Reset();
try try
{ {
if (exchange.Request<Tresponse>(alias, inbox, if (exchange.Request<Tresponse>(alias, inbox,
@ -119,12 +131,12 @@ namespace ZeroLevel.Network
ev.Set(); ev.Set();
})) }))
{ {
ev.WaitOne(Network.BaseSocket.MAX_REQUEST_TIME_MS); ev.Wait(Network.BaseSocket.MAX_REQUEST_TIME_MS);
} }
} }
finally finally
{ {
_mrePool.Release(ev); _mrePool.Return(ev);
} }
return response; return response;
} }
@ -132,18 +144,19 @@ namespace ZeroLevel.Network
public static Tresponse Request<Trequest, Tresponse>(this IClientSet exchange, string alias, Trequest request) public static Tresponse Request<Trequest, Tresponse>(this IClientSet exchange, string alias, Trequest request)
{ {
Tresponse response = default; Tresponse response = default;
var ev = _mrePool.Acquire(); var ev = _mrePool.Get();
ev.Reset();
try try
{ {
if (exchange.Request<Trequest, Tresponse>(alias, request, if (exchange.Request<Trequest, Tresponse>(alias, request,
_response => { response = _response; ev.Set(); })) _response => { response = _response; ev.Set(); }))
{ {
ev.WaitOne(Network.BaseSocket.MAX_REQUEST_TIME_MS); ev.Wait(Network.BaseSocket.MAX_REQUEST_TIME_MS);
} }
} }
finally finally
{ {
_mrePool.Release(ev); _mrePool.Return(ev);
} }
return response; return response;
} }
@ -152,18 +165,19 @@ namespace ZeroLevel.Network
, Trequest request) , Trequest request)
{ {
Tresponse response = default; Tresponse response = default;
var ev = _mrePool.Acquire(); var ev = _mrePool.Get();
ev.Reset();
try try
{ {
if (exchange.Request<Trequest, Tresponse>(alias, inbox, request, if (exchange.Request<Trequest, Tresponse>(alias, inbox, request,
_response => { response = _response; ev.Set(); })) _response => { response = _response; ev.Set(); }))
{ {
ev.WaitOne(Network.BaseSocket.MAX_REQUEST_TIME_MS); ev.Wait(Network.BaseSocket.MAX_REQUEST_TIME_MS);
} }
} }
finally finally
{ {
_mrePool.Release(ev); _mrePool.Return(ev);
} }
return response; return response;
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save

Powered by TurnKey Linux.