/// <summary>
/// 環形堆棧類,長度固定,頂與底相接造成一個圓環,需自定義覆蓋時丟棄對象的處理方法
/// </summary>
/// <typeparam name="T">環形堆棧中對象的類型</typeparam>
/// <remarks>屬於一個固定大小的堆棧式緩存,當增加速度過快時自動覆蓋最早壓入的對象</remarks>
public sealed class RingStack<T>
{
/// <summary>
/// 堆棧的容量
/// </summary>
public readonly int Capacity;
/// <summary>
/// 堆棧的數據集
/// </summary>
private T[] _Items;
/// <summary>
/// 堆棧頂部的指針
/// </summary>
private int _TopIndex;
/// <summary>
/// 堆棧底部的指針
/// </summary>
private int _BottomIndex;
/// <summary>
/// 對象的數量
/// </summary>
private int _Count;
/// <summary>
/// 獲取堆棧中對象的數量
/// </summary>
/// <remarks>此屬性的讀取是內部鎖定的,所以多線程操做是安全的</remarks>
public int Count
{
get
{
lock (this)
{
return _Count;
}
}
}
/// <summary>
/// 覆蓋時丟棄對象的處理方法
/// </summary>
public Action<T> Drop;
/// <summary>
/// 初始化環形堆棧的新實例
/// </summary>
/// <param name="capacity">堆棧的容量</param>
public RingStack(int capacity)
{
Capacity = capacity;
_Items = new T[Capacity];
_TopIndex = _BottomIndex = 0;
_Count = 0;
}
/// <summary>
/// 從堆棧中彈出一個對象
/// </summary>
/// <param name="item">彈出的對象</param>
/// <returns>返回是否成功彈出對象,true表示彈出對象成功,false表示彈出對象失敗</returns>
/// <remarks>此操做是內部鎖定的,所以多線程操做是安全的</remarks>
public bool Pop(ref T item)
{
lock (this)
{
if (_TopIndex == _BottomIndex)
{
return false;
}
item = _Items[_TopIndex];
if ((--_TopIndex) == -1)
{
_TopIndex = Capacity - 1;
}
--_Count;
return true;
}
}
/// <summary>
/// 將指定的對象壓入堆棧
/// </summary>
/// <param name="item">須要壓入的對象</param>
/// <remarks>此操做是內部鎖定的,所以多線程操做是安全的</remarks>
public void Push(T item)
{
Console.WriteLine(string.Format("top:{0},bott:{1}", _TopIndex, _BottomIndex));
lock (this)
{
if ((++_TopIndex) == Capacity)
{
_TopIndex = 0;
}
if (_TopIndex == _BottomIndex)
{
if ((++_BottomIndex) == Capacity)
{
_BottomIndex = 0;
}
if (Drop != null)
{
Drop(_Items[_BottomIndex]);
}
--_Count;
}
_Items[_TopIndex] = item;
//_TopIndex++;
++_Count;
}
}
/// <summary>
/// 清除堆棧中的全部對象
/// </summary>
/// <remarks>此操做是內部鎖定的,所以多線程操做是安全的</remarks>
public void Clear()
{
lock (this)
{
T t = default(T);
while (_Count > 0)
{
Pop(ref t);
if (Drop != null)
{
Drop(t);
}
}
}
}
}