Skip to content

Instantly share code, notes, and snippets.

@E-K
Created March 17, 2022 11:38
Show Gist options
  • Save E-K/5e9f70778cc6e098f6faa25aea56f163 to your computer and use it in GitHub Desktop.
Save E-K/5e9f70778cc6e098f6faa25aea56f163 to your computer and use it in GitHub Desktop.
ランダムアクセス可能なリングバッファで実装されたQueue
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