Skip to content
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

Improve generator code layout #638

Merged
merged 2 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 45 additions & 42 deletions Generators/SuperLinq.Async.Generator/EquiZip.sbntxt
Original file line number Diff line number Diff line change
@@ -1,64 +1,66 @@
{{
$arity = arity
$ordinals = ordinals
$cardinals = cardinals
}}

{{~
$arity = arity
$ordinals = ordinals
$cardinals = cardinals
~}}
namespace SuperLinq.Async;

#nullable enable

public static partial class AsyncSuperEnumerable
{
{{~ for $i in 2..4 ~}}
/// <summary>
/// <summary>
/// <para>
/// Applies a specified function to the corresponding elements of {{ $ordinals[$i] }} sequences,
/// producing a sequence of the results.</para>
/// <para>
/// The resulting sequence has the same length as the input sequences.
/// If the input sequences are of different lengths, an exception is thrown.</para>
/// </summary>
/// <typeparam name="TResult">
/// The type of the elements of the result sequence.</typeparam>
/// <param name="resultSelector">A projection function that combines
/// elements from all of the sequences.</param>
/// <returns>A sequence of elements returned by <paramref name="resultSelector"/>.</returns>
/// <remarks>
/// This method uses deferred execution and stream its results.
/// </remarks>
/// <exception cref="global::System.ArgumentNullException"><paramref name="resultSelector"/> or any of the input sequences is null.</exception>
/// <exception cref="global::System.InvalidOperationException">
/// </summary>
/// <typeparam name="TResult">
/// The type of the elements of the result sequence.</typeparam>
/// <param name="resultSelector">A projection function that combines
/// elements from all of the sequences.</param>
/// <returns>A sequence of elements returned by <paramref name="resultSelector"/>.</returns>
/// <remarks>
/// This method uses deferred execution and stream its results.
/// </remarks>
/// <exception cref="global::System.ArgumentNullException"><paramref name="resultSelector"/> or any of the input sequences is null.</exception>
/// <exception cref="global::System.InvalidOperationException">
/// Any of the input sequences are shorter than the others.
/// </exception>
{{~ for $j in 1..$i ~}}
/// <typeparam name="T{{ $cardinals[$j] }}">The type of the elements of <paramref name="{{ $ordinals[$j] }}" />.</typeparam>
/// <typeparam name="T{{ $cardinals[$j] }}">The type of the elements of <paramref name="{{ $ordinals[$j] }}" />.</typeparam>
/// <param name="{{ $ordinals[$j] }}">The {{ $ordinals[$j] }} sequence of elements.</param>
{{~ end ~}}
public static global::System.Collections.Generic.IAsyncEnumerable<TResult> EquiZip<{{ for $j in 1..$i }}T{{ $cardinals[$j] }}, {{ end }}TResult>(this
public static global::System.Collections.Generic.IAsyncEnumerable<TResult> EquiZip<{{ for $j in 1..$i }}T{{ $cardinals[$j] }}, {{ end }}TResult>(this
{{~ for $j in 1..$i ~}}
global::System.Collections.Generic.IAsyncEnumerable<T{{ $cardinals[$j] }}> {{ $ordinals[$j] }},
global::System.Collections.Generic.IAsyncEnumerable<T{{ $cardinals[$j] }}> {{ $ordinals[$j] }},
{{~ end ~}}
global::System.Func<{{ for $j in 1..$i }}T{{ $cardinals[$j] }}, {{ end }}TResult> resultSelector)
global::System.Func<{{ for $j in 1..$i }}T{{ $cardinals[$j] }}, {{ end }}TResult> resultSelector
)
{
{{~ for $j in 1..$i ~}}
ArgumentNullException.ThrowIfNull({{ $ordinals[$j] }});
ArgumentNullException.ThrowIfNull({{ $ordinals[$j] }});
{{~ end ~}}

ArgumentNullException.ThrowIfNull(resultSelector);
ArgumentNullException.ThrowIfNull(resultSelector);

return Core(
{{~ for $j in 1..$i ~}}
{{ $ordinals[$j] }},
{{~ end ~}}
resultSelector);
resultSelector
);

static async global::System.Collections.Generic.IAsyncEnumerable<TResult> Core(
{{~ for $j in 1..$i ~}}
global::System.Collections.Generic.IAsyncEnumerable<T{{ $cardinals[$j] }}> {{ $ordinals[$j] }},
{{~ end ~}}
global::System.Func<{{ for $j in 1..$i }}T{{ $cardinals[$j] }}, {{ end }}TResult> resultSelector,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
[EnumeratorCancellation] CancellationToken cancellationToken = default
)
{
{{~ for $j in 1..$i ~}}
await using var e{{ $j }} = {{ $ordinals[$j] }}.ConfigureAwait(false).WithCancellation(cancellationToken).GetAsyncEnumerator();
Expand All @@ -75,10 +77,10 @@ public static partial class AsyncSuperEnumerable
|| await e{{$j}}.MoveNextAsync()
{{~ end
end ~}}
)
)
{
ThrowHelper.ThrowInvalidOperationException("First sequence too short.");
}
ThrowHelper.ThrowInvalidOperationException("First sequence too short.");
}

yield break;
}
Expand All @@ -101,26 +103,27 @@ public static partial class AsyncSuperEnumerable
/// <summary>
/// Joins the corresponding elements of {{ $ordinals[$i] }} sequences,
/// producing a sequence of tuples containing them.
/// </summary>
/// <returns>A sequence of
/// </summary>
/// <returns>A sequence of
/// <see cref="global::System.ValueTuple{ {{~ for $j in 1..$i ~}}T{{$j}}{{ if !for.last }},{{ end }}{{ end }} }" />
/// containing corresponding elements from each of the sequences.</returns>
/// <remarks>
/// This method uses deferred execution and stream its results.
/// </remarks>
/// <exception cref="global::System.ArgumentNullException">Any of the input sequences is null.</exception>
/// <exception cref="global::System.InvalidOperationException">
/// containing corresponding elements from each of the sequences.</returns>
/// <remarks>
/// This method uses deferred execution and stream its results.
/// </remarks>
/// <exception cref="global::System.ArgumentNullException">Any of the input sequences is null.</exception>
/// <exception cref="global::System.InvalidOperationException">
/// Any of the input sequences are shorter than the others.
/// </exception>
{{~ for $j in 1..$i ~}}
/// <typeparam name="T{{ $cardinals[$j] }}">The type of the elements of <paramref name="{{ $ordinals[$j] }}" />.</typeparam>
/// <typeparam name="T{{ $cardinals[$j] }}">The type of the elements of <paramref name="{{ $ordinals[$j] }}" />.</typeparam>
/// <param name="{{ $ordinals[$j] }}">The {{ $ordinals[$j] }} sequence of elements.</param>
{{~ end ~}}
public static global::System.Collections.Generic.IAsyncEnumerable<({{~ for $j in 1..$i ~}}T{{ $cardinals[$j] }}{{ if !for.last }},{{ end }}{{ end }})>
public static global::System.Collections.Generic.IAsyncEnumerable<({{~ for $j in 1..$i ~}}T{{ $cardinals[$j] }}{{ if !for.last }},{{ end }}{{ end }})>
EquiZip<{{~ for $j in 1..$i ~}}T{{ $cardinals[$j] }}{{ if !for.last }},{{ end }}{{ end }}>(this
{{~ for $j in 1..$i ~}}
global::System.Collections.Generic.IAsyncEnumerable<T{{ $cardinals[$j] }}> {{ $ordinals[$j] }}{{ if !for.last }},{{ end }}
{{~ end ~}}) =>
EquiZip({{~ for $j in 1..$i ~}}{{ $ordinals[$j] }}, {{ end }}global::System.ValueTuple.Create);
{{ end ~}}
{{~ end ~}}
) => EquiZip({{~ for $j in 1..$i ~}}{{ $ordinals[$j] }}, {{ end }}global::System.ValueTuple.Create);

{{~ end ~}}
}
51 changes: 25 additions & 26 deletions Generators/SuperLinq.Async.Generator/Fold.sbntxt
Original file line number Diff line number Diff line change
@@ -1,41 +1,39 @@
namespace SuperLinq.Async;
namespace SuperLinq.Async;

#nullable enable

public static partial class AsyncSuperEnumerable
{
{{~ for $i in 1..16 ~}}
/// <summary>
/// Returns the result of applying a function to a sequence of {{$i}} element{{if $i != 1}}s{{end}}.
/// </summary>
/// <remarks>
/// This operator uses immediate execution and buffers as many items of the source sequence as necessary.
/// </remarks>
/// <typeparam name="T">Type of element in the source sequence</typeparam>
/// <typeparam name="TResult">Type of the result</typeparam>
/// <param name="source">The sequence of items to fold.</param>
/// <param name="folder">Function to apply to the elements in the sequence.</param>
/// <returns>The folded value returned by <paramref name="folder"/>.</returns>
/// <exception cref="global::System.ArgumentNullException"><paramref name="source"/> or <paramref name="folder"/> is null.</exception>
/// <exception cref="global::System.InvalidOperationException">
/// <summary>
/// Returns the result of applying a function to a sequence of {{$i}} element{{if $i != 1}}s{{end}}.
/// </summary>
/// <remarks>
/// This operator uses immediate execution and buffers as many items of the source sequence as necessary.
/// </remarks>
/// <typeparam name="T">Type of element in the source sequence</typeparam>
/// <typeparam name="TResult">Type of the result</typeparam>
/// <param name="source">The sequence of items to fold.</param>
/// <param name="folder">Function to apply to the elements in the sequence.</param>
/// <returns>The folded value returned by <paramref name="folder"/>.</returns>
/// <exception cref="global::System.ArgumentNullException"><paramref name="source"/> or <paramref name="folder"/> is null.</exception>
/// <exception cref="global::System.InvalidOperationException">
/// <paramref name="source"/> does not contain exactly {{$i}} element{{if $i != 1}}s{{end}}.
/// </exception>
public static global::System.Threading.Tasks.ValueTask<TResult> Fold<T, TResult>(this global::System.Collections.Generic.IAsyncEnumerable<T> source, global::System.Func<
{{~ for $j in 1..$i ~}}
T,
{{~ end ~}}
TResult> folder)
{
public static global::System.Threading.Tasks.ValueTask<TResult> Fold<T, TResult>(
this global::System.Collections.Generic.IAsyncEnumerable<T> source,
global::System.Func<{{~ for $j in 1..$i ~}}T, {{ end ~}}TResult> folder
)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(folder);

return Core(source, folder);

static async global::System.Threading.Tasks.ValueTask<TResult> Core(global::System.Collections.Generic.IAsyncEnumerable<T> source, global::System.Func<
{{~ for $j in 1..$i ~}}
T,
{{~ end ~}}
TResult> folder)
static async global::System.Threading.Tasks.ValueTask<TResult> Core(
global::System.Collections.Generic.IAsyncEnumerable<T> source,
global::System.Func<{{~ for $j in 1..$i ~}}T, {{ end ~}}TResult> folder
)
{
var elements = await source.AssertCount({{$i}}).ToListAsync().ConfigureAwait(false);

Expand All @@ -46,5 +44,6 @@ public static partial class AsyncSuperEnumerable
);
}
}
{{ end ~}}

{{~ end ~}}
}
10 changes: 1 addition & 9 deletions Generators/SuperLinq.Async.Generator/Generator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Scriban;
Expand Down Expand Up @@ -28,14 +28,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
private static SourceText GenerateArgumentNamesTemplate(string template)
{
var output = Template.Parse(template).Render(ArgumentNames.Instance);

// Apply formatting since indenting isn't that nice in Scriban when rendering nested
// structures via functions.
output = Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseCompilationUnit(output)
.NormalizeWhitespace()
.GetText()
.ToString();

return SourceText.From(output, Encoding.UTF8);
}
}
79 changes: 41 additions & 38 deletions Generators/SuperLinq.Async.Generator/ZipLongest.sbntxt
Original file line number Diff line number Diff line change
@@ -1,60 +1,62 @@
{{
$arity = arity
$ordinals = ordinals
$cardinals = cardinals
}}

{{~
$arity = arity
$ordinals = ordinals
$cardinals = cardinals
~}}
namespace SuperLinq.Async;

#nullable enable

public static partial class AsyncSuperEnumerable
{
{{~ for $i in 2..4 ~}}
/// <summary>
/// <summary>
/// Returns a projection of tuples, where each tuple contains the N-th
/// element from each of the argument sequences. The resulting sequence
/// will always be as long as the longest of input sequences where the
/// default value of each of the shorter sequence element types is used
/// for padding.
/// </summary>
/// <typeparam name="TResult">
/// The type of the elements of the result sequence.</typeparam>
/// <param name="resultSelector">A projection function that combines
/// elements from all of the sequences.</param>
/// <returns>A sequence of elements returned by <paramref name="resultSelector"/>.</returns>
/// <remarks>
/// This method uses deferred execution and streams its results.
/// </remarks>
/// <exception cref="global::System.ArgumentNullException"><paramref name="resultSelector"/> or any of the input sequences is null.</exception>
/// </summary>
/// <typeparam name="TResult">
/// The type of the elements of the result sequence.</typeparam>
/// <param name="resultSelector">A projection function that combines
/// elements from all of the sequences.</param>
/// <returns>A sequence of elements returned by <paramref name="resultSelector"/>.</returns>
/// <remarks>
/// This method uses deferred execution and streams its results.
/// </remarks>
/// <exception cref="global::System.ArgumentNullException"><paramref name="resultSelector"/> or any of the input sequences is null.</exception>
{{~ for $j in 1..$i ~}}
/// <typeparam name="T{{ $j }}">The type of the elements of <paramref name="{{ $ordinals[$j] }}" />.</typeparam>
/// <typeparam name="T{{ $j }}">The type of the elements of <paramref name="{{ $ordinals[$j] }}" />.</typeparam>
/// <param name="{{ $ordinals[$j] }}">The {{ $ordinals[$j] }} sequence of elements.</param>
{{~ end ~}}
public static global::System.Collections.Generic.IAsyncEnumerable<TResult> ZipLongest<{{ for $j in 1..$i }}T{{ $j }}, {{ end }}TResult>(this
public static global::System.Collections.Generic.IAsyncEnumerable<TResult> ZipLongest<{{ for $j in 1..$i }}T{{ $j }}, {{ end }}TResult>(this
{{~ for $j in 1..$i ~}}
global::System.Collections.Generic.IAsyncEnumerable<T{{ $j }}> {{ $ordinals[$j] }},
global::System.Collections.Generic.IAsyncEnumerable<T{{ $j }}> {{ $ordinals[$j] }},
{{~ end ~}}
global::System.Func<{{ for $j in 1..$i }}T{{ $j }}?, {{ end }}TResult> resultSelector)
global::System.Func<{{ for $j in 1..$i }}T{{ $j }}?, {{ end }}TResult> resultSelector
)
{
{{~ for $j in 1..$i ~}}
ArgumentNullException.ThrowIfNull({{ $ordinals[$j] }});
ArgumentNullException.ThrowIfNull({{ $ordinals[$j] }});
{{~ end ~}}

ArgumentNullException.ThrowIfNull(resultSelector);
ArgumentNullException.ThrowIfNull(resultSelector);

return Core(
{{~ for $j in 1..$i ~}}
{{ $ordinals[$j] }},
{{~ end ~}}
resultSelector);
resultSelector
);

static async global::System.Collections.Generic.IAsyncEnumerable<TResult> Core(
{{~ for $j in 1..$i ~}}
global::System.Collections.Generic.IAsyncEnumerable<T{{ $j }}> {{ $ordinals[$j] }},
{{~ end ~}}
global::System.Func<{{ for $j in 1..$i }}T{{ $j }}?, {{ end }}TResult> resultSelector,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
[EnumeratorCancellation] CancellationToken cancellationToken = default
)
{
{{~ for $j in 1..$i ~}}
await using var e{{ $j }} = {{ $ordinals[$j] }}.ConfigureAwait(false).WithCancellation(cancellationToken).GetAsyncEnumerator();
Expand All @@ -68,7 +70,7 @@ public static partial class AsyncSuperEnumerable
? e{{ $j }}.Current : default(T{{ $j }});
{{~ end ~}}

if (!f1 {{ for $j in 2..$i }}&& !f{{ $j }}{{ end }})
if (!f1{{ for $j in 2..$i }} && !f{{ $j }}{{ end }})
yield break;

yield return resultSelector(
Expand All @@ -86,23 +88,24 @@ public static partial class AsyncSuperEnumerable
/// will always be as long as the longest of input sequences where the
/// default value of each of the shorter sequence element types is used
/// for padding.
/// </summary>
/// <returns>A sequence of
/// </summary>
/// <returns>A sequence of
/// <see cref="global::System.ValueTuple{ {{~ for $j in 1..$i ~}}T{{$j}}{{ if !for.last }},{{ end }}{{ end }} }" />
/// containing corresponding elements from each of the sequences.</returns>
/// <remarks>
/// This method uses deferred execution and streams its results.
/// </remarks>
/// <exception cref="global::System.ArgumentNullException">Any of the input sequences is null.</exception>
/// containing corresponding elements from each of the sequences.</returns>
/// <remarks>
/// This method uses deferred execution and streams its results.
/// </remarks>
/// <exception cref="global::System.ArgumentNullException">Any of the input sequences is null.</exception>
{{~ for $j in 1..$i ~}}
/// <typeparam name="T{{ $j }}">The type of the elements of <paramref name="{{ $ordinals[$j] }}" />.</typeparam>
/// <typeparam name="T{{ $j }}">The type of the elements of <paramref name="{{ $ordinals[$j] }}" />.</typeparam>
/// <param name="{{ $ordinals[$j] }}">The {{ $ordinals[$j] }} sequence of elements.</param>
{{~ end ~}}
public static global::System.Collections.Generic.IAsyncEnumerable<({{~ for $j in 1..$i ~}}T{{ $j }}?{{ if !for.last }},{{ end }}{{ end }})>
public static global::System.Collections.Generic.IAsyncEnumerable<({{~ for $j in 1..$i ~}}T{{ $j }}?{{ if !for.last }},{{ end }}{{ end }})>
ZipLongest<{{~ for $j in 1..$i ~}}T{{ $j }}{{ if !for.last }},{{ end }}{{ end }}>(this
{{~ for $j in 1..$i ~}}
global::System.Collections.Generic.IAsyncEnumerable<T{{ $j }}> {{ $ordinals[$j] }}{{ if !for.last }},{{ end }}
{{~ end ~}}) =>
ZipLongest({{~ for $j in 1..$i ~}}{{ $ordinals[$j] }}, {{ end }}global::System.ValueTuple.Create);
{{ end ~}}
{{~ end ~}}
) => ZipLongest({{~ for $j in 1..$i ~}}{{ $ordinals[$j] }}, {{ end }}global::System.ValueTuple.Create);

{{~ end ~}}
}
Loading
Loading