2023-06-21 12:46:23 -04:00

471 lines
14 KiB
C#

using System;
using System.Collections;
namespace System.util.collections
{
/// <summary>
/// Circular buffer of arrays
/// </summary>
public class k_Deque : ISequence
{
#region k_BlockIterator Implementation
private class k_BlockIterator : k_Iterator
{
private readonly k_Deque mk_Deque;
private int mi_Index;
private int mi_BlockIndex;
private int mi_BlockOffset;
public k_BlockIterator(k_Deque ak_Deque, int ai_Index)
{
mk_Deque = ak_Deque;
mi_Index = ai_Index;
mi_BlockIndex = mk_Deque.CalcBlockAndPos(mi_Index, out mi_BlockOffset);
}
public override void Move(int ai_Count)
{
int li_Index = mi_Index + ai_Count;
if (li_Index > mk_Deque.Count)
throw new InvalidOperationException("Tried to move beyond end element.");
else if (li_Index < 0)
throw new InvalidOperationException("Tried to move before first element.");
mi_Index = li_Index;
mi_BlockOffset += ai_Count;
if (mi_BlockOffset >= k_Deque.mi_BlockSize || mi_BlockOffset < 0)
mi_BlockIndex = mk_Deque.CalcBlockAndPos(mi_Index, out mi_BlockOffset);
}
public override int Distance(k_Iterator ak_Iter)
{
return mi_Index - ((k_BlockIterator)ak_Iter).mi_Index;
}
public override object Collection
{
get { return mk_Deque; }
}
public override object Current
{
get
{
if (mi_Index < 0 || mi_Index >= mk_Deque.mi_Count)
throw new k_InvalidPositionException();
return mk_Deque.mk_Blocks[mi_BlockIndex][mi_BlockOffset];
}
set
{
if (mi_Index < 0 || mi_Index >= mk_Deque.mi_Count)
throw new k_InvalidPositionException();
mk_Deque.mk_Blocks[mi_BlockIndex][mi_BlockOffset] = value;
}
}
public override bool Equals(object ak_Obj)
{
k_BlockIterator lk_Iter = ak_Obj as k_BlockIterator;
if (lk_Iter == null)
return false;
return (mi_Index == lk_Iter.mi_Index) && object.ReferenceEquals(this.Collection, lk_Iter.Collection);
}
public override int GetHashCode()
{
return mk_Deque.GetHashCode() ^ mi_Index;
}
public override k_Iterator Clone()
{
return new k_BlockIterator(mk_Deque, mi_Index);
}
internal int Index
{
get { return mi_Index; }
}
}
private class k_PinnedBlockIterator : k_BlockIterator
{
public k_PinnedBlockIterator(k_Deque ak_Deque, int ai_Index)
: base(ak_Deque, ai_Index)
{
}
public override void Move(int ai_Count)
{
throw new k_IteratorPinnedException();
}
}
#endregion
private const int mi_BlockSize = 16;
private object[][] mk_Blocks;
private int mi_Offset;
private int mi_Count;
public k_Deque()
: this(mi_BlockSize)
{
}
public k_Deque(int ai_Capacity)
{
if (ai_Capacity < 0)
throw new ArgumentException("Capacity must be positive.", "ai_Capacity");
mk_Blocks = new object[(ai_Capacity+mi_BlockSize-1)/mi_BlockSize][];
for (int i=0; i<mk_Blocks.Length; ++i)
mk_Blocks[i] = new object[mi_BlockSize];
}
// IContainer Members
public k_Iterator Begin
{
get { return new k_PinnedBlockIterator(this, 0); }
}
public k_Iterator End
{
get { return new k_PinnedBlockIterator(this, mi_Count); }
}
public bool IsEmpty
{
get { return (this.Count == 0); }
}
public k_Iterator Find(object ak_Value)
{
return k_Algorithm.Find(this.Begin, this.End, ak_Value);
}
public k_Iterator Erase(k_Iterator ak_Where)
{
return Erase(ak_Where, ak_Where + 1);
}
public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last)
{
if (ak_First == ak_Last)
return ak_Last;
int li_FirstIndex = ((k_BlockIterator)ak_First).Index;
int li_Count = ak_Last - ak_First;
int li_LastCount = this.End - ak_Last;
if (li_FirstIndex < li_LastCount)
{
k_Algorithm.CopyBackward(this.Begin, ak_First, ak_Last);
k_Algorithm.Fill(this.Begin, ak_First, null);
mi_Offset += li_Count;
mi_Offset %= (mk_Blocks.Length * mi_BlockSize);
}
else
{
k_Algorithm.Copy(ak_Last, this.End, ak_First);
k_Algorithm.Fill(ak_Last, this.End, null);
}
mi_Count -= li_Count;
return new k_BlockIterator(this, li_FirstIndex);
}
// ISequence Members
public object Front
{
get { return this.Begin.Current; }
set { this.Begin.Current = value; }
}
public object Back
{
get { return (this.End-1).Current; }
set { (this.End-1).Current = value; }
}
public void PushFront(object ak_Value)
{
if (mi_Offset % mi_BlockSize == 0 // currently on block boundary
&& mk_Blocks.Length * mi_BlockSize - mi_Count < mi_BlockSize)
{
AllocateBlock(mi_BlockSize);
}
if (mi_Offset == 0)
mi_Offset = mk_Blocks.Length * mi_BlockSize;
--mi_Offset;
mk_Blocks[mi_Offset/mi_BlockSize][mi_Offset%mi_BlockSize] = ak_Value;
++mi_Count;
}
public void PopFront()
{
Erase(this.Begin);
}
public void PushBack(object ak_Value)
{
if ((mi_Offset+mi_Count) % mi_BlockSize == 0 // currently on block boundary
&& mk_Blocks.Length * mi_BlockSize - mi_Count < mi_BlockSize)
{
AllocateBlock(mi_BlockSize);
}
int li_Pos = mi_Offset + mi_Count;
int li_Block = li_Pos/mi_BlockSize;
if (li_Block >= mk_Blocks.Length)
li_Block -= mk_Blocks.Length;
mk_Blocks[li_Block][li_Pos%mi_BlockSize] = ak_Value;
++mi_Count;
}
public void PopBack()
{
Erase(this.End-1);
}
public void Assign(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd)
{
Clear();
Insert(this.End, ak_SrcBegin, ak_SrcEnd);
}
public void Assign(object ak_Value, int ai_Count)
{
Clear();
for (int i = 0; i < ai_Count; ++i)
Insert(this.End, ak_Value);
}
public void Insert(k_Iterator ak_Where, object ak_Value)
{
if (ak_Where == this.Begin)
PushFront(ak_Value);
else if (ak_Where == this.End)
PushBack(ak_Value);
else
{
int li_Index = ((k_BlockIterator)ak_Where).Index;
if (mk_Blocks.Length * mi_BlockSize - mi_Count < mi_BlockSize)
AllocateBlock(mi_BlockSize);
++mi_Count;
if (li_Index < mi_Count/2)
{
if (mi_Offset == 0)
mi_Offset = mk_Blocks.Length * mi_BlockSize;
--mi_Offset;
k_Iterator lk_Dest = k_Algorithm.Copy(this.Begin+1, this.Begin+li_Index+1, this.Begin);
lk_Dest.Current = ak_Value;
}
else
{
// count has been incremented - there is a free element at the end
k_Iterator lk_Dest = this.Begin + li_Index;
k_Algorithm.CopyBackward(lk_Dest, this.End - 1, this.End);
lk_Dest.Current = ak_Value;
}
}
}
public void Insert(k_Iterator ak_Where, k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd)
{
int li_FirstIndex = ((k_BlockIterator)ak_Where).Index;
int li_Count = ak_SrcEnd - ak_SrcBegin;
if (mk_Blocks.Length * mi_BlockSize <= mi_Count + li_Count + mi_BlockSize)
AllocateBlock(li_Count);
mi_Count += li_Count;
k_Iterator lk_Dest;
if (li_FirstIndex < li_Count/2)
{
if (mi_Offset == 0)
mi_Offset = mk_Blocks.Length * mi_BlockSize;
mi_Offset -= li_Count;
lk_Dest = k_Algorithm.Copy(this.Begin+li_Count, this.Begin+li_FirstIndex+li_Count, this.Begin);
}
else
{
// count has been incremented - there are li_Count free elements at the end
lk_Dest = this.Begin + li_FirstIndex;
k_Algorithm.CopyBackward(lk_Dest, this.End - li_Count, this.End);
}
k_Algorithm.Copy(ak_SrcBegin, ak_SrcEnd, lk_Dest);
}
#region IList Members
public int Add(object ak_Value)
{
PushBack(ak_Value);
return mi_Count;
}
public void Clear()
{
for (int i=0; i<mk_Blocks.Length; ++i)
mk_Blocks[i] = new object[mi_BlockSize];
mi_Count = 0;
mi_Offset = 0;
}
public bool Contains(object ak_Value)
{
return (Find(ak_Value) != this.End);
}
public int IndexOf(object ak_Value)
{
k_Iterator lk_Found = Find(ak_Value);
if (lk_Found == this.End)
return -1;
return ((k_BlockIterator)lk_Found).Index;
}
public void Insert(int ai_Index, object ak_Value)
{
Insert(this.Begin + ai_Index, ak_Value);
}
public void Remove(object ak_Value)
{
Erase(Find(ak_Value));
}
public void RemoveAt(int ai_Index)
{
Erase(this.Begin + ai_Index);
}
public bool IsReadOnly
{
get { return false; }
}
public bool IsFixedSize
{
get { return false; }
}
public object this[int ai_Index]
{
get
{
if (ai_Index >= mi_Count || ai_Index < 0)
throw new ArgumentOutOfRangeException("Position out of boundary");
int li_Pos, li_Block = CalcBlockAndPos(ai_Index, out li_Pos);
return mk_Blocks[li_Block][li_Pos];
}
set
{
if (ai_Index >= mi_Count || ai_Index < 0)
throw new ArgumentOutOfRangeException("Position out of boundary");
int li_Pos, li_Block = CalcBlockAndPos(ai_Index, out li_Pos);
mk_Blocks[li_Block][li_Pos] = value;
}
}
#endregion
#region ICollection Members
public void CopyTo(Array ak_Array, int ai_Index)
{
for (k_Iterator lk_Iter = this.Begin.Clone(); lk_Iter != this.End; lk_Iter.Next())
ak_Array.SetValue(lk_Iter.Current, ai_Index++);
}
public int Count
{
get { return mi_Count; }
}
public bool IsSynchronized
{
get { return false; }
}
public object SyncRoot
{
get { return this; }
}
#endregion
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
return new k_IteratorEnumerator(this.Begin, this.End);
}
#endregion
#region ICloneable Members
public object Clone()
{
k_Deque lk_Clone = new k_Deque(this.Count);
lk_Clone.Insert(lk_Clone.End, this.Begin, this.End);
return lk_Clone;
}
#endregion
private void AllocateBlock(int ai_MinElements)
{
// number of new blocks - grow by half block count (150%)
int li_Increment = mk_Blocks.Length / 2;
if (ai_MinElements > li_Increment*mi_BlockSize)
li_Increment = (ai_MinElements + mi_BlockSize - 1)/mi_BlockSize;
object[][] lk_NewBlocks = new object[mk_Blocks.Length + li_Increment][];
// first move all blocks after offset to front
int li_StartBlock = mi_Offset / mi_BlockSize;
int li_BackCount = mk_Blocks.Length - li_StartBlock;
Array.Copy(mk_Blocks, li_StartBlock, lk_NewBlocks, 0, li_BackCount);
int li_TotalOld = li_BackCount;
// second move all blocks before offset to end
int li_FrontCount = (mi_Offset + mi_Count + mi_BlockSize - 1) / mi_BlockSize - mk_Blocks.Length;
if (li_FrontCount > 0)
{
Array.Copy(mk_Blocks, 0, lk_NewBlocks, li_BackCount, li_FrontCount);
li_TotalOld += li_FrontCount;
}
// actually create new empty blocks
for (int i=li_TotalOld; i < li_TotalOld+li_Increment; ++i)
lk_NewBlocks[i] = new object[mi_BlockSize];
mk_Blocks = lk_NewBlocks;
mi_Offset %= mi_BlockSize;
}
private int CalcBlockAndPos(int ai_Index, out int ai_Pos)
{
ai_Pos = mi_Offset + ai_Index;
int li_BlockIndex = ai_Pos / mi_BlockSize;
if (li_BlockIndex >= mk_Blocks.Length)
li_BlockIndex -= mk_Blocks.Length;
ai_Pos %= mi_BlockSize;
return li_BlockIndex;
}
}
}