| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 | 
							- <#@ template debug="false" hostspecific="false" language="C#" #>
 
- <#@ assembly name="System.Core" #>
 
- <#@ import namespace="System.Linq" #>
 
- <#@ import namespace="System.Text" #>
 
- <#@ import namespace="System.Collections.Generic" #>
 
- <#@ output extension=".cs" #>
 
- // 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
 
-     {
 
- <#
 
- foreach (var m in new[] { "Max", "Min" })
 
- {
 
-     var comparison = m == "Max" ? ">" : "<";
 
-     var extremum = m == "Max" ? "maximum" : "minimum";
 
-     foreach (var t in new[] { "int", "int?", "long", "long?", "float", "float?", "double", "double?", "decimal", "decimal?" })
 
-     {
 
-         var isFloatingPoint = t.StartsWith("float") || t.StartsWith("double");
 
-         var isInteger = t.StartsWith("int") || t.StartsWith("long");
 
-         var isNullable = t.EndsWith("?");
 
-         var shortCircuit = t.StartsWith("decimal");
 
-         var typeStr = t;
 
-         if (isNullable) {
 
-             typeStr = "Nullable{" + t.Substring(0, 1).ToUpper() + t.Substring(1, t.Length - 2) + "}";
 
-         }
 
- #>
 
-         /// <summary>
 
-         /// Returns the <#=extremum#> value in an async-enumerable sequence of <see cref="<#=typeStr#>" /> values.
 
-         /// </summary>
 
-         /// <param name="source">A sequence of <see cref="<#=typeStr#>" /> values to determine the <#=extremum#> value of.</param>
 
-         /// <param name="cancellationToken">The optional cancellation token to be used for cancelling the sequence at any time.</param>
 
-         /// <returns>A ValueTask containing a single element with the <#=extremum#> value in the source sequence.</returns>
 
-         /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
 
-         public static ValueTask<<#=t#>> <#=m#>Async(this IAsyncEnumerable<<#=t#>> source, CancellationToken cancellationToken = default)
 
-         {
 
-             if (source == null)
 
-                 throw Error.ArgumentNull(nameof(source));
 
-             return Core(source, cancellationToken);
 
-             static async ValueTask<<#=t#>> Core(IAsyncEnumerable<<#=t#>> source, CancellationToken cancellationToken)
 
-             {
 
- <#
 
-         if (!isNullable)
 
-         {
 
- #>
 
-                 <#=t#> value;
 
-                 await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
 
-                 {
 
-                     if (!await e.MoveNextAsync())
 
-                     {
 
-                         throw Error.NoElements();
 
-                     }
 
-                     value = e.Current;
 
- <#
 
-             if (isFloatingPoint && m == "Max")
 
-             {
 
- #>
 
-                     // 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 (<#=t#>.IsNaN(value))
 
-                     {
 
-                         if (!await e.MoveNextAsync())
 
-                         {
 
-                             return value;
 
-                         }
 
-                         value = e.Current;
 
-                     }
 
- <#
 
-             }
 
- #>
 
-                     while (await e.MoveNextAsync())
 
-                     {
 
-                         var x = e.Current;
 
-                         if (x <#=comparison#> value)
 
-                         {
 
-                             value = x;
 
-                         }
 
- <#
 
-             if (isFloatingPoint && m == "Min")
 
-             {
 
- #>
 
-                         else
 
-                         {
 
-                             // Normally NaN < anything is false, as is anything < NaN
 
-                             // However, this leads to some irksome outcomes in Min and Max.
 
-                             // If we use those semantics then Min(NaN, 5.0) is NaN, but
 
-                             // Min(5.0, NaN) is 5.0!  To fix this, we impose a total
 
-                             // ordering where NaN is smaller than every value, including
 
-                             // negative infinity.
 
-                             // Not testing for NaN therefore isn't an option, but since we
 
-                             // can't find a smaller value, we can short-circuit.
 
-                             if (<#=t#>.IsNaN(x))
 
-                             {
 
-                                 return x;
 
-                             }
 
-                         }
 
- <#
 
-             }
 
- #>
 
-                     }
 
-                 }
 
-                 return value;
 
- <#
 
-         }
 
-         else
 
-         {
 
- #>
 
-                 <#=t#> 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 (isInteger && m == "Max")
 
-             {
 
- #>
 
-                     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 <#=comparison#> 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 <#=comparison#> valueVal)
 
-                             {
 
-                                 valueVal = x;
 
-                                 value = cur;
 
-                             }
 
-                         }
 
-                     }
 
- <#
 
-             }
 
-             else if (isFloatingPoint && m == "Min")
 
-             {
 
- #>
 
-                     while (await e.MoveNextAsync())
 
-                     {
 
-                         var cur = e.Current;
 
-                         if (cur.HasValue)
 
-                         {
 
-                             var x = cur.GetValueOrDefault();
 
-                             if (x <#=comparison#> valueVal)
 
-                             {
 
-                                 valueVal = x;
 
-                                 value = cur;
 
-                             }
 
-                             else
 
-                             {
 
-                                 // Normally NaN < anything is false, as is anything < NaN
 
-                                 // However, this leads to some irksome outcomes in Min and Max.
 
-                                 // If we use those semantics then Min(NaN, 5.0) is NaN, but
 
-                                 // Min(5.0, NaN) is 5.0!  To fix this, we impose a total
 
-                                 // ordering where NaN is smaller than every value, including
 
-                                 // negative infinity.
 
-                                 // Not testing for NaN therefore isn't an option, but since we
 
-                                 // can't find a smaller value, we can short-circuit.
 
-                                 if (<#=t.TrimEnd('?')#>.IsNaN(x))
 
-                                 {
 
-                                     return cur;
 
-                                 }
 
-                             }
 
-                         }
 
-                     }
 
- <#
 
-             }
 
-             else
 
-             {
 
-                 if (isFloatingPoint && m == "Max")
 
-                 {
 
- #>
 
-                     // 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 (<#=t.TrimEnd('?')#>.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();
 
- <#
 
-                 if (shortCircuit)
 
-                 {
 
- #>
 
-                         if (cur.HasValue && x <#=comparison#> valueVal)
 
- <#
 
-                 }
 
-                 else
 
-                 {
 
- #>
 
-                         // Do not replace & with &&. The branch prediction cost outweighs the extra operation
 
-                         // unless nulls either never happen or always happen.
 
-                         if (cur.HasValue & x <#=comparison#> valueVal)
 
- <#
 
-                 }
 
- #>
 
-                         {
 
-                             valueVal = x;
 
-                             value = cur;
 
-                         }
 
-                     }
 
- <#
 
-             }
 
- #>
 
-                 }
 
-                 return value;
 
- <#
 
-         }
 
- #>
 
-             }
 
-         }
 
- <#
 
- foreach (var overload in new[] {
 
-     new { selector = "Func<TSource, " + t + ">", invoke = "selector(e.Current)" },
 
-     new { selector = "Func<TSource, ValueTask<" + t + ">>", invoke = "await selector(e.Current).ConfigureAwait(false)" },
 
-     new { selector = "Func<TSource, CancellationToken, ValueTask<" + t + ">>", invoke = "await selector(e.Current, cancellationToken).ConfigureAwait(false)" },
 
- })
 
- {
 
-     var isAsync = overload.invoke.StartsWith("await");
 
-     var isDeepCancellation = overload.selector.Contains("CancellationToken");
 
-     var suffix = isAsync ? "Await" : "";
 
-     var visibility = isAsync ? "internal" : "public";
 
-     var core = isAsync ? "Core" : "";
 
-     if (isDeepCancellation)
 
-     {
 
-         suffix += "WithCancellation";
 
- #>
 
- #if !NO_DEEP_CANCELLATION
 
- <#
 
-     }
 
- #>
 
-         <#=visibility#> static ValueTask<<#=t#>> <#=m#><#=suffix#>Async<#=core#><TSource>(this IAsyncEnumerable<TSource> source, <#=overload.selector#> 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<<#=t#>> Core(IAsyncEnumerable<TSource> source, <#=overload.selector#> selector, CancellationToken cancellationToken)
 
-             {
 
- <#
 
-         if (!isNullable)
 
-         {
 
- #>
 
-                 <#=t#> value;
 
-                 await using (var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false))
 
-                 {
 
-                     if (!await e.MoveNextAsync())
 
-                     {
 
-                         throw Error.NoElements();
 
-                     }
 
-                     value = <#=overload.invoke#>;
 
- <#
 
-             if (isFloatingPoint && m == "Max")
 
-             {
 
- #>
 
-                     // 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 (<#=t#>.IsNaN(value))
 
-                     {
 
-                         if (!await e.MoveNextAsync())
 
-                         {
 
-                             return value;
 
-                         }
 
-                         value = <#=overload.invoke#>;
 
-                     }
 
- <#
 
-             }
 
- #>
 
-                     while (await e.MoveNextAsync())
 
-                     {
 
-                         var x = <#=overload.invoke#>;
 
-                         if (x <#=comparison#> value)
 
-                         {
 
-                             value = x;
 
-                         }
 
- <#
 
-             if (isFloatingPoint && m == "Min")
 
-             {
 
- #>
 
-                         else
 
-                         {
 
-                             // Normally NaN < anything is false, as is anything < NaN
 
-                             // However, this leads to some irksome outcomes in Min and Max.
 
-                             // If we use those semantics then Min(NaN, 5.0) is NaN, but
 
-                             // Min(5.0, NaN) is 5.0!  To fix this, we impose a total
 
-                             // ordering where NaN is smaller than every value, including
 
-                             // negative infinity.
 
-                             // Not testing for NaN therefore isn't an option, but since we
 
-                             // can't find a smaller value, we can short-circuit.
 
-                             if (<#=t#>.IsNaN(x))
 
-                             {
 
-                                 return x;
 
-                             }
 
-                         }
 
- <#
 
-             }
 
- #>
 
-                     }
 
-                 }
 
-                 return value;
 
- <#
 
-         }
 
-         else
 
-         {
 
- #>
 
-                 <#=t#> 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 = <#=overload.invoke#>;
 
-                     }
 
-                     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 (isInteger && m == "Max")
 
-             {
 
- #>
 
-                     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 = <#=overload.invoke#>;
 
-                             var x = cur.GetValueOrDefault();
 
-                             if (x <#=comparison#> valueVal)
 
-                             {
 
-                                 valueVal = x;
 
-                                 value = cur;
 
-                             }
 
-                         }
 
-                     }
 
-                     else
 
-                     {
 
-                         while (await e.MoveNextAsync())
 
-                         {
 
-                             var cur = <#=overload.invoke#>;
 
-                             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 <#=comparison#> valueVal)
 
-                             {
 
-                                 valueVal = x;
 
-                                 value = cur;
 
-                             }
 
-                         }
 
-                     }
 
- <#
 
-             }
 
-             else if (isFloatingPoint && m == "Min")
 
-             {
 
- #>
 
-                     while (await e.MoveNextAsync())
 
-                     {
 
-                         var cur = <#=overload.invoke#>;
 
-                         if (cur.HasValue)
 
-                         {
 
-                             var x = cur.GetValueOrDefault();
 
-                             if (x <#=comparison#> valueVal)
 
-                             {
 
-                                 valueVal = x;
 
-                                 value = cur;
 
-                             }
 
-                             else
 
-                             {
 
-                                 // Normally NaN < anything is false, as is anything < NaN
 
-                                 // However, this leads to some irksome outcomes in Min and Max.
 
-                                 // If we use those semantics then Min(NaN, 5.0) is NaN, but
 
-                                 // Min(5.0, NaN) is 5.0!  To fix this, we impose a total
 
-                                 // ordering where NaN is smaller than every value, including
 
-                                 // negative infinity.
 
-                                 // Not testing for NaN therefore isn't an option, but since we
 
-                                 // can't find a smaller value, we can short-circuit.
 
-                                 if (<#=t.TrimEnd('?')#>.IsNaN(x))
 
-                                 {
 
-                                     return cur;
 
-                                 }
 
-                             }
 
-                         }
 
-                     }
 
- <#
 
-             }
 
-             else
 
-             {
 
-                 if (isFloatingPoint && m == "Max")
 
-                 {
 
- #>
 
-                     // 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 (<#=t.TrimEnd('?')#>.IsNaN(valueVal))
 
-                     {
 
-                         if (!await e.MoveNextAsync())
 
-                         {
 
-                             return value;
 
-                         }
 
-                         var cur = <#=overload.invoke#>;
 
-                         if (cur.HasValue)
 
-                         {
 
-                             valueVal = (value = cur).GetValueOrDefault();
 
-                         }
 
-                     }
 
- <#
 
-                 }
 
- #>
 
-                     while (await e.MoveNextAsync())
 
-                     {
 
-                         var cur = <#=overload.invoke#>;
 
-                         var x = cur.GetValueOrDefault();
 
- <#
 
-                 if (shortCircuit)
 
-                 {
 
- #>
 
-                         if (cur.HasValue && x <#=comparison#> valueVal)
 
- <#
 
-                 }
 
-                 else
 
-                 {
 
- #>
 
-                         // Do not replace & with &&. The branch prediction cost outweighs the extra operation
 
-                         // unless nulls either never happen or always happen.
 
-                         if (cur.HasValue & x <#=comparison#> valueVal)
 
- <#
 
-                 }
 
- #>
 
-                         {
 
-                             valueVal = x;
 
-                             value = cur;
 
-                         }
 
-                     }
 
- <#
 
-             }
 
- #>
 
-                 }
 
-                 return value;
 
- <#
 
-         }
 
- #>
 
-             }
 
-         }
 
- <#
 
-     if (isDeepCancellation)
 
-     {
 
- #>
 
- #endif
 
- <#
 
-     }
 
- }
 
- #>
 
- <#
 
-     }
 
- }
 
- #>
 
-     }
 
- }
 
 
  |