Example #1
0
        /// <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);