Remove unnecessary _version++ from a few places (#82500)
authorStephen Toub <stoub@microsoft.com>
Thu, 23 Feb 2023 22:03:01 +0000 (17:03 -0500)
committerGitHub <noreply@github.com>
Thu, 23 Feb 2023 22:03:01 +0000 (17:03 -0500)
* Remove unnecessarion _version++ from a few places

In some collection types, resizing the backing store can affect in-flight enumerations, e.g. growing a queue will cause the implementation to relayout the elements contiguously from the beginning, which will invalidate indices stored in enumerators.  But for `List<T>` and `Stack<T>`, changing the backing array doesn't impact the index stored in an enumerator, nor does it impact what the enumerator will enumerate, so these operations needn't invalidate the enumerators.  `List<T>`'s `set_Capacity` and `TrimExcess` already didn't update the version, but its `EnsureCapacity` did, and `Stack<T>`'s `TrimExcess` and `EnsureCapacity` both updated the version.  This change just removes those unnecessary increments.

* Add a Stack.TrimExcess test

src/libraries/System.Collections/src/System/Collections/Generic/Stack.cs
src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.EnsureCapacity.cs
src/libraries/System.Collections/tests/Generic/Stack/Stack.Generic.Tests.cs
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs

index 181a619..ae5cc7b 100644 (file)
@@ -174,7 +174,6 @@ namespace System.Collections.Generic
             if (_size < threshold)
             {
                 Array.Resize(ref _array, _size);
-                _version++;
             }
         }
 
@@ -296,7 +295,6 @@ namespace System.Collections.Generic
             if (_array.Length < capacity)
             {
                 Grow(capacity);
-                _version++;
             }
 
             return _array.Length;
index cfbd15a..ce2956a 100644 (file)
@@ -13,7 +13,7 @@ namespace System.Collections.Tests
     {
         [Theory]
         [MemberData(nameof(ValidCollectionSizes))]
-        public void EnsureCapacity_RequestingLargerCapacity_DoesInvalidateEnumeration(int count)
+        public void EnsureCapacity_RequestingLargerCapacity_DoesNotInvalidateEnumeration(int count)
         {
             List<T> list = GenericListFactory(count);
             IEnumerator<T> copiedListEnumerator = new List<T>(list).GetEnumerator();
@@ -22,7 +22,7 @@ namespace System.Collections.Tests
 
             list.EnsureCapacity(capacity + 1);
 
-            Assert.Throws<InvalidOperationException>(() => enumerator.MoveNext());
+            enumerator.MoveNext();
         }
 
         [Fact]
index 6553220..1edc037 100644 (file)
@@ -239,6 +239,17 @@ namespace System.Collections.Tests
             }
         }
 
+        [Fact]
+        public void Stack_Generic_TrimExcess_DoesNotInvalidateEnumeration()
+        {
+            Stack<T> stack = GenericStackFactory(10);
+            stack.EnsureCapacity(100);
+
+            IEnumerator<T> enumerator = stack.GetEnumerator();
+            stack.TrimExcess();
+            enumerator.MoveNext();
+        }
+
         #endregion
 
         [Theory]
@@ -289,7 +300,7 @@ namespace System.Collections.Tests
 
         [Theory]
         [MemberData(nameof(ValidCollectionSizes))]
-        public void Stack_Generic_EnsureCapacity_RequestingLargerCapacity_DoesInvalidateEnumeration(int count)
+        public void Stack_Generic_EnsureCapacity_RequestingLargerCapacity_DoesNotInvalidateEnumeration(int count)
         {
             Stack<T> stack = GenericStackFactory(count);
             IEnumerator<T> copiedEnumerator = new List<T>(stack).GetEnumerator();
@@ -297,7 +308,7 @@ namespace System.Collections.Tests
 
             stack.EnsureCapacity(count + 1);
 
-            Assert.Throws<InvalidOperationException>(() => enumerator.MoveNext());
+            enumerator.MoveNext();
         }
 
         [Fact]
index 5e358bc..1cfe6a6 100644 (file)
@@ -439,7 +439,6 @@ namespace System.Collections.Generic
             if (_items.Length < capacity)
             {
                 Grow(capacity);
-                _version++;
             }
 
             return _items.Length;