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
}