// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace System.Linq
{
public static partial class AsyncEnumerable
{
///
/// Returns the maximum element in an async-enumerable sequence.
///
/// The type of the elements in the source sequence.
/// An async-enumerable sequence to determine the maximum element of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum element in the source sequence.
/// is null.
/// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
if (default(TSource)! == null) // NB: Null value is desired; JIT-time check.
{
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
var comparer = Comparer.Default;
TSource value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
do
{
if (!await e.MoveNextAsync())
{
return default!;
}
value = e.Current;
}
while (value == null);
while (await e.MoveNextAsync())
{
var x = e.Current;
if (x != null && comparer.Compare(x, value) > 0)
{
value = x;
}
}
}
return value;
}
}
else
{
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
var comparer = Comparer.Default;
TSource value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = e.Current;
while (await e.MoveNextAsync())
{
var x = e.Current;
if (comparer.Compare(x, value) > 0)
{
value = x;
}
}
}
return value;
}
}
}
///
/// Invokes a transform function on each element of a sequence and returns the maximum value.
///
/// The type of the elements in the source sequence.
/// The type of the objects derived from the elements in the source sequence to determine the maximum of.
/// An async-enumerable sequence to determine the minimum element of.
/// A transform function to apply to each element.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the value that corresponds to the maximum element in the source sequence.
/// or is null.
/// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
public static ValueTask MaxAsync(this IAsyncEnumerable source, Func selector, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
if (selector == null)
throw Error.ArgumentNull(nameof(selector));
if (default(TResult)! == null) // NB: Null value is desired; JIT-time check.
{
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
var comparer = Comparer.Default;
TResult value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
do
{
if (!await e.MoveNextAsync())
{
return default!;
}
value = selector(e.Current);
}
while (value == null);
while (await e.MoveNextAsync())
{
var x = selector(e.Current);
if (x != null && comparer.Compare(x, value) > 0)
{
value = x;
}
}
}
return value;
}
}
else
{
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
var comparer = Comparer.Default;
TResult value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = selector(e.Current);
while (await e.MoveNextAsync())
{
var x = selector(e.Current);
if (comparer.Compare(x, value) > 0)
{
value = x;
}
}
}
return value;
}
}
}
internal static ValueTask MaxAwaitAsyncCore(this IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
if (selector == null)
throw Error.ArgumentNull(nameof(selector));
if (default(TResult)! == null) // NB: Null value is desired; JIT-time check.
{
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
var comparer = Comparer.Default;
TResult value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
do
{
if (!await e.MoveNextAsync())
{
return default!;
}
value = await selector(e.Current).ConfigureAwait(false);
}
while (value == null);
while (await e.MoveNextAsync())
{
var x = await selector(e.Current).ConfigureAwait(false);
if (x != null && comparer.Compare(x, value) > 0)
{
value = x;
}
}
}
return value;
}
}
else
{
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
var comparer = Comparer.Default;
TResult value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = await selector(e.Current).ConfigureAwait(false);
while (await e.MoveNextAsync())
{
var x = await selector(e.Current).ConfigureAwait(false);
if (comparer.Compare(x, value) > 0)
{
value = x;
}
}
}
return value;
}
}
}
#if !NO_DEEP_CANCELLATION
internal static ValueTask MaxAwaitWithCancellationAsyncCore(this IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
if (selector == null)
throw Error.ArgumentNull(nameof(selector));
if (default(TResult)! == null) // NB: Null value is desired; JIT-time check.
{
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
var comparer = Comparer.Default;
TResult value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
do
{
if (!await e.MoveNextAsync())
{
return default!;
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
}
while (value == null);
while (await e.MoveNextAsync())
{
var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
if (x != null && comparer.Compare(x, value) > 0)
{
value = x;
}
}
}
return value;
}
}
else
{
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
var comparer = Comparer.Default;
TResult value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
while (await e.MoveNextAsync())
{
var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
if (comparer.Compare(x, value) > 0)
{
value = x;
}
}
}
return value;
}
}
}
#endif
}
}