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

Migrate ZipLongest to Source Generator #162

Merged
merged 8 commits into from
Jan 27, 2023
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
2 changes: 2 additions & 0 deletions Generators/SuperLinq.Async.Generator/EquiZip.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

namespace SuperLinq.Async;

#nullable enable

public static partial class AsyncSuperEnumerable
{
{{~ for $i in 2..4 ~}}
Expand Down
4 changes: 3 additions & 1 deletion Generators/SuperLinq.Async.Generator/Fold.sbntxt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace SuperLinq.Async;

#nullable enable

public static partial class AsyncSuperEnumerable
{
{{~ for $i in 1..16 ~}}
Expand Down Expand Up @@ -27,7 +29,7 @@ public static partial class AsyncSuperEnumerable
global::CommunityToolkit.Diagnostics.Guard.IsNotNull(source);
global::CommunityToolkit.Diagnostics.Guard.IsNotNull(folder);

var elements = await source.Take({{$i}} + 1).ToListAsync();
var elements = await source.Take({{$i}} + 1).ToListAsync().ConfigureAwait(false);
if (elements.Count != {{$i}})
global::CommunityToolkit.Diagnostics.ThrowHelper.ThrowInvalidOperationException(
$"Sequence contained an incorrect number of elements. (Expected: {{$i}}, Actual: {elements.Count})");
Expand Down
2 changes: 2 additions & 0 deletions Generators/SuperLinq.Async.Generator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
"EquiZip.g.cs", GenerateArgumentNamesTemplate(ThisAssembly.Resources.EquiZip.Text)));
context.RegisterPostInitializationOutput(ctx => ctx.AddSource(
"Fold.g.cs", GenerateArgumentNamesTemplate(ThisAssembly.Resources.Fold.Text)));
context.RegisterPostInitializationOutput(ctx => ctx.AddSource(
"ZipLongest.g.cs", GenerateArgumentNamesTemplate(ThisAssembly.Resources.ZipLongest.Text)));
}

private static SourceText GenerateArgumentNamesTemplate(string template)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,18 @@
</ItemGroup>

<ItemGroup>
<None Remove="*.sbntxt" />
<EmbeddedResource Include="*.sbntxt" Kind="Text" />
</ItemGroup>

<ItemGroup>
<Compile Include="../SuperLinq.Generator/ArgumentNames.cs" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="ZipLongest.sbntxt">
<Kind>Text</Kind>
</EmbeddedResource>
</ItemGroup>

</Project>
108 changes: 108 additions & 0 deletions Generators/SuperLinq.Async.Generator/ZipLongest.sbntxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
{{
$arity = arity
$ordinals = ordinals
$cardinals = cardinals
}}

namespace SuperLinq.Async;

#nullable enable

public static partial class AsyncSuperEnumerable
{
{{~ for $i in 2..4 ~}}
/// <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>
{{~ for $j in 1..$i ~}}
/// <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
{{~ 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)
{
{{~ for $j in 1..$i ~}}
global::CommunityToolkit.Diagnostics.Guard.IsNotNull({{ $ordinals[$j] }});
{{~ end ~}}

global::CommunityToolkit.Diagnostics.Guard.IsNotNull(resultSelector);

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

static async global::System.Collections.Generic.IAsyncEnumerable<TResult> _(
{{~ 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)
{
{{~ for $j in 1..$i ~}}
await using var e{{ $j }} = {{ $ordinals[$j] }}.ConfigureAwait(false).WithCancellation(cancellationToken).GetAsyncEnumerator();
var f{{ $j }} = true;
{{~ end ~}}

while (true)
{
{{~ for $j in 1..$i ~}}
var v{{ $j }} = (f{{ $j }} && (f{{ $j }} = await e{{ $j }}.MoveNextAsync()))
? e{{ $j }}.Current : default(T{{ $j }});
{{~ end ~}}

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

yield return resultSelector(
{{~ for $j in 1..$i ~}}
v{{$j}}{{ if !for.last }},{{ end }}
{{~ end ~}}
);
}
}
}

/// <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>
/// <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>
{{~ for $j in 1..$i ~}}
/// <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 }})>
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 ~}}
}
2 changes: 2 additions & 0 deletions Generators/SuperLinq.Generator/Aggregate.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

namespace SuperLinq;

#nullable enable

public static partial class SuperEnumerable
{
{{~ for $i in 2..($arity.size - 1) ~}}
Expand Down
2 changes: 2 additions & 0 deletions Generators/SuperLinq.Generator/Cartesian.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

namespace SuperLinq;

#nullable enable

public static partial class SuperEnumerable
{
{{~ for $i in 2..($arity.size - 1) ~}}
Expand Down
2 changes: 2 additions & 0 deletions Generators/SuperLinq.Generator/EquiZip.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

namespace SuperLinq;

#nullable enable

public static partial class SuperEnumerable
{
{{~ for $i in 2..4 ~}}
Expand Down
2 changes: 2 additions & 0 deletions Generators/SuperLinq.Generator/Fold.sbntxt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace SuperLinq;

#nullable enable

public static partial class SuperEnumerable
{
{{~ for $i in 1..16 ~}}
Expand Down
2 changes: 2 additions & 0 deletions Generators/SuperLinq.Generator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
"Fold.g.cs", GenerateArgumentNamesTemplate(ThisAssembly.Resources.Fold.Text)));
context.RegisterPostInitializationOutput(ctx => ctx.AddSource(
"ToDelimitedString.g.cs", ToDelimitedString.Generate()));
context.RegisterPostInitializationOutput(ctx => ctx.AddSource(
"ZipLongest.g.cs", GenerateArgumentNamesTemplate(ThisAssembly.Resources.ZipLongest.Text)));
}

private static SourceText GenerateArgumentNamesTemplate(string template)
Expand Down
1 change: 1 addition & 0 deletions Generators/SuperLinq.Generator/SuperLinq.Generator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
</ItemGroup>

<ItemGroup>
<None Remove="*.sbntxt" />
<EmbeddedResource Include="*.sbntxt" Kind="Text" />
</ItemGroup>

Expand Down
2 changes: 2 additions & 0 deletions Generators/SuperLinq.Generator/ToDelimitedString.sbntxt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace SuperLinq;

#nullable enable

public static partial class SuperEnumerable
{
{{~ for t in types ~}}
Expand Down
116 changes: 116 additions & 0 deletions Generators/SuperLinq.Generator/ZipLongest.sbntxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{{
$arity = arity
$ordinals = ordinals
$cardinals = cardinals
}}

namespace SuperLinq;

#nullable enable

public static partial class SuperEnumerable
{
private static bool DoRead<T>(bool flag, IEnumerator<T> iter, out T? value)
{
if (!flag || !iter.MoveNext())
{
value = default;
return false;
}

value = iter.Current;
return true;
}

{{~ for $i in 2..4 ~}}
/// <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>
{{~ for $j in 1..$i ~}}
/// <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.IEnumerable<TResult> ZipLongest<{{ for $j in 1..$i }}T{{ $j }}, {{ end }}TResult>(this
{{~ for $j in 1..$i ~}}
global::System.Collections.Generic.IEnumerable<T{{ $j }}> {{ $ordinals[$j] }},
{{~ end ~}}
global::System.Func<{{ for $j in 1..$i }}T{{ $j }}?, {{ end }}TResult> resultSelector)
{
{{~ for $j in 1..$i ~}}
global::CommunityToolkit.Diagnostics.Guard.IsNotNull({{ $ordinals[$j] }});
{{~ end ~}}

global::CommunityToolkit.Diagnostics.Guard.IsNotNull(resultSelector);

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

static global::System.Collections.Generic.IEnumerable<TResult> _(
{{~ for $j in 1..$i ~}}
global::System.Collections.Generic.IEnumerable<T{{ $j }}> {{ $ordinals[$j] }},
{{~ end ~}}
global::System.Func<{{ for $j in 1..$i }}T{{ $j }}?, {{ end }}TResult> resultSelector)
{
{{~ for $j in 1..$i ~}}
using var e{{ $j }} = {{ $ordinals[$j] }}.GetEnumerator();
var f{{ $j }} = true;
{{~ end ~}}

while (
{{~ for $j in 1..$i ~}}
{{ if !for.first }}|{{ end }}
(f{{$j}} = DoRead(f{{$j}}, e{{$j}}, out var v{{$j}}))
{{~ end ~}}
)
{
yield return resultSelector(
{{~ for $j in 1..$i ~}}
v{{$j}}{{ if !for.last }},{{ end }}
{{~ end ~}}
);
}
}
}

/// <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>
/// <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>
{{~ for $j in 1..$i ~}}
/// <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.IEnumerable<({{~ 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.IEnumerable<T{{ $j }}> {{ $ordinals[$j] }}{{ if !for.last }},{{ end }}
{{~ end ~}}) =>
ZipLongest({{~ for $j in 1..$i ~}}{{ $ordinals[$j] }}, {{ end }}global::System.ValueTuple.Create);
{{ end ~}}
}
Loading