Skip null entries when enumerating DeviceCollection
authorFraser Waters <frassle@gmail.com>
Thu, 5 Oct 2017 21:47:08 +0000 (22:47 +0100)
committerFraser Waters <frassle@gmail.com>
Thu, 5 Oct 2017 22:00:57 +0000 (23:00 +0100)
Fixes #656.

DeviceCollection used the underlying List<T>'s enumerator. But we replace
entries in the list with nulls to save memory movement. This commit adds a
custom enumerator that skips nulls in the list.

src/OpenTK/Platform/DeviceCollection.cs

index 76bada0..6a48994 100644 (file)
@@ -25,6 +25,7 @@
 // THE SOFTWARE.
 //
 
+using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
 
@@ -38,23 +39,70 @@ namespace OpenTK.Platform
     //        that is added.
     internal class DeviceCollection<T> : IEnumerable<T>
     {
+        internal struct Enumerator : IEnumerator<T>
+        {
+            private int Index;
+            private DeviceCollection<T> Collection;
+
+            internal Enumerator(DeviceCollection<T> collection)
+            {
+                Collection = collection;
+                Index = -1;
+                Current = default(T);
+            }
+
+            public T Current { get; private set; }
+
+            object IEnumerator.Current
+            {
+                get
+                {
+                    return Current;
+                }
+            }
+
+            public void Dispose()
+            {
+            }
+
+            public bool MoveNext()
+            {
+                do
+                {
+                    ++Index;
+                    if (Index < Collection.Devices.Count)
+                    {
+                        Current = Collection.Devices[Index];
+                    }
+                } while (Index < Collection.Devices.Count && Collection.Devices[Index] == null);
+
+                return Index < Collection.Devices.Count;
+            }
+
+            public void Reset()
+            {
+                Index = -1;
+                Current = default(T);
+            }
+        }
+
         private readonly Dictionary<long, int> Map = new Dictionary<long, int>();
         private readonly List<T> Devices = new List<T>();
 
         IEnumerator<T> IEnumerable<T>.GetEnumerator()
         {
-            return Devices.GetEnumerator();
+            return new Enumerator(this);
         }
 
-        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+        IEnumerator IEnumerable.GetEnumerator()
         {
-            return GetEnumerator();
+            return new Enumerator(this);
         }
 
         // This avoids boxing when using foreach loops
-        public List<T>.Enumerator GetEnumerator()
+        public Enumerator GetEnumerator()
         {
-            return Devices.GetEnumerator();
+            return new Enumerator(this);
         }
 
         public T this[int index]