Last active
December 21, 2020 10:07
-
-
Save hsytkm/14390c1280397538fe8b87a366db2c44 to your computer and use it in GitHub Desktop.
Access array items via ref
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* - 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