using System; using System.Collections; namespace System.util.collections { /// /// Circular buffer of arrays /// 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) 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= 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; } } }