using System.Collections.Generic;
namespace Collections
{
///
/// 循環バッファ。
///
/// 要素の型
public class CircularBuffer : IEnumerable
{
#region フィールド
T[] data;
int top, bottom;
int mask;
#endregion
#region 初期化
public CircularBuffer() : this(256) {}
///
/// 初期最大容量を指定して初期化。
///
/// 初期載大容量
public CircularBuffer(int capacity)
{
capacity = Pow2((uint)capacity);
this.data = new T[capacity];
this.top = this.bottom = 0;
this.mask = capacity - 1;
}
static int Pow2(uint n)
{
--n;
int p = 0;
for (; n != 0; n >>= 1) p = (p << 1) + 1;
return p + 1;
}
#endregion
#region プロパティ
///
/// 格納されている要素数。
///
public int Count
{
get
{
int count = this.bottom - this.top;
if (count < 0) count += this.data.Length;
return count;
}
}
///
/// i 番目の要素を読み書き。
///
/// 読み書き位置
/// 読み出した要素
public T this[int i]
{
get { return this.data[(i + this.top) & this.mask]; }
set { this.data[(i + this.top) & this.mask] = value; }
}
#endregion
#region 挿入・削除
///
/// 配列を確保しなおす。
///
///
/// 配列長は2倍ずつ拡張していきます。
///
void Extend()
{
T[] data = new T[this.data.Length * 2];
int i = 0;
foreach (T elem in this)
{
data[i] = elem;
++i;
}
this.top = 0;
this.bottom = this.Count;
this.data = data;
this.mask = data.Length - 1;
}
///
/// i 番目の位置に新しい要素を追加。
///
/// 追加位置
/// 追加する要素
public void Insert(int i, T elem)
{
if (this.Count >= this.data.Length - 1)
this.Extend();
if (i < this.Count / 2)
{
for (int n = 0; n <= i; ++n)
{
this[n - 1] = this[n];
}
this.top = (this.top - 1) & this.mask;
this[i] = elem;
}
else
{
for (int n = this.Count; n > i; --n)
{
this[n] = this[n - 1];
}
this[i] = elem;
this.bottom = (this.bottom + 1) & this.mask;
}
}
///
/// 先頭に新しい要素を追加。
///
/// 追加する要素
public void InsertFirst(T elem)
{
if (this.Count >= this.data.Length - 1)
this.Extend();
this.top = (this.top - 1) & this.mask;
this.data[this.top] = elem;
}
///
/// 末尾に新しい要素を追加。
///
/// 追加する要素
public void InsertLast(T elem)
{
if (this.Count >= this.data.Length - 1)
this.Extend();
this.data[this.bottom] = elem;
this.bottom = (this.bottom + 1) & this.mask;
}
///
/// i 番目の要素を削除。
///
/// 削除位置
public void Erase(int i)
{
for (int n = i; n < this.Count - 1; ++n)
{
this[n] = this[n + 1];
}
this.bottom = (this.bottom - 1) & this.mask;
}
///
/// 先頭の要素を削除。
///
public void EraseFirst()
{
this.top = (this.top + 1) & this.mask;
}
///
/// 末尾の要素を削除。
///
public void EraseLast()
{
this.bottom = (this.bottom - 1) & this.mask;
}
#endregion
#region IEnumerable メンバ
public IEnumerator GetEnumerator()
{
if (this.top <= this.bottom)
{
for (int i = this.top; i < this.bottom; ++i)
yield return this.data[i];
}
else
{
for (int i = this.top; i < this.data.Length; ++i)
yield return this.data[i];
for (int i = 0; i < this.bottom; ++i)
yield return this.data[i];
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
}