// 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
{
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
int 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
int 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
int 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
int 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
int? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = e.Current;
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
if (valueVal >= 0)
{
// We can fast-path this case where we know HasValue will
// never affect the outcome, without constantly checking
// if we're in such a state. Similar fast-paths could
// be done for other cases, but as all-positive or mostly-
// positive integer values are quite common in real-world
// uses, it's only been done for int? and long?.
while (await e.MoveNextAsync())
{
var cur = e.Current;
var x = cur.GetValueOrDefault();
if (x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
else
{
while (await e.MoveNextAsync())
{
var cur = e.Current;
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
int? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = selector(e.Current);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
if (valueVal >= 0)
{
// We can fast-path this case where we know HasValue will
// never affect the outcome, without constantly checking
// if we're in such a state. Similar fast-paths could
// be done for other cases, but as all-positive or mostly-
// positive integer values are quite common in real-world
// uses, it's only been done for int? and long?.
while (await e.MoveNextAsync())
{
var cur = selector(e.Current);
var x = cur.GetValueOrDefault();
if (x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
else
{
while (await e.MoveNextAsync())
{
var cur = selector(e.Current);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
int? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
if (valueVal >= 0)
{
// We can fast-path this case where we know HasValue will
// never affect the outcome, without constantly checking
// if we're in such a state. Similar fast-paths could
// be done for other cases, but as all-positive or mostly-
// positive integer values are quite common in real-world
// uses, it's only been done for int? and long?.
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
if (x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
else
{
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
int? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
if (valueVal >= 0)
{
// We can fast-path this case where we know HasValue will
// never affect the outcome, without constantly checking
// if we're in such a state. Similar fast-paths could
// be done for other cases, but as all-positive or mostly-
// positive integer values are quite common in real-world
// uses, it's only been done for int? and long?.
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current, cancellationToken).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
if (x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
else
{
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current, cancellationToken).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
long 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
long 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
long 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
long 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
long? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = e.Current;
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
if (valueVal >= 0)
{
// We can fast-path this case where we know HasValue will
// never affect the outcome, without constantly checking
// if we're in such a state. Similar fast-paths could
// be done for other cases, but as all-positive or mostly-
// positive integer values are quite common in real-world
// uses, it's only been done for int? and long?.
while (await e.MoveNextAsync())
{
var cur = e.Current;
var x = cur.GetValueOrDefault();
if (x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
else
{
while (await e.MoveNextAsync())
{
var cur = e.Current;
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
long? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = selector(e.Current);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
if (valueVal >= 0)
{
// We can fast-path this case where we know HasValue will
// never affect the outcome, without constantly checking
// if we're in such a state. Similar fast-paths could
// be done for other cases, but as all-positive or mostly-
// positive integer values are quite common in real-world
// uses, it's only been done for int? and long?.
while (await e.MoveNextAsync())
{
var cur = selector(e.Current);
var x = cur.GetValueOrDefault();
if (x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
else
{
while (await e.MoveNextAsync())
{
var cur = selector(e.Current);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
long? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
if (valueVal >= 0)
{
// We can fast-path this case where we know HasValue will
// never affect the outcome, without constantly checking
// if we're in such a state. Similar fast-paths could
// be done for other cases, but as all-positive or mostly-
// positive integer values are quite common in real-world
// uses, it's only been done for int? and long?.
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
if (x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
else
{
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
long? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
if (valueVal >= 0)
{
// We can fast-path this case where we know HasValue will
// never affect the outcome, without constantly checking
// if we're in such a state. Similar fast-paths could
// be done for other cases, but as all-positive or mostly-
// positive integer values are quite common in real-world
// uses, it's only been done for int? and long?.
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current, cancellationToken).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
if (x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
else
{
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current, cancellationToken).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
float value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = e.Current;
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (float.IsNaN(value))
{
if (!await e.MoveNextAsync())
{
return value;
}
value = e.Current;
}
while (await e.MoveNextAsync())
{
var x = e.Current;
if (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
float value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = selector(e.Current);
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (float.IsNaN(value))
{
if (!await e.MoveNextAsync())
{
return value;
}
value = selector(e.Current);
}
while (await e.MoveNextAsync())
{
var x = selector(e.Current);
if (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
float value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = await selector(e.Current).ConfigureAwait(false);
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (float.IsNaN(value))
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current).ConfigureAwait(false);
}
while (await e.MoveNextAsync())
{
var x = await selector(e.Current).ConfigureAwait(false);
if (x > value)
{
value = x;
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
float value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (float.IsNaN(value))
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
}
while (await e.MoveNextAsync())
{
var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
if (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
float? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = e.Current;
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (float.IsNaN(valueVal))
{
if (!await e.MoveNextAsync())
{
return value;
}
var cur = e.Current;
if (cur.HasValue)
{
valueVal = (value = cur).GetValueOrDefault();
}
}
while (await e.MoveNextAsync())
{
var cur = e.Current;
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
float? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = selector(e.Current);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (float.IsNaN(valueVal))
{
if (!await e.MoveNextAsync())
{
return value;
}
var cur = selector(e.Current);
if (cur.HasValue)
{
valueVal = (value = cur).GetValueOrDefault();
}
}
while (await e.MoveNextAsync())
{
var cur = selector(e.Current);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
float? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (float.IsNaN(valueVal))
{
if (!await e.MoveNextAsync())
{
return value;
}
var cur = await selector(e.Current).ConfigureAwait(false);
if (cur.HasValue)
{
valueVal = (value = cur).GetValueOrDefault();
}
}
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
float? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (float.IsNaN(valueVal))
{
if (!await e.MoveNextAsync())
{
return value;
}
var cur = await selector(e.Current, cancellationToken).ConfigureAwait(false);
if (cur.HasValue)
{
valueVal = (value = cur).GetValueOrDefault();
}
}
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current, cancellationToken).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
double value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = e.Current;
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (double.IsNaN(value))
{
if (!await e.MoveNextAsync())
{
return value;
}
value = e.Current;
}
while (await e.MoveNextAsync())
{
var x = e.Current;
if (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
double value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = selector(e.Current);
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (double.IsNaN(value))
{
if (!await e.MoveNextAsync())
{
return value;
}
value = selector(e.Current);
}
while (await e.MoveNextAsync())
{
var x = selector(e.Current);
if (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
double value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = await selector(e.Current).ConfigureAwait(false);
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (double.IsNaN(value))
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current).ConfigureAwait(false);
}
while (await e.MoveNextAsync())
{
var x = await selector(e.Current).ConfigureAwait(false);
if (x > value)
{
value = x;
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
double value;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
if (!await e.MoveNextAsync())
{
throw Error.NoElements();
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (double.IsNaN(value))
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
}
while (await e.MoveNextAsync())
{
var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
if (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
double? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = e.Current;
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (double.IsNaN(valueVal))
{
if (!await e.MoveNextAsync())
{
return value;
}
var cur = e.Current;
if (cur.HasValue)
{
valueVal = (value = cur).GetValueOrDefault();
}
}
while (await e.MoveNextAsync())
{
var cur = e.Current;
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
double? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = selector(e.Current);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (double.IsNaN(valueVal))
{
if (!await e.MoveNextAsync())
{
return value;
}
var cur = selector(e.Current);
if (cur.HasValue)
{
valueVal = (value = cur).GetValueOrDefault();
}
}
while (await e.MoveNextAsync())
{
var cur = selector(e.Current);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
double? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (double.IsNaN(valueVal))
{
if (!await e.MoveNextAsync())
{
return value;
}
var cur = await selector(e.Current).ConfigureAwait(false);
if (cur.HasValue)
{
valueVal = (value = cur).GetValueOrDefault();
}
}
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
double? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
// NaN is ordered less than all other values. We need to do explicit checks
// to ensure this, but once we've found a value that is not NaN we need no
// longer worry about it, so first loop until such a value is found (or not,
// as the case may be).
while (double.IsNaN(valueVal))
{
if (!await e.MoveNextAsync())
{
return value;
}
var cur = await selector(e.Current, cancellationToken).ConfigureAwait(false);
if (cur.HasValue)
{
valueVal = (value = cur).GetValueOrDefault();
}
}
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current, cancellationToken).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
// Do not replace & with &&. The branch prediction cost outweighs the extra operation
// unless nulls either never happen or always happen.
if (cur.HasValue & x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
decimal 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
decimal 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
decimal 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
decimal 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 (x > value)
{
value = x;
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the maximum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the maximum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the maximum value in the source sequence.
/// is null.
public static ValueTask MaxAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
decimal? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = e.Current;
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
while (await e.MoveNextAsync())
{
var cur = e.Current;
var x = cur.GetValueOrDefault();
if (cur.HasValue && x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func selector, CancellationToken cancellationToken)
{
decimal? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = selector(e.Current);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
while (await e.MoveNextAsync())
{
var cur = selector(e.Current);
var x = cur.GetValueOrDefault();
if (cur.HasValue && x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#endif
///
/// Invokes and awaits a transform function on each element of a sequence and returns the maximum value.
///
/// Type of elements in the source sequence.
/// The source sequence.
/// An asynchronous transform function to invoke and await on each element of the source.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing the maximum value in the sequence.
/// or is .
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
decimal? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
if (cur.HasValue && x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use MaxByAsync. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality previously provided by MaxAwaitWithCancellationAsync now exists as an overload of MaxByAsync.")]
private 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));
return Core(source, selector, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, Func> selector, CancellationToken cancellationToken)
{
decimal? value = null;
await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
{
// Start off knowing that we've a non-null value (or exit here, knowing we don't)
// so we don't have to keep testing for nullity.
do
{
if (!await e.MoveNextAsync())
{
return value;
}
value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
}
while (!value.HasValue);
// Keep hold of the wrapped value, and do comparisons on that, rather than
// using the lifted operation each time.
var valueVal = value.GetValueOrDefault();
while (await e.MoveNextAsync())
{
var cur = await selector(e.Current, cancellationToken).ConfigureAwait(false);
var x = cur.GetValueOrDefault();
if (cur.HasValue && x > valueVal)
{
valueVal = x;
value = cur;
}
}
}
return value;
}
}
#endif
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Returns the minimum value in an async-enumerable sequence of values.
///
/// A sequence of values to determine the minimum value of.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// A ValueTask containing a single element with the minimum value in the source sequence.
/// is null.
public static ValueTask MinAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
return Core(source, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, CancellationToken cancellationToken)
{
int 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 (x < value)
{
value = x;
}
}
}
return value;
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
public static ValueTask