Skip to content

Commit 2e6da08

Browse files
Added ArrayPoolSegment and extensions for use with subsets.
1 parent dd237d9 commit 2e6da08

3 files changed

Lines changed: 116 additions & 25 deletions

File tree

source/ArrayPoolSegment.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Buffers;
3+
4+
namespace Open.Collections;
5+
6+
public readonly struct ArrayPoolSegment<T> : IDisposable
7+
{
8+
public readonly ArraySegment<T> Segment;
9+
public readonly ArrayPool<T>? Pool;
10+
private readonly bool _clear;
11+
12+
public ArrayPoolSegment(
13+
int length,
14+
ArrayPool<T>? pool = null,
15+
bool clearArrayOnDispose = false)
16+
{
17+
_clear = clearArrayOnDispose;
18+
Pool = pool;
19+
T[]? array = pool?.Rent(length) ?? new T[length];
20+
Segment = new(array, 0, length);
21+
}
22+
23+
public void Dispose() => Pool?.Return(Segment.Array, _clear);
24+
25+
public static implicit operator ArraySegment<T> (ArrayPoolSegment<T> segment) => segment.Segment;
26+
public static implicit operator Memory<T> (ArrayPoolSegment<T> segment) => segment.Segment;
27+
public static implicit operator ReadOnlyMemory<T>(ArrayPoolSegment<T> segment) => segment.Segment;
28+
}
29+
30+
public static class ArrayPoolExtensions
31+
{
32+
public static ArrayPoolSegment<T> RentSegment<T>(
33+
this ArrayPool<T> pool,
34+
int length,
35+
bool clearArrayOnDispose = false)
36+
=> new(length, pool, clearArrayOnDispose);
37+
}

source/Extensions.Subsets.cs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,21 @@ static IEnumerable<T[]> SubsetsCore(IReadOnlyList<T> source, int count, T[] buff
3030
{
3131
if (count == 1)
3232
{
33-
foreach (var e in source)
33+
foreach (T? e in source)
3434
{
3535
buffer[0] = e;
3636
yield return buffer;
3737
}
3838
yield break;
3939
}
4040

41-
var diff = source.Count - count;
42-
var pool = count > 128 ? ArrayPool<int>.Shared : null;
43-
var indices = pool?.Rent(count) ?? new int[count];
41+
int diff = source.Count - count;
42+
ArrayPool<int>? pool = count > 128 ? ArrayPool<int>.Shared : null;
43+
int[]? indices = pool?.Rent(count) ?? new int[count];
4444
try
4545
{
46-
var pos = 0;
47-
var index = 0;
46+
int pos = 0;
47+
int index = 0;
4848

4949
loop:
5050
while (pos < count)
@@ -78,12 +78,12 @@ static IEnumerable<T[]> SubsetsCore(IReadOnlyList<T> source, int count, T[] buff
7878
/// <returns>An enumerable containing the resultant subsets as a memory buffer.</returns>
7979
public static IEnumerable<ReadOnlyMemory<T>> SubsetsBuffered<T>(this IReadOnlyList<T> source, int count)
8080
{
81-
var pool = count > 128 ? ArrayPool<T>.Shared : null;
82-
var buffer = pool?.Rent(count) ?? new T[count];
81+
ArrayPool<T>? pool = count > 128 ? ArrayPool<T>.Shared : null;
82+
T[]? buffer = pool?.Rent(count) ?? new T[count];
8383
var readBuffer = new ReadOnlyMemory<T>(buffer, 0, count);
8484
try
8585
{
86-
foreach (var _ in Subsets(source, count, buffer))
86+
foreach (T[]? _ in Subsets(source, count, buffer))
8787
yield return readBuffer;
8888
}
8989
finally
@@ -100,7 +100,34 @@ public static IEnumerable<ReadOnlyMemory<T>> SubsetsBuffered<T>(this IReadOnlyLi
100100
/// <returns>An enumerable containing the resultant subsets.</returns>
101101
public static IEnumerable<T[]> Subsets<T>(this IReadOnlyList<T> source, int count)
102102
{
103-
foreach (var subset in SubsetsBuffered(source, count))
104-
yield return subset.ToArray();
103+
ArrayPool<T>? pool = count > 128 ? ArrayPool<T>.Shared : null;
104+
T[]? buffer = pool?.Rent(count) ?? new T[count];
105+
try
106+
{
107+
foreach (T[]? _ in Subsets(source, count, buffer))
108+
{
109+
var a = new T[count];
110+
buffer.CopyTo(a.AsSpan());
111+
yield return a;
112+
}
113+
}
114+
finally
115+
{
116+
pool?.Return(buffer, true);
117+
}
118+
}
119+
120+
/// <param name="source">The source list to derive from.</param>
121+
/// <param name="count">The maximum number of items in the result sets.</param>
122+
/// <param name="pool">The array pool to get result arrays from.</param>
123+
/// <inheritdoc cref="Subsets{T}(IReadOnlyList{T}, int)" />
124+
public static IEnumerable<ArrayPoolSegment<T>> Subsets<T>(this IReadOnlyList<T> source, int count, ArrayPool<T>? pool, bool clearArray = false)
125+
{
126+
foreach (ReadOnlyMemory<T> subset in SubsetsBuffered(source, count))
127+
{
128+
var a = new ArrayPoolSegment<T>(count, pool, clearArray);
129+
subset.CopyTo(a);
130+
yield return a;
131+
}
105132
}
106133
}

source/Extensions.SubsetsProgressive.cs

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,23 @@ static IEnumerable<T[]> SubsetsProgressiveCore(IReadOnlyList<T> source, int coun
2828
{
2929
if (count == 1)
3030
{
31-
foreach (var e in source)
31+
foreach (T? e in source)
3232
{
3333
buffer[0] = e;
3434
yield return buffer;
3535
}
3636
yield break;
3737
}
3838

39-
var lastSlot = count - 1;
40-
var pool = lastSlot > 128 ? ArrayPool<int>.Shared : null;
41-
var indices = pool?.Rent(lastSlot) ?? new int[lastSlot];
39+
int lastSlot = count - 1;
40+
ArrayPool<int>? pool = lastSlot > 128 ? ArrayPool<int>.Shared : null;
41+
int[]? indices = pool?.Rent(lastSlot) ?? new int[lastSlot];
4242
try
4343
{
44-
using var e = source.GetEnumerator();
44+
using IEnumerator<T>? e = source.GetEnumerator();
4545

46-
// Setup the first result and make sure there's enough for the count.
47-
var n = 0;
46+
// Setup the first result and make sure there's enough for the count.
47+
int n = 0;
4848
for (; n < count; ++n)
4949
{
5050
if (!e.MoveNext()) throw new ArgumentOutOfRangeException(nameof(count), count, "Is greater than the length of the source.");
@@ -57,9 +57,9 @@ static IEnumerable<T[]> SubsetsProgressiveCore(IReadOnlyList<T> source, int coun
5757
while (e.MoveNext())
5858
{
5959
buffer[lastSlot] = e.Current;
60-
foreach (var _ in Collections.Subsets.IndexesInternal(n, lastSlot, indices))
60+
foreach (int[]? _ in Collections.Subsets.IndexesInternal(n, lastSlot, indices))
6161
{
62-
for (var i = 0; i < lastSlot; i++)
62+
for (int i = 0; i < lastSlot; i++)
6363
buffer[i] = source[indices[i]];
6464

6565
yield return buffer;
@@ -79,12 +79,12 @@ static IEnumerable<T[]> SubsetsProgressiveCore(IReadOnlyList<T> source, int coun
7979
/// <returns>An enumerable containing the resultant subsets as a memory buffer.</returns>
8080
public static IEnumerable<ReadOnlyMemory<T>> SubsetsProgressiveBuffered<T>(this IReadOnlyList<T> source, int count)
8181
{
82-
var pool = count > 128 ? ArrayPool<T>.Shared : null;
83-
var buffer = pool?.Rent(count) ?? new T[count];
82+
ArrayPool<T>? pool = count > 128 ? ArrayPool<T>.Shared : null;
83+
T[]? buffer = pool?.Rent(count) ?? new T[count];
8484
var readBuffer = new ReadOnlyMemory<T>(buffer, 0, count);
8585
try
8686
{
87-
foreach (var _ in SubsetsProgressive(source, count, buffer))
87+
foreach (T[]? _ in SubsetsProgressive(source, count, buffer))
8888
yield return readBuffer;
8989
}
9090
finally
@@ -103,7 +103,34 @@ public static IEnumerable<ReadOnlyMemory<T>> SubsetsProgressiveBuffered<T>(this
103103
/// <returns>An enumerable containing the resultant subsets.</returns>
104104
public static IEnumerable<T[]> SubsetsProgressive<T>(this IReadOnlyList<T> source, int count)
105105
{
106-
foreach (var subset in SubsetsProgressiveBuffered(source, count))
107-
yield return subset.ToArray();
106+
ArrayPool<T>? pool = count > 128 ? ArrayPool<T>.Shared : null;
107+
T[]? buffer = pool?.Rent(count) ?? new T[count];
108+
try
109+
{
110+
foreach (T[]? _ in SubsetsProgressive(source, count, buffer))
111+
{
112+
var a = new T[count];
113+
buffer.CopyTo(a.AsSpan());
114+
yield return a;
115+
}
116+
}
117+
finally
118+
{
119+
pool?.Return(buffer, true);
120+
}
121+
}
122+
123+
/// <param name="source">The source list to derive from.</param>
124+
/// <param name="count">The maximum number of items in the result sets.</param>
125+
/// <param name="pool">The array pool to get result arrays from.</param>
126+
/// <inheritdoc cref="SubsetsProgressive{T}(IReadOnlyList{T}, int)" />
127+
public static IEnumerable<ArrayPoolSegment<T>> SubsetsProgressive<T>(this IReadOnlyList<T> source, int count, ArrayPool<T>? pool, bool clearArray = false)
128+
{
129+
foreach (ReadOnlyMemory<T> subset in SubsetsProgressiveBuffered(source, count))
130+
{
131+
var a = new ArrayPoolSegment<T>(count, pool, clearArray);
132+
subset.CopyTo(a);
133+
yield return a;
134+
}
108135
}
109136
}

0 commit comments

Comments
 (0)