|
@@ -44,6 +44,55 @@ namespace System.Collections.Generic
|
|
}
|
|
}
|
|
else
|
|
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);
|
|
var en = source.GetAsyncEnumerator(cancellationToken);
|
|
|
|
|
|
try
|
|
try
|
|
@@ -97,6 +146,7 @@ namespace System.Collections.Generic
|
|
{
|
|
{
|
|
await en.DisposeAsync().ConfigureAwait(false);
|
|
await en.DisposeAsync().ConfigureAwait(false);
|
|
}
|
|
}
|
|
|
|
+#endif
|
|
}
|
|
}
|
|
|
|
|
|
result.Length = 0;
|
|
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)
|
|
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);
|
|
var e = source.GetAsyncEnumerator(cancellationToken);
|
|
|
|
|
|
try
|
|
try
|
|
{
|
|
{
|
|
- var set = new Set<T>(comparer);
|
|
|
|
-
|
|
|
|
while (await e.MoveNextAsync().ConfigureAwait(false))
|
|
while (await e.MoveNextAsync().ConfigureAwait(false))
|
|
{
|
|
{
|
|
set.Add(e.Current);
|
|
set.Add(e.Current);
|
|
}
|
|
}
|
|
-
|
|
|
|
- return set;
|
|
|
|
}
|
|
}
|
|
finally
|
|
finally
|
|
{
|
|
{
|
|
await e.DisposeAsync().ConfigureAwait(false);
|
|
await e.DisposeAsync().ConfigureAwait(false);
|
|
}
|
|
}
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ return set;
|
|
}
|
|
}
|
|
|
|
|
|
internal struct ArrayWithLength<T>
|
|
internal struct ArrayWithLength<T>
|