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 } }