Created
March 17, 2022 11:38
-
-
Save E-K/5e9f70778cc6e098f6faa25aea56f163 to your computer and use it in GitHub Desktop.
ランダムアクセス可能なリングバッファで実装されたQueue
This file contains hidden or 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
using System; | |
using System.Collections.Generic; | |
using System.Runtime.CompilerServices; | |
namespace Nandemoii | |
{ | |
/// <summary> | |
/// 各要素にランダムアクセス可能なリングバッファで実装されたQueue | |
/// </summary> | |
public class RandomAccessQueue<T> : IReadOnlyList<T> | |
{ | |
/// <summary> | |
/// バッファサイズを拡張していく際の係数 | |
/// </summary> | |
const int ResizeFactor = 2; | |
/// <summary> | |
/// 初期バッファサイズを確保するときのサイズ | |
/// </summary> | |
const int DefaultCapacity = 8; | |
private int _from; | |
private T[] _array; | |
public int Count { get; private set; } | |
public int Capacity => _array.Length; | |
public T this[int index] | |
{ | |
get | |
{ | |
if (index < 0 || index >= Count) | |
throw new ArgumentOutOfRangeException(nameof(index)); | |
return GetItemAt(index); | |
} | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private T GetItemAt(int index /* 先頭のアイテムから数えたindex、生のバッファ内の位置ではない */) | |
{ | |
var rawIndex = (_from + index) % _array.Length; | |
return _array[rawIndex]; | |
} | |
public RandomAccessQueue() : this(DefaultCapacity) | |
{ | |
} | |
public RandomAccessQueue(int capacity) | |
{ | |
if (capacity < 0) | |
throw new ArgumentException(nameof(capacity)); | |
_array = new T[capacity]; | |
_from = 0; | |
Count = 0; | |
} | |
public void Enqueue(T item) | |
{ | |
void Add(T itm) | |
{ | |
var next = (_from + Count) % _array.Length; | |
_array[next] = itm; | |
Count++; | |
} | |
if(_array.Length > Count) | |
{ | |
Add(item); | |
return; | |
} | |
//full | |
var newArray = new T[Math.Max(_array.Length * ResizeFactor, DefaultCapacity)]; | |
if(Count > 0) | |
{ | |
for(int i = 0; i < Count; i++) | |
{ | |
var index = (_from + i) % _array.Length; | |
newArray[i] = _array[index]; | |
} | |
_array = newArray; | |
_from = 0; | |
Add(item); | |
} | |
} | |
public bool TryDequeue(out T item) | |
{ | |
if (Count == 0) | |
{ | |
item = default; | |
return false; | |
} | |
item = _array[_from]; | |
_array[_from] = default; | |
_from = (++_from) % _array.Length; | |
Count--; | |
return true; | |
} | |
public T Dequeue() | |
{ | |
if (TryDequeue(out var item)) | |
return item; | |
throw new InvalidOperationException("cannot dequeue from empty queue."); | |
} | |
public void Clear() | |
{ | |
for(int i = 0; i < _array.Length; i++) | |
{ | |
_array[i] = default; | |
} | |
Count = 0; | |
_from = 0; | |
} | |
public IEnumerator<T> GetEnumerator() => new Enumerator(this); | |
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => this.GetEnumerator(); | |
public struct Enumerator : IEnumerator<T> | |
{ | |
private readonly RandomAccessQueue<T> _enumerable; | |
private int _index; | |
public T Current => _enumerable[_index]; | |
object System.Collections.IEnumerator.Current => this.Current; | |
public Enumerator(RandomAccessQueue<T> enumerable) | |
{ | |
_enumerable = enumerable; | |
_index = -1; | |
} | |
public bool MoveNext() => ++_index < _enumerable.Count; | |
public void Dispose() { } | |
public void Reset() { } | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment