-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Use Linq helpers. #79775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use Linq helpers. #79775
Changes from 1 commit
fda7045
1d162fe
ed8dfdd
14ab013
04ce44d
ac5786a
113f868
1db289b
042a013
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,8 +10,8 @@ | |
| using System.Collections.Immutable; | ||
| using System.Collections.ObjectModel; | ||
| using System.Diagnostics; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Linq; | ||
| using System.Runtime.InteropServices; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.CodeAnalysis; | ||
|
|
@@ -330,10 +330,38 @@ public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) | |
|
|
||
| return source.Where((Func<T?, bool>)s_notNullTest)!; | ||
| } | ||
| private static bool TryGetBuilder<TSource, TResult>( | ||
CyrusNajmabadi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| [NotNullWhen(true)] IEnumerable<TSource>? source, | ||
| [NotNullWhen(true)] out ArrayBuilder<TResult>? builder) | ||
| { | ||
| if (source is null) | ||
| { | ||
| builder = null; | ||
| return false; | ||
| } | ||
|
|
||
| #if NET | ||
| if (source.TryGetNonEnumeratedCount(out var count)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we reasonably optimize further if the count is < 4, using TemporaryArray?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That seems hard to do in a generalized fashion.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. or, put another way. can i postpone that till later. i'd rather get this in and focus on other stuff for now. |
||
| { | ||
| if (count == 0) | ||
| { | ||
| builder = null; | ||
| return false; | ||
| } | ||
|
|
||
| builder = ArrayBuilder<TResult>.GetInstance(count); | ||
| return true; | ||
| } | ||
| #endif | ||
|
|
||
| builder = ArrayBuilder<TResult>.GetInstance(); | ||
| return true; | ||
| } | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optimized a bunch of these helpers if the count can be determined (fast path to returning empty array, and also properly sizing the dest buffer). |
||
|
|
||
| public static ImmutableArray<T> WhereAsArray<T, TArg>(this IEnumerable<T> values, Func<T, TArg, bool> predicate, TArg arg) | ||
| { | ||
| var result = ArrayBuilder<T>.GetInstance(); | ||
| if (!TryGetBuilder<T, T>(values, out var result)) | ||
| return []; | ||
|
|
||
| foreach (var value in values) | ||
| { | ||
|
|
@@ -349,25 +377,34 @@ public static T[] AsArray<T>(this IEnumerable<T> source) | |
|
|
||
| public static ImmutableArray<TResult> SelectAsArray<TSource, TResult>(this IEnumerable<TSource>? source, Func<TSource, TResult> selector) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extensions that work on null receiver are odd.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't disagree. however, a lot of collect/ienumrable methods do this. so this is keeping things mostly consistent. would prefer to not rock the boat there for now. |
||
| { | ||
| if (source == null) | ||
| { | ||
| return ImmutableArray<TResult>.Empty; | ||
| } | ||
| if (!TryGetBuilder<TSource, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| var builder = ArrayBuilder<TResult>.GetInstance(); | ||
| builder.AddRange(source.Select(selector)); | ||
| return builder.ToImmutableAndFree(); | ||
|
|
||
| } | ||
|
|
||
| public static ImmutableArray<TResult> SelectAsArray<TItem, TResult>(this IEnumerable<TItem>? source, Func<TItem, bool> predicate, Func<TItem, TResult> selector) | ||
| { | ||
| if (!TryGetBuilder<TItem, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| foreach (var item in source) | ||
| { | ||
| if (predicate(item)) | ||
| builder.Add(selector(item)); | ||
| } | ||
|
|
||
| return builder.ToImmutableAndFree(); | ||
| } | ||
|
|
||
| public static ImmutableArray<TResult> SelectAsArray<TSource, TResult>(this IEnumerable<TSource>? source, Func<TSource, int, TResult> selector) | ||
| { | ||
| if (source == null) | ||
| return ImmutableArray<TResult>.Empty; | ||
| if (!TryGetBuilder<TSource, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| var builder = ArrayBuilder<TResult>.GetInstance(); | ||
|
|
||
| int index = 0; | ||
| var index = 0; | ||
| foreach (var element in source) | ||
| { | ||
| builder.Add(selector(element, index)); | ||
|
|
@@ -379,42 +416,33 @@ public static ImmutableArray<TResult> SelectAsArray<TSource, TResult>(this IEnum | |
|
|
||
| public static ImmutableArray<TResult> SelectAsArray<TSource, TResult>(this IReadOnlyCollection<TSource>? source, Func<TSource, TResult> selector) | ||
| { | ||
| if (source == null) | ||
| return ImmutableArray<TResult>.Empty; | ||
| if (source is null or { Count: 0 }) | ||
| return []; | ||
|
|
||
| var builder = new TResult[source.Count]; | ||
| var index = 0; | ||
| var builder = new FixedSizeArrayBuilder<TResult>(source.Count); | ||
| foreach (var item in source) | ||
| { | ||
| builder[index] = selector(item); | ||
| index++; | ||
| } | ||
| builder.Add(selector(item)); | ||
|
|
||
| return ImmutableCollectionsMarshal.AsImmutableArray(builder); | ||
| return builder.MoveToImmutable(); | ||
| } | ||
|
|
||
| public static ImmutableArray<TResult> SelectAsArray<TSource, TResult, TArg>(this IReadOnlyCollection<TSource>? source, Func<TSource, TArg, TResult> selector, TArg arg) | ||
| { | ||
| if (source == null) | ||
| return ImmutableArray<TResult>.Empty; | ||
| if (source is null or { Count: 0 }) | ||
| return []; | ||
|
|
||
| var builder = new TResult[source.Count]; | ||
| var index = 0; | ||
| var builder = new FixedSizeArrayBuilder<TResult>(source.Count); | ||
| foreach (var item in source) | ||
| { | ||
| builder[index] = selector(item, arg); | ||
| index++; | ||
| } | ||
| builder.Add(selector(item, arg)); | ||
|
|
||
| return ImmutableCollectionsMarshal.AsImmutableArray(builder); | ||
| return builder.MoveToImmutable(); | ||
| } | ||
|
|
||
| public static ImmutableArray<TResult> SelectManyAsArray<TSource, TResult>(this IEnumerable<TSource>? source, Func<TSource, IEnumerable<TResult>> selector) | ||
| { | ||
| if (source == null) | ||
| return ImmutableArray<TResult>.Empty; | ||
| if (!TryGetBuilder<TSource, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| var builder = ArrayBuilder<TResult>.GetInstance(); | ||
| foreach (var item in source) | ||
| builder.AddRange(selector(item)); | ||
|
|
||
|
|
@@ -423,10 +451,9 @@ public static ImmutableArray<TResult> SelectManyAsArray<TSource, TResult>(this I | |
|
|
||
| public static ImmutableArray<TResult> SelectManyAsArray<TItem, TArg, TResult>(this IEnumerable<TItem>? source, Func<TItem, TArg, IEnumerable<TResult>> selector, TArg arg) | ||
| { | ||
| if (source == null) | ||
| return ImmutableArray<TResult>.Empty; | ||
| if (!TryGetBuilder<TItem, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| var builder = ArrayBuilder<TResult>.GetInstance(); | ||
| foreach (var item in source) | ||
| builder.AddRange(selector(item, arg)); | ||
|
|
||
|
|
@@ -435,8 +462,8 @@ public static ImmutableArray<TResult> SelectManyAsArray<TItem, TArg, TResult>(th | |
|
|
||
| public static ImmutableArray<TResult> SelectManyAsArray<TItem, TResult>(this IReadOnlyCollection<TItem>? source, Func<TItem, IEnumerable<TResult>> selector) | ||
| { | ||
| if (source == null) | ||
| return ImmutableArray<TResult>.Empty; | ||
| if (source is null or { Count: 0 }) | ||
| return []; | ||
|
|
||
| // Basic heuristic. Assume each element in the source adds one item to the result. | ||
| var builder = ArrayBuilder<TResult>.GetInstance(source.Count); | ||
|
|
@@ -448,8 +475,8 @@ public static ImmutableArray<TResult> SelectManyAsArray<TItem, TResult>(this IRe | |
|
|
||
| public static ImmutableArray<TResult> SelectManyAsArray<TItem, TArg, TResult>(this IReadOnlyCollection<TItem>? source, Func<TItem, TArg, IEnumerable<TResult>> selector, TArg arg) | ||
| { | ||
| if (source == null) | ||
| return ImmutableArray<TResult>.Empty; | ||
| if (source is null or { Count: 0 }) | ||
| return []; | ||
|
|
||
| // Basic heuristic. Assume each element in the source adds one item to the result. | ||
| var builder = ArrayBuilder<TResult>.GetInstance(source.Count); | ||
|
|
@@ -461,10 +488,9 @@ public static ImmutableArray<TResult> SelectManyAsArray<TItem, TArg, TResult>(th | |
|
|
||
| public static ImmutableArray<TResult> SelectManyAsArray<TSource, TResult>(this IEnumerable<TSource>? source, Func<TSource, OneOrMany<TResult>> selector) | ||
| { | ||
| if (source == null) | ||
| return ImmutableArray<TResult>.Empty; | ||
| if (!TryGetBuilder<TSource, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| var builder = ArrayBuilder<TResult>.GetInstance(); | ||
| foreach (var item in source) | ||
| selector(item).AddRangeTo(builder); | ||
|
|
||
|
|
@@ -476,12 +502,11 @@ public static ImmutableArray<TResult> SelectManyAsArray<TSource, TResult>(this I | |
| /// </summary> | ||
| public static async ValueTask<ImmutableArray<TResult>> SelectAsArrayAsync<TItem, TResult>(this IEnumerable<TItem> source, Func<TItem, ValueTask<TResult>> selector) | ||
| { | ||
| var builder = ArrayBuilder<TResult>.GetInstance(); | ||
| if (!TryGetBuilder<TItem, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| foreach (var item in source) | ||
| { | ||
| builder.Add(await selector(item).ConfigureAwait(false)); | ||
| } | ||
|
|
||
| return builder.ToImmutableAndFree(); | ||
| } | ||
|
|
@@ -491,12 +516,11 @@ public static async ValueTask<ImmutableArray<TResult>> SelectAsArrayAsync<TItem, | |
| /// </summary> | ||
| public static async ValueTask<ImmutableArray<TResult>> SelectAsArrayAsync<TItem, TResult>(this IEnumerable<TItem> source, Func<TItem, CancellationToken, ValueTask<TResult>> selector, CancellationToken cancellationToken) | ||
| { | ||
| var builder = ArrayBuilder<TResult>.GetInstance(); | ||
| if (!TryGetBuilder<TItem, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| foreach (var item in source) | ||
| { | ||
| builder.Add(await selector(item, cancellationToken).ConfigureAwait(false)); | ||
| } | ||
|
|
||
| return builder.ToImmutableAndFree(); | ||
| } | ||
|
|
@@ -506,24 +530,22 @@ public static async ValueTask<ImmutableArray<TResult>> SelectAsArrayAsync<TItem, | |
| /// </summary> | ||
| public static async ValueTask<ImmutableArray<TResult>> SelectAsArrayAsync<TItem, TArg, TResult>(this IEnumerable<TItem> source, Func<TItem, TArg, CancellationToken, ValueTask<TResult>> selector, TArg arg, CancellationToken cancellationToken) | ||
| { | ||
| var builder = ArrayBuilder<TResult>.GetInstance(); | ||
| if (!TryGetBuilder<TItem, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| foreach (var item in source) | ||
| { | ||
| builder.Add(await selector(item, arg, cancellationToken).ConfigureAwait(false)); | ||
| } | ||
|
|
||
| return builder.ToImmutableAndFree(); | ||
| } | ||
|
|
||
| public static async ValueTask<ImmutableArray<TResult>> SelectManyAsArrayAsync<TItem, TArg, TResult>(this IEnumerable<TItem> source, Func<TItem, TArg, CancellationToken, ValueTask<IEnumerable<TResult>>> selector, TArg arg, CancellationToken cancellationToken) | ||
| { | ||
| var builder = ArrayBuilder<TResult>.GetInstance(); | ||
| if (!TryGetBuilder<TItem, TResult>(source, out var builder)) | ||
| return []; | ||
|
|
||
| foreach (var item in source) | ||
| { | ||
| builder.AddRange(await selector(item, arg, cancellationToken).ConfigureAwait(false)); | ||
| } | ||
|
|
||
| return builder.ToImmutableAndFree(); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where+SelectAsArray becomes SelectAsArray (with predicate passed to the latter).