using System; using System.Collections.Generic; using System.Collections; namespace Nuclex.Support.Collections { #if false /// A double-ended queue that allocates memory in blocks /// Type of the items being stored in the queue /// /// /// The double-ended queue allows items to be appended to either side of the queue /// without a hefty toll on performance. Like its namesake in C++, it is implemented /// using multiple arrays. /// /// /// Therefore, it's not only good at coping with lists that are modified at their /// beginning, but also at handling huge data sets since enlarging the deque doesn't /// require items to be copied around and still can be accessed by index. /// /// public class Deque /*: IList, IList*/ { /// Initializes a new deque public Deque() : this(512) { } /// Initializes a new deque using the specified block size /// Size of the individual memory blocks used public Deque(int blockSize) { this.blockSize = blockSize; this.blocks = new List(); this.blocks.Add(new ItemType[this.blockSize]); } /// Number of items contained in the double ended queue public int Count { get { return this.count; } } /// Accesses an item by its index /// Index of the item that will be accessed /// The item at the specified index public ItemType this[int index] { get { int blockIndex, subIndex; findIndex(index, out blockIndex, out subIndex); return this.blocks[blockIndex][subIndex]; } set { int blockIndex, subIndex; findIndex(index, out blockIndex, out subIndex); this.blocks[blockIndex][subIndex] = value; } } /// The first item in the double-ended queue public ItemType First { get { if(this.lastBlockEndIndex <= this.firstBlockStartIndex) { throw new InvalidOperationException("The deque is empty"); } return this.blocks[0][this.firstBlockStartIndex]; } } /// The last item in the double-ended queue public ItemType Last { get { if(this.lastBlockEndIndex <= this.firstBlockStartIndex) { throw new InvalidOperationException("The deque is empty"); } return this.blocks[this.blocks.Count - 1][this.lastBlockEndIndex - 1]; } } /// Removes the first item in the double-ended queue public void RemoveFirst() { if(this.count == 0) { throw new InvalidOperationException("Cannot remove items from empty deque"); } ++this.firstBlockStartIndex; if(this.firstBlockStartIndex >= this.blockSize) { // Block became empty if(this.count > 1) { // Still more blocks in queue, remove block this.blocks.RemoveAt(0); this.firstBlockStartIndex = 0; } else { // Last block - do not remove this.firstBlockStartIndex = 0; this.lastBlockEndIndex = 0; } } --this.count; } /// Removes the last item in the double-ended queue public void RemoveLast() { if(this.count == 0) { throw new InvalidOperationException("Cannot remove items from empty deque"); } --this.lastBlockEndIndex; if(this.lastBlockEndIndex == 0) { // Block became empty if(this.count > 1) { this.blocks.RemoveAt(this.blocks.Count - 1); this.lastBlockEndIndex = this.blockSize; } else { // Last block - do not remove this.firstBlockStartIndex = 0; this.lastBlockEndIndex = 0; } } --this.count; } /// Inserts an item at the beginning of the double-ended queue /// Item that will be inserted into the queue public void AddFirst(ItemType item) { if(this.firstBlockStartIndex > 0) { --this.firstBlockStartIndex; } else { // Need to allocate a new block this.blocks.Insert(0, new ItemType[this.blockSize]); this.firstBlockStartIndex = this.blockSize - 1; } this.blocks[0][this.firstBlockStartIndex] = item; ++this.count; } /// Appends an item to the end of the double-ended queue /// Item that will be appended to the queue public void AddLast(ItemType item) { if(this.lastBlockEndIndex < this.blockSize) { ++this.lastBlockEndIndex; } else { // Need to allocate a new block this.blocks.Add(new ItemType[this.blockSize]); this.lastBlockEndIndex = 1; } this.blocks[this.blocks.Count - 1][this.lastBlockEndIndex - 1] = item; ++this.count; } public void Insert(int index, ItemType item) { if(index == this.count) { AddLast(item); } else { int blockIndex, subIndex; findIndex(index, out blockIndex, out subIndex); //for(int block = this.blocks.Count - 1; block > } } // http://www.codeproject.com/KB/dotnet/ccnetsandcastle.aspx /* public int IndexOf(ItemType item) { switch(this.blocks.Count) { // No block exist, so the item cannot be found case 0: { return -1; } // Only one block exists, start index and end index apply to the same block case 1: { int count = this.lastBlockEndIndex - this.firstBlockStartIndex; int index = Array.IndexOf( this.blocks[0], item, this.firstBlockStartIndex, count ); // If we found something, we need to adjust its index so the first item in // the deque always appears at index 0 to the user if(index != -1) { return (index - this.firstBlockStartIndex); } else { return -1; } } // Two blocks exist, start index is in first block, end index in second block case 2: { // Scan the first block for the item and if found, return the index int count = this.blockSize - this.firstBlockStartIndex; int index = Array.IndexOf( this.blocks[0], item, this.firstBlockStartIndex, this.blockSize ); // If we found something, we need to adjust its index if(index != -1) { return (index - this.firstBlockStartIndex); } // Nothing found, continue the search in the index = Array.IndexOf( this.blocks[1], item, 0, this.lastBlockEndIndex ); if(index == -1) { return -1; } else { return (index - this.firstBlockStartIndex + this.blockSize); } } default: { int count = this.blockSize - this.firstBlockStartIndex; int index = Array.IndexOf( this.blocks[0], item, this.firstBlockStartIndex, this.blockSize ); return -1; } } } */ /// Calculates the block index and local sub index of an entry /// Index of the entry that will be located /// Index of the block the entry is contained in /// Local sub index of the entry within the block private void findIndex(int index, out int blockIndex, out int subIndex) { if((index < 0) || (index >= this.count)) { throw new ArgumentOutOfRangeException("Index out of range", "index"); } index += this.firstBlockStartIndex; blockIndex = Math.DivRem(index, this.blockSize, out subIndex); } /// Number if items currently stored in the deque private int count; /// Size of a single deque block private int blockSize; /// Memory blocks being used to store the deque's data private List blocks; /// Starting index of data in the first block private int firstBlockStartIndex; /// End index of data in the last block private int lastBlockEndIndex; } #endif } // namespace Nuclex.Support.Collections