Skip to content

Instantly share code, notes, and snippets.

@hsytkm
Last active December 21, 2020 10:07
Show Gist options
  • Save hsytkm/14390c1280397538fe8b87a366db2c44 to your computer and use it in GitHub Desktop.
Save hsytkm/14390c1280397538fe8b87a366db2c44 to your computer and use it in GitHub Desktop.
Access array items via ref
/* - https://github.com/hsytkm/CSharpStandardSamples/blob/master/CSharpStandardSamples.Core/Spans/PooledArray.cs
*
* - Pooling large arrays with ArrayPool https://adamsitnik.com/Array-Pool/
* that it has a default max array length, equal to 2^20 (1024*1024 = 1 048 576).
*
* - LitJWTに見るモダンなC#のbyte[]とSpan操作法 http://neue.cc/2019/05/27_578.html
* ようするに、今どきnew byte[]なんてしたら殺されるぞ!
*
* - https://gist.github.com/ufcpp/b0853cff5823d49306ba693aaa5c39fb
*/
#nullable enable
using System;
using System.Buffers;
var size = 1025; // 1MByte最大っぽいので控えめに
using var array = new PooledArray<byte>(size);
// ゼロ初期化されてないのでクリア
for (var i = 0; i < array.Length; i++)
{
array[i] = 0;
}
Console.WriteLine($"array[1]={array[1]}");
ref var x1 = ref array[1];
x1 += 1;
Console.WriteLine($"array[1]={array[1]}");
array[1] += 10;
Console.WriteLine($"array[1]={array[1]}");
int counter = 0;
foreach (ref var x in array)
{
x += 100;
counter++;
}
Console.WriteLine($"array[1]={array[1]}");
Console.WriteLine($"LoopCount={counter}");
/// <summary>
/// <see cref="ArrayPool{T}"/>から借りてきて、<see cref="Dispose"/>で返却するためのラッパー。
/// 小サイズなら stackalloc<T> を使った方が効率よく、バカ大なら T[] するしかない(はず)。
/// </summary>
public readonly struct PooledArray<T> : IDisposable
where T : notnull
{
public readonly int Length;
private readonly ArrayPool<T>? _pool;
private readonly T[] _array; // 要求サイズよりも大きいキリのよいサイズが確保されています
public PooledArray(int minimumLength) : this(minimumLength, ArrayPool<T>.Shared) { }
private PooledArray(int minimumLength, ArrayPool<T> pool)
=> (Length, _pool, _array) = (minimumLength, pool, pool.Rent(minimumLength));
public ref T this[int index] => ref _array[index];
public void Dispose() => _pool?.Return(_array);
public PooledArrayEnumerator<T> GetEnumerator() => new PooledArrayEnumerator<T>(_array, Length);
public struct PooledArrayEnumerator<U> where U : notnull
{
private int _index;
private readonly U[] _array;
private readonly int _length;
public PooledArrayEnumerator(U[] array, int length)
=> (_index, _array, _length) = (-1, array, length);
public ref U Current => ref _array[_index];
public bool MoveNext() => ++_index < _length;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment