/// <summary> /// Creates a new <see cref="IAsyncReadOnlyCollection{T}" /> that contains the sorted elements of the /// <see cref="IAsyncEnumerable{T}" />. /// </summary> /// <param name="source"> /// The <see cref="IAsyncEnumerable{T}" /> to sort. /// </param> /// <param name="comparison"> /// The comparison to use while sorting. /// </param> /// <typeparam name="T"> /// The type of the items. /// </typeparam> /// <returns> /// The sorted <see cref="IAsyncReadOnlyCollection{T}" />. /// </returns> public async Task <IAsyncReadOnlyCollection <T> > SortAsync <T>(IAsyncEnumerable <T> source, Comparison <T> comparison) { var chunks = new List <IAsyncReadOnlyCollection <T> >(); if (source.Policy != this) { source = await this.MaterializeAsync(source).ConfigureAwait(false); } await source.Batch(this.MaximumChunkSize).ForEachAsync( async batch => { var builder = await this.CreateBuilder <T>().AddAsync(await this.memPolicy.SortAsync(batch, comparison).ConfigureAwait(false)); chunks.Add(await builder.BuildAsync().ConfigureAwait(false)); }); var result = this.CreateBuilder <T>(); var enumerators = chunks.Select(c => c.GetAsyncEnumerator()).ToList(); foreach (var enumerator in enumerators.ToArray()) { if (!enumerator.MoveNext() && !(await enumerator.NextBatchAsync().ConfigureAwait(false) && enumerator.MoveNext())) { enumerator.Dispose(); enumerators.Remove(enumerator); } } enumerators.Sort((a, b) => comparison(a.Current, b.Current)); while (true) { await result.AddAsync(TemporaryFilePolicy.TakeItems(enumerators, comparison)).ConfigureAwait(false); if (!(await enumerators[0].NextBatchAsync().ConfigureAwait(false) && enumerators[0].MoveNext())) { enumerators[0].Dispose(); enumerators.RemoveAt(0); if (enumerators.Count == 0) { break; } } else { TemporaryFilePolicy.SortEnumerators(enumerators, comparison); } } foreach (var chunk in chunks) { chunk.Dispose(); } return(await result.BuildAsync().ConfigureAwait(false)); }
public static ValueTask Batch <T>(this IAsyncEnumerable <T> source, Func <T, ValueTask> action) => source.Batch(0, action);