using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
public class RingBuffer<T> : IEnumerable<T>
{
#region フィールド
T[] data;
int _Count;
#endregion
#region コンストラクター
/// <summary>
/// 初期最大容量を指定して初期化
/// </summary>
/// <param name="capacity">初期載大容量</param>
public RingBuffer(int capacity)
{
this.data = new T[capacity];
}
public RingBuffer(IList<T> list)
{
this.data = list.ToArray<T>();
_Count = data.Length;
}
#endregion
#region プロパティー
public int Count
{
get
{
return _Count;
}
}
/// <summary>
/// インデクサー
/// </summary>
/// <param name="i">読み書き位置</param>
/// <returns>読み出した要素</returns>
public T this[int i]
{
get
{
if (i < 0)
{
uint a = (uint)-i;
if (a > _Count)
{
a = MathEx.mod(a, (uint)_Count);
if (a == 0) return data[0];
}
return data[_Count - a];
}
return this.data[(int)MathEx.mod((uint)i, (uint)data.Length)];
}
set
{
this.data[(int)MathEx.mod((uint)i, (uint)data.Length)] = value;
}
}
#endregion
#region 配列操作
/// <summary>
/// 配列を拡張する
/// </summary>
/// <param name="capacity"></param>
private void Extend(int capacity)
{
if ( capacity <= _Count)
throw new ArgumentException("容量が要素の数より少ないか、同じ");
Array.Resize(ref data, capacity);
}
/// <summary>
/// 配列の大きさを要素の個数に合わせる
/// </summary>
public void Fit()
{
Array.Resize(ref data, _Count);
}
/// <summary>
/// idx番目の位置に新しい要素を追加
/// </summary>
/// <param name="idx">追加位置</param>
/// <param name="elem">追加する要素</param>
public void Insert(int idx, T elem)
{
if (this._Count <= this.data.Length - 1)
Extend(_Count + 1);
Array.Copy(data, idx, data, idx + 1, _Count - idx);
data[idx] = elem;
_Count++;
}
/// <summary>
/// 先頭に新しい要素を追加。
/// </summary>
/// <param name="elem">追加する要素</param>
public void InsertFirst(T elem)
{
this.Insert(0, elem);
}
/// <summary>
/// 末尾に新しい要素を追加。
/// </summary>
/// <param name="elem">追加する要素</param>
public void InsertLast(T elem)
{
if (this._Count <= this.data.Length - 1)
Extend(_Count + 1);
data[_Count] = elem;
_Count++;
}
/// <summary>
/// i 番目の要素を削除。
/// </summary>
/// <param name="i">削除位置</param>
public void Delete(int idx)
{
for (int n = idx; n < this._Count - 1; n++)
{
data[n] = data[n + 1];
}
_Count--;
}
/// <summary>
/// 先頭の要素を削除。
/// </summary>
public void DeleteFirst()
{
//this.top = (this.top + 1) & this.mask;
Delete(0);
}
/// <summary>
/// 末尾の要素を削除。
/// </summary>
public void DeleteLast()
{
//this.bottom = (this.bottom - 1) & this.mask;
Delete(_Count - 1);
}
#endregion
#region 検索
public int FindIndex(Predicate<T> match)
{
for (int idx = 0; idx < data.Length; idx++)
{
if (match(data[idx]))
return idx;
}
return -1;
}
public int FindIndex(int startIndex, Predicate<T> match)
{
for (int idx = startIndex; idx < data.Length; idx++)
{
if (match(data[idx]))
return idx;
}
return -1;
}
public int FindIndex(int startIndex, int count, Predicate<T> match)
{
for (int idx = startIndex; idx < startIndex + count; idx++)
{
if (match(data[idx]))
return idx;
}
return -1;
}
#endregion
#region IEnumerable<T> メンバ
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < _Count; i++)
{
yield return data[i];
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
}
public static class MathEx
{
/// <summary>
/// 剰余の計算
/// </summary>
/// <param name="x">割られる数</param>
/// <param name="y">割る数</param>
/// <returns>余り</returns>
public static uint mod(uint x, uint y)
{
ulong a = x;
ulong b = y;
b = b << 31;
for (int i = 0; i < 32; i++)
{
if (a >= b)
{
a -= b;
}
b = b >> 1;
}
return (uint)a;
}
}