diff --git a/Source/Collections/Deque.Insertion.cs b/Source/Collections/Deque.Insertion.cs index ed50529..94db355 100644 --- a/Source/Collections/Deque.Insertion.cs +++ b/Source/Collections/Deque.Insertion.cs @@ -38,6 +38,9 @@ namespace Nuclex.Support.Collections { this.blocks[0][this.firstBlockStartIndex] = item; ++this.count; +#if DEBUG + ++this.version; +#endif } /// Appends an item to the end of the double-ended queue @@ -52,6 +55,9 @@ namespace Nuclex.Support.Collections { this.blocks[this.blocks.Count - 1][this.lastBlockEndIndex - 1] = item; ++this.count; +#if DEBUG + ++this.version; +#endif } /// Inserts the item at the specified index @@ -64,6 +70,9 @@ namespace Nuclex.Support.Collections { } else { // Nope, we're closer to the right end shiftRightAndInsert(index, item); } +#if DEBUG + ++this.version; +#endif } /// diff --git a/Source/Collections/Deque.Removal.cs b/Source/Collections/Deque.Removal.cs index 72b53c2..d5b414e 100644 --- a/Source/Collections/Deque.Removal.cs +++ b/Source/Collections/Deque.Removal.cs @@ -54,6 +54,9 @@ namespace Nuclex.Support.Collections { this.firstBlockStartIndex = 0; this.lastBlockEndIndex = 0; this.count = 0; +#if DEBUG + ++this.version; +#endif } /// Removes the specified item from the deque @@ -66,6 +69,9 @@ namespace Nuclex.Support.Collections { } RemoveAt(index); +#if DEBUG + ++this.version; +#endif return true; } @@ -92,6 +98,9 @@ namespace Nuclex.Support.Collections { } } --this.count; +#if DEBUG + ++this.version; +#endif } /// Removes the last item in the double-ended queue @@ -118,6 +127,9 @@ namespace Nuclex.Support.Collections { } } --this.count; +#if DEBUG + ++this.version; +#endif } /// Removes the item at the specified index @@ -129,6 +141,9 @@ namespace Nuclex.Support.Collections { } else { // Nope, we're closer to the right end removeFromRight(index); } +#if DEBUG + ++this.version; +#endif } /// diff --git a/Source/Collections/Deque.Test.cs b/Source/Collections/Deque.Test.cs index 96561d4..7be1d19 100644 --- a/Source/Collections/Deque.Test.cs +++ b/Source/Collections/Deque.Test.cs @@ -93,7 +93,6 @@ namespace Nuclex.Support.Collections { } } - /// Verifies that the Insert() method works in all cases /// /// We have several different cases here that will be tested. The deque can @@ -655,6 +654,23 @@ namespace Nuclex.Support.Collections { delegate() { intDeque.CopyTo(new int[7], 0); } ); } + +#if DEBUG + /// + /// Tests whether the deque enumerator detects when it runs out of sync + /// + [Test] + public void TestInvalidatedEnumeratorDetection() { + Deque intDeque = createDeque(8); + using(IEnumerator enumerator = intDeque.GetEnumerator()) { + Assert.IsTrue(enumerator.MoveNext()); + intDeque.AddFirst(12345); + Assert.Throws( + delegate() { enumerator.MoveNext(); } + ); + } + } +#endif /// /// Creates a deque whose first element does not coincide with a block boundary diff --git a/Source/Collections/Deque.cs b/Source/Collections/Deque.cs index 24a35cb..14286a9 100644 --- a/Source/Collections/Deque.cs +++ b/Source/Collections/Deque.cs @@ -65,6 +65,9 @@ namespace Nuclex.Support.Collections { /// The item at the enumerator's current position public ItemType Current { get { +#if DEBUG + checkVersion(); +#endif if(this.currentBlock == null) { throw new InvalidOperationException("Enumerator is not on a valid position"); } @@ -77,6 +80,10 @@ namespace Nuclex.Support.Collections { /// True if there was a next item public bool MoveNext() { +#if DEBUG + checkVersion(); +#endif + // If we haven't reached the last block yet if(this.currentBlockIndex < this.lastBlock) { @@ -117,6 +124,7 @@ namespace Nuclex.Support.Collections { this.currentBlock = null; this.currentBlockIndex = -1; this.subIndex = this.deque.blockSize - 1; + this.expectedVersion = this.deque.version; } /// The item at the enumerator's current position @@ -124,6 +132,14 @@ namespace Nuclex.Support.Collections { get { return Current; } } +#if DEBUG + /// Ensures that the deque has not changed + private void checkVersion() { + if(this.expectedVersion != this.deque.version) + throw new InvalidOperationException("Deque has been modified"); + } +#endif + /// Deque the enumerator belongs to private Deque deque; /// Size of the blocks in the deque @@ -140,6 +156,9 @@ namespace Nuclex.Support.Collections { /// Index in the current block private int subIndex; + /// Version the deque is expected to have + private int expectedVersion; + } #endregion // class Enumerator @@ -303,6 +322,10 @@ namespace Nuclex.Support.Collections { private int firstBlockStartIndex; /// End index of data in the last block private int lastBlockEndIndex; +#if DEBUG + /// Used to detect when enumerators go out of sync + private int version; +#endif } diff --git a/Source/Collections/PriorityQueue.cs b/Source/Collections/PriorityQueue.cs index 230f3b7..cbb8fe1 100644 --- a/Source/Collections/PriorityQueue.cs +++ b/Source/Collections/PriorityQueue.cs @@ -43,7 +43,7 @@ namespace Nuclex.Support.Collections { public void Reset() { this.index = -1; #if DEBUG - this.expectedVersion = priorityQueue.version; + this.expectedVersion = this.priorityQueue.version; #endif }