1
0
Эх сурвалжийг харах

Use C# 8.0 in AsyncEnumerableHelpers.

Bart De Smet 6 жил өмнө
parent
commit
b1e58d2148

+ 61 - 4
Ix.NET/Source/System.Linq.Async/System/Linq/AsyncEnumerableHelpers.cs

@@ -44,6 +44,55 @@ namespace System.Collections.Generic
             }
             else
             {
+#if CSHARP8
+                await using (var en = source.GetAsyncEnumerator(cancellationToken).ConfigureAwait(false))
+                {
+                    if (await en.MoveNextAsync())
+                    {
+                        const int DefaultCapacity = 4;
+                        var arr = new T[DefaultCapacity];
+                        arr[0] = en.Current;
+                        var count = 1;
+
+                        while (await en.MoveNextAsync())
+                        {
+                            if (count == arr.Length)
+                            {
+                                // MaxArrayLength is defined in Array.MaxArrayLength and in gchelpers in CoreCLR.
+                                // It represents the maximum number of elements that can be in an array where
+                                // the size of the element is greater than one byte; a separate, slightly larger constant,
+                                // is used when the size of the element is one.
+                                const int MaxArrayLength = 0x7FEFFFFF;
+
+                                // This is the same growth logic as in List<T>:
+                                // If the array is currently empty, we make it a default size.  Otherwise, we attempt to 
+                                // double the size of the array.  Doubling will overflow once the size of the array reaches
+                                // 2^30, since doubling to 2^31 is 1 larger than Int32.MaxValue.  In that case, we instead 
+                                // constrain the length to be MaxArrayLength (this overflow check works because of the 
+                                // cast to uint).  Because a slightly larger constant is used when T is one byte in size, we 
+                                // could then end up in a situation where arr.Length is MaxArrayLength or slightly larger, such 
+                                // that we constrain newLength to be MaxArrayLength but the needed number of elements is actually 
+                                // larger than that.  For that case, we then ensure that the newLength is large enough to hold 
+                                // the desired capacity.  This does mean that in the very rare case where we've grown to such a 
+                                // large size, each new element added after MaxArrayLength will end up doing a resize.
+                                var newLength = count << 1;
+                                if ((uint)newLength > MaxArrayLength)
+                                {
+                                    newLength = MaxArrayLength <= count ? count + 1 : MaxArrayLength;
+                                }
+
+                                Array.Resize(ref arr, newLength);
+                            }
+
+                            arr[count++] = en.Current;
+                        }
+
+                        result.Length = count;
+                        result.Array = arr;
+                        return result;
+                    }
+                }
+#else
                 var en = source.GetAsyncEnumerator(cancellationToken);
 
                 try
@@ -97,6 +146,7 @@ namespace System.Collections.Generic
                 {
                     await en.DisposeAsync().ConfigureAwait(false);
                 }
+#endif
             }
 
             result.Length = 0;
@@ -110,23 +160,30 @@ namespace System.Collections.Generic
 
         internal static async Task<Set<T>> ToSet<T>(IAsyncEnumerable<T> source, IEqualityComparer<T> comparer, CancellationToken cancellationToken)
         {
+            var set = new Set<T>(comparer);
+
+#if CSHARP8 && AETOR_HAS_CT // CS0656 Missing compiler required member 'System.Collections.Generic.IAsyncEnumerable`1.GetAsyncEnumerator'
+            await foreach (T item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
+            {
+                set.Add(item);
+            }
+#else
             var e = source.GetAsyncEnumerator(cancellationToken);
 
             try
             {
-                var set = new Set<T>(comparer);
-
                 while (await e.MoveNextAsync().ConfigureAwait(false))
                 {
                     set.Add(e.Current);
                 }
-
-                return set;
             }
             finally
             {
                 await e.DisposeAsync().ConfigureAwait(false);
             }
+#endif
+
+            return set;
         }
 
         internal struct ArrayWithLength<T>