diff --git a/MoreLinq/Enumerator.cs b/MoreLinq/Enumerator.cs
new file mode 100644
index 000000000..5e3897754
--- /dev/null
+++ b/MoreLinq/Enumerator.cs
@@ -0,0 +1,66 @@
+#region License and Terms
+// MoreLINQ - Extensions to LINQ to Objects
+// Copyright (c) 2019 Pierre Lando. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+namespace MoreLinq
+{
+ using System.Collections.Generic;
+
+ static class Enumerator
+ {
+ ///
+ ///
+ /// Move the to the next position and put the
+ /// new current value into .
+ ///
+ /// If the has no more element it's disposed and
+ /// set to null, and is set to default.
+ ///
+ /// If the is null the method return immediately
+ /// and is set to null.
+ ///
+ /// The type of element that are enumerated.
+ /// The enumerator to iterate or dispose.
+ /// The new current value of or
+ /// default if has no more element.
+ ///
+ ///
+ /// Because and may both be modified
+ /// they are both passed by reference.
+ ///
+ /// A bool value indicating if the enumerator has moved to the next element.
+
+ public static bool TryRead(ref IEnumerator? enumerator, out T? item)
+ {
+ if (enumerator is null)
+ {
+ item = default;
+ return false;
+ }
+
+ if (enumerator.MoveNext())
+ {
+ item = enumerator.Current;
+ return true;
+ }
+
+ enumerator.Dispose();
+ enumerator = null;
+ item = default;
+ return false;
+ }
+ }
+}
diff --git a/MoreLinq/EquiZip.cs b/MoreLinq/EquiZip.cs
deleted file mode 100644
index 61212f122..000000000
--- a/MoreLinq/EquiZip.cs
+++ /dev/null
@@ -1,223 +0,0 @@
-#region License and Terms
-// MoreLINQ - Extensions to LINQ to Objects
-// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#endregion
-
-namespace MoreLinq
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
-
- static partial class MoreEnumerable
- {
- ///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. An exception is thrown
- /// if the input sequences are of different lengths.
- ///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
- ///
- /// Function to apply to each pair of elements.
- ///
- /// A sequence that contains elements of the two input sequences,
- /// combined by .
- ///
- ///
- /// The input sequences are of different lengths.
- ///
- ///
- /// , , or is .
- ///
- ///
- /// n + l);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1A",
- /// "2B", "3C", "4D" in turn.
- ///
- ///
- /// This operator uses deferred execution and streams its results.
- ///
-
- public static IEnumerable EquiZip(
- this IEnumerable first,
- IEnumerable second,
- Func resultSelector)
- {
- if (first == null) throw new ArgumentNullException(nameof(first));
- if (second == null) throw new ArgumentNullException(nameof(second));
- if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
-
- return EquiZipImpl(first, second, null, null, (a, b, _, _) => resultSelector(a, b));
- }
-
- ///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. An exception is thrown
- /// if the input sequences are of different lengths.
- ///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in third sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
- ///
- /// Function to apply to each triplet of elements.
- ///
- /// A sequence that contains elements of the three input sequences,
- /// combined by .
- ///
- ///
- /// The input sequences are of different lengths.
- ///
- ///
- /// , , , or is .
- ///
- ///
- /// n + l + c);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1Aa",
- /// "2Bb", "3Cc", "4Dd" in turn.
- ///
- ///
- /// This operator uses deferred execution and streams its results.
- ///
-
- public static IEnumerable EquiZip(
- this IEnumerable first,
- IEnumerable second, IEnumerable third,
- Func resultSelector)
- {
- if (first == null) throw new ArgumentNullException(nameof(first));
- if (second == null) throw new ArgumentNullException(nameof(second));
- if (third == null) throw new ArgumentNullException(nameof(third));
- if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
-
- return EquiZipImpl(first, second, third, null, (a, b, c, _) => resultSelector(a, b, c));
- }
-
- ///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. An exception is thrown
- /// if the input sequences are of different lengths.
- ///
- /// Type of elements in first sequence
- /// Type of elements in second sequence
- /// Type of elements in third sequence
- /// Type of elements in fourth sequence
- /// Type of elements in result sequence
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
- /// The fourth sequence.
- ///
- /// Function to apply to each quadruplet of elements.
- ///
- /// A sequence that contains elements of the four input sequences,
- /// combined by .
- ///
- ///
- /// The input sequences are of different lengths.
- ///
- ///
- /// , , , , or is .
- ///
- ///
- /// n + l + c + f);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1AaTrue",
- /// "2BbFalse", "3CcTrue", "4DdFalse" in turn.
- ///
- ///
- /// This operator uses deferred execution and streams its results.
- ///
-
- public static IEnumerable EquiZip(
- this IEnumerable first,
- IEnumerable second, IEnumerable third, IEnumerable fourth,
- Func resultSelector)
- {
- if (first == null) throw new ArgumentNullException(nameof(first));
- if (second == null) throw new ArgumentNullException(nameof(second));
- if (third == null) throw new ArgumentNullException(nameof(third));
- if (fourth == null) throw new ArgumentNullException(nameof(fourth));
- if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
-
- return EquiZipImpl(first, second, third, fourth, resultSelector);
- }
-
- static IEnumerable EquiZipImpl(
- IEnumerable s1,
- IEnumerable s2,
- IEnumerable? s3,
- IEnumerable? s4,
- Func resultSelector)
- {
- const int zero = 0, one = 1;
-
- var limit = 1 + (s3 != null ? one : zero)
- + (s4 != null ? one : zero);
-
- return ZipImpl(s1, s2, s3, s4, resultSelector, limit, enumerators =>
- {
- var i = enumerators.Index().First(x => x.Value == null).Key;
- return new InvalidOperationException(OrdinalNumbers[i] + " sequence too short.");
- });
- }
-
- static readonly string[] OrdinalNumbers =
- {
- "First",
- "Second",
- "Third",
- "Fourth",
- // "Fifth",
- // "Sixth",
- // "Seventh",
- // "Eighth",
- // "Ninth",
- // "Tenth",
- // "Eleventh",
- // "Twelfth",
- // "Thirteenth",
- // "Fourteenth",
- // "Fifteenth",
- // "Sixteenth",
- };
- }
-}
diff --git a/MoreLinq/EquiZip.g.cs b/MoreLinq/EquiZip.g.cs
new file mode 100644
index 000000000..15b74bc84
--- /dev/null
+++ b/MoreLinq/EquiZip.g.cs
@@ -0,0 +1,230 @@
+#region License and Terms
+// MoreLINQ - Extensions to LINQ to Objects
+// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+namespace MoreLinq
+{
+ using System;
+ using System.Collections.Generic;
+
+ static partial class MoreEnumerable
+ {
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of two sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence has the same length as the input sequences.
+ /// If the input sequences are of different lengths, an exception is thrown.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ ///
+ /// A function that specifies how to merge the elements from the two sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of two input sequences.
+ ///
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ /// The input sequences are of different lengths.
+ ///
+ /// This operator uses deferred execution and streams its results.
+
+ public static IEnumerable EquiZip(
+ this IEnumerable first,
+ IEnumerable second,
+ Func resultSelector)
+ {
+ if (first == null) throw new ArgumentNullException(nameof(first));
+ if (second == null) throw new ArgumentNullException(nameof(second));
+ if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
+
+ return _(); IEnumerable _()
+ {
+ using var e1 = first.GetEnumerator();
+ using var e2 = second.GetEnumerator();
+
+ for (;;)
+ {
+ if (e1.MoveNext())
+ {
+ if (e2.MoveNext())
+ yield return resultSelector(e1.Current, e2.Current);
+ else
+ break;
+ }
+ else
+ {
+ if (e2.MoveNext())
+ break;
+ else
+ yield break;
+ }
+ }
+
+ throw new InvalidOperationException("The input sequences are of different lengths.");
+ }
+ }
+
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of three sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence has the same length as the input sequences.
+ /// If the input sequences are of different lengths, an exception is thrown.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
+ ///
+ /// A function that specifies how to merge the elements from the three sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of three input sequences.
+ ///
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ /// The input sequences are of different lengths.
+ ///
+ /// This operator uses deferred execution and streams its results.
+
+ public static IEnumerable EquiZip(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ Func resultSelector)
+ {
+ if (first == null) throw new ArgumentNullException(nameof(first));
+ if (second == null) throw new ArgumentNullException(nameof(second));
+ if (third == null) throw new ArgumentNullException(nameof(third));
+ if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
+
+ return _(); IEnumerable _()
+ {
+ using var e1 = first.GetEnumerator();
+ using var e2 = second.GetEnumerator();
+ using var e3 = third.GetEnumerator();
+
+ for (;;)
+ {
+ if (e1.MoveNext())
+ {
+ if (e2.MoveNext() && e3.MoveNext())
+ yield return resultSelector(e1.Current, e2.Current, e3.Current);
+ else
+ break;
+ }
+ else
+ {
+ if (e2.MoveNext() || e3.MoveNext())
+ break;
+ else
+ yield break;
+ }
+ }
+
+ throw new InvalidOperationException("The input sequences are of different lengths.");
+ }
+ }
+
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of four sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence has the same length as the input sequences.
+ /// If the input sequences are of different lengths, an exception is thrown.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the fourth input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
+ /// The fourth sequence to merge.
+ ///
+ /// A function that specifies how to merge the elements from the four sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of four input sequences.
+ ///
+ /// ,
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ /// The input sequences are of different lengths.
+ ///
+ /// This operator uses deferred execution and streams its results.
+
+ public static IEnumerable EquiZip(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ IEnumerable fourth,
+ Func resultSelector)
+ {
+ if (first == null) throw new ArgumentNullException(nameof(first));
+ if (second == null) throw new ArgumentNullException(nameof(second));
+ if (third == null) throw new ArgumentNullException(nameof(third));
+ if (fourth == null) throw new ArgumentNullException(nameof(fourth));
+ if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
+
+ return _(); IEnumerable _()
+ {
+ using var e1 = first.GetEnumerator();
+ using var e2 = second.GetEnumerator();
+ using var e3 = third.GetEnumerator();
+ using var e4 = fourth.GetEnumerator();
+
+ for (;;)
+ {
+ if (e1.MoveNext())
+ {
+ if (e2.MoveNext() && e3.MoveNext() && e4.MoveNext())
+ yield return resultSelector(e1.Current, e2.Current, e3.Current, e4.Current);
+ else
+ break;
+ }
+ else
+ {
+ if (e2.MoveNext() || e3.MoveNext() || e4.MoveNext())
+ break;
+ else
+ yield break;
+ }
+ }
+
+ throw new InvalidOperationException("The input sequences are of different lengths.");
+ }
+ }
+
+ }
+}
diff --git a/MoreLinq/EquiZip.g.tt b/MoreLinq/EquiZip.g.tt
new file mode 100644
index 000000000..2746a2071
--- /dev/null
+++ b/MoreLinq/EquiZip.g.tt
@@ -0,0 +1,142 @@
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ output extension=".cs" #>
+<#@ assembly name="System.Core" #>
+<#@ import namespace="System.Globalization" #>
+<#@ import namespace="System.Linq" #>
+#region License and Terms
+// MoreLINQ - Extensions to LINQ to Objects
+// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+<#
+ var ordinals = new[]
+ {
+ string.Empty,
+ "First", "Second", "Third", "Fourth",
+ "Fifth", "Sixth", "Seventh", "Eighth"
+ };
+
+ var cardinals = new[]
+ {
+ "zero",
+ "one", "two", "three", "four",
+ "five", "six", "seven", "eight"
+ };
+
+ var overloads =
+ from argCount in Enumerable.Range(2, 3)
+ from args in new[]
+ {
+ from argPosition in Enumerable.Range(1, argCount)
+ select new
+ {
+ IsFirst = argPosition == 1,
+ IsLast = argPosition == argCount,
+ Name = ordinals[argPosition].ToLower(),
+ ordinal = ordinals[argPosition].ToLower(),
+ Type = $"T{ordinals[argPosition]}",
+ // Objects associated with the argument
+ Enumerator = $"e{argPosition}",
+ Value = $"v{argPosition}"
+ }
+ }
+ select new
+ {
+ Arguments = args.ToList(),
+ cardinal = cardinals[argCount],
+ TParams = string.Join(", ", from arg in args select arg.Type)
+ };
+#>
+namespace MoreLinq
+{
+ using System;
+ using System.Collections.Generic;
+
+ static partial class MoreEnumerable
+ {
+<# foreach (var o in overloads)
+ {
+#>
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of <#= o.cardinal #> sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence has the same length as the input sequences.
+ /// If the input sequences are of different lengths, an exception is thrown.
+ ///
+<# foreach (var arg in o.Arguments) { #>
+ /// The type of the elements of the <#= arg.ordinal #> input sequence.
+<# } #>
+ /// The type of the elements of the result sequence.
+<# foreach (var arg in o.Arguments) { #>
+ /// The <#= arg.ordinal #> sequence to merge.
+<# } #>
+ ///
+ /// A function that specifies how to merge the elements from the <#= o.cardinal #> sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of <#= o.cardinal #> input sequences.
+ ///
+<# foreach (var arg in o.Arguments) { #>
+ /// <#= arg.IsLast ? " or" : "," #>
+<# } #>
+ /// is null
.
+ ///
+ /// The input sequences are of different lengths.
+ ///
+ /// This operator uses deferred execution and streams its results.
+
+ public static IEnumerable EquiZip<<#= o.TParams #>, TResult>(
+<# foreach (var arg in o.Arguments) { #>
+ <#= arg.IsFirst ? "this " : "" #>IEnumerable<<#= arg.Type #>> <#= arg.Name #>,
+<# } #>
+ Func<<#= o.TParams #>, TResult> resultSelector)
+ {
+<# foreach (var arg in o.Arguments) { #>
+ if (<#= arg.Name #> == null) throw new ArgumentNullException(nameof(<#= arg.Name #>));
+<# } #>
+ if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
+
+ return _(); IEnumerable _()
+ {
+<# foreach (var arg in o.Arguments) { #>
+ using var <#= arg.Enumerator #> = <#= arg.Name #>.GetEnumerator();
+<# } #>
+
+ for (;;)
+ {
+ if (<#= o.Arguments.First().Enumerator #>.MoveNext())
+ {
+ if (<# foreach (var arg in o.Arguments.Skip(1)) { #><#= arg.Enumerator #>.MoveNext()<#= arg.IsLast ? "" : " && " #><# } #>)
+ yield return resultSelector(<# foreach (var arg in o.Arguments) { #><#= arg.Enumerator #>.Current<#= arg.IsLast ? "" : ", " #><# } #>);
+ else
+ break;
+ }
+ else
+ {
+ if (<# foreach (var arg in o.Arguments.Skip(1)) { #><#= arg.Enumerator #>.MoveNext()<#= arg.IsLast ? "" : " || " #><# } #>)
+ break;
+ else
+ yield break;
+ }
+ }
+
+ throw new InvalidOperationException("The input sequences are of different lengths.");
+ }
+ }
+
+<# } #>
+ }
+}
diff --git a/MoreLinq/Extensions.g.cs b/MoreLinq/Extensions.g.cs
index a5ca2ac81..7c09d1c24 100644
--- a/MoreLinq/Extensions.g.cs
+++ b/MoreLinq/Extensions.g.cs
@@ -1338,40 +1338,30 @@ public static bool EndsWith(this IEnumerable first, IEnumerable second,
public static partial class EquiZipExtension
{
///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. An exception is thrown
- /// if the input sequences are of different lengths.
- ///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
+ ///
+ /// Applies a specified function to the corresponding elements of two sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence has the same length as the input sequences.
+ /// If the input sequences are of different lengths, an exception is thrown.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
///
- /// Function to apply to each pair of elements.
+ /// A function that specifies how to merge the elements from the two sequences.
///
- /// A sequence that contains elements of the two input sequences,
- /// combined by .
- ///
- ///
- /// The input sequences are of different lengths.
- ///
+ /// An IEnumerable
that contains merged elements of two input sequences.
///
- /// , , or is .
- ///
- ///
- /// n + l);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1A",
- /// "2B", "3C", "4D" in turn.
- ///
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ /// The input sequences are of different lengths.
///
- /// This operator uses deferred execution and streams its results.
- ///
+ /// This operator uses deferred execution and streams its results.
public static IEnumerable EquiZip(
this IEnumerable first,
@@ -1380,98 +1370,79 @@ public static IEnumerable EquiZip(
=> MoreEnumerable.EquiZip(first, second, resultSelector);
///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. An exception is thrown
- /// if the input sequences are of different lengths.
+ ///
+ /// Applies a specified function to the corresponding elements of three sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence has the same length as the input sequences.
+ /// If the input sequences are of different lengths, an exception is thrown.
///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in third sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
///
- /// Function to apply to each triplet of elements.
+ /// A function that specifies how to merge the elements from the three sequences.
///
- /// A sequence that contains elements of the three input sequences,
- /// combined by .
- ///
- ///
- /// The input sequences are of different lengths.
- ///
+ /// An IEnumerable
that contains merged elements of three input sequences.
///
- /// , , , or is .
- ///
- ///
- /// n + l + c);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1Aa",
- /// "2Bb", "3Cc", "4Dd" in turn.
- ///
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ /// The input sequences are of different lengths.
///
- /// This operator uses deferred execution and streams its results.
- ///
+ /// This operator uses deferred execution and streams its results.
- public static IEnumerable EquiZip(
- this IEnumerable first,
- IEnumerable second, IEnumerable third,
- Func resultSelector)
+ public static IEnumerable EquiZip(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ Func resultSelector)
=> MoreEnumerable.EquiZip(first, second, third, resultSelector);
///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. An exception is thrown
- /// if the input sequences are of different lengths.
+ ///
+ /// Applies a specified function to the corresponding elements of four sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence has the same length as the input sequences.
+ /// If the input sequences are of different lengths, an exception is thrown.
///
- /// Type of elements in first sequence
- /// Type of elements in second sequence
- /// Type of elements in third sequence
- /// Type of elements in fourth sequence
- /// Type of elements in result sequence
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
- /// The fourth sequence.
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the fourth input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
+ /// The fourth sequence to merge.
///
- /// Function to apply to each quadruplet of elements.
+ /// A function that specifies how to merge the elements from the four sequences.
///
- /// A sequence that contains elements of the four input sequences,
- /// combined by .
- ///
- ///
- /// The input sequences are of different lengths.
- ///
+ /// An IEnumerable
that contains merged elements of four input sequences.
///
- /// , , , , or is .
- ///
- ///
- /// n + l + c + f);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1AaTrue",
- /// "2BbFalse", "3CcTrue", "4DdFalse" in turn.
- ///
+ /// ,
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ /// The input sequences are of different lengths.
///
- /// This operator uses deferred execution and streams its results.
- ///
+ /// This operator uses deferred execution and streams its results.
- public static IEnumerable EquiZip(
- this IEnumerable first,
- IEnumerable second, IEnumerable third, IEnumerable fourth,
- Func resultSelector)
+ public static IEnumerable EquiZip(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ IEnumerable fourth,
+ Func resultSelector)
=> MoreEnumerable.EquiZip(first, second, third, fourth, resultSelector);
}
@@ -6872,140 +6843,117 @@ public static IEnumerable> WindowRight(this IEnumerable<
public static partial class ZipLongestExtension
{
///
- /// 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.
- ///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
+ ///
+ /// Applies a specified function to the corresponding elements of two sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as long as the longest of the input sequences.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
///
- /// Function to apply to each pair of elements.
+ /// A function that specifies how to merge the elements from the two sequences.
///
- /// A sequence that contains elements of the two input sequences,
- /// combined by .
- ///
+ /// An IEnumerable
that contains merged elements of two input sequences.
///
- /// , , or is .
- ///
- ///
- /// n + l);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1A",
- /// "2B", "3C", "0D" in turn.
- ///
+ /// ,
+ /// or
+ /// is null
.
///
- /// This operator uses deferred execution and streams its results.
+ ///
+ /// If the input sequences are of different lengths, the default values of the types
+ /// of the elements of the shortests sequences are used for padding.
+ ///
+ /// This operator uses deferred execution and streams its results.
///
public static IEnumerable ZipLongest(
this IEnumerable first,
IEnumerable second,
- Func resultSelector)
+ Func resultSelector)
=> MoreEnumerable.ZipLongest(first, second, resultSelector);
///
- /// 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.
+ ///
+ /// Applies a specified function to the corresponding elements of three sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as long as the longest of the input sequences.
///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in third sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
///
- /// Function to apply to each triplet of elements.
+ /// A function that specifies how to merge the elements from the three sequences.
///
- /// A sequence that contains elements of the three input sequences,
- /// combined by .
- ///
+ /// An IEnumerable
that contains merged elements of three input sequences.
///
- /// , , , or is .
- ///
- ///
- /// n + l + c);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1Aa",
- /// "2Bb", "3Cc", "0Dd", "0e" in turn.
- ///
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
///
- /// This operator uses deferred execution and streams its results.
+ ///
+ /// If the input sequences are of different lengths, the default values of the types
+ /// of the elements of the shortests sequences are used for padding.
+ ///
+ /// This operator uses deferred execution and streams its results.
///
- public static IEnumerable ZipLongest(
- this IEnumerable first,
- IEnumerable second,
- IEnumerable third,
- Func resultSelector)
+ public static IEnumerable ZipLongest(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ Func resultSelector)
=> MoreEnumerable.ZipLongest(first, second, third, resultSelector);
///
- /// 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.
- ///
- /// Type of elements in first sequence
- /// Type of elements in second sequence
- /// Type of elements in third sequence
- /// Type of elements in fourth sequence
- /// Type of elements in result sequence
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
- /// The fourth sequence.
+ ///
+ /// Applies a specified function to the corresponding elements of four sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as long as the longest of the input sequences.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the fourth input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
+ /// The fourth sequence to merge.
///
- /// Function to apply to each quadruplet of elements.
+ /// A function that specifies how to merge the elements from the four sequences.
///
- /// A sequence that contains elements of the four input sequences,
- /// combined by .
- ///
+ /// An IEnumerable
that contains merged elements of four input sequences.
///
- /// , , , , or is .
- ///
- ///
- /// n + l + c + f);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1AaTrue",
- /// "2BbFalse", "3CcTrue", "0DdFalse", "0eTrue", "0\0False" in turn.
- ///
+ /// ,
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
///
- /// This operator uses deferred execution and streams its results.
+ ///
+ /// If the input sequences are of different lengths, the default values of the types
+ /// of the elements of the shortests sequences are used for padding.
+ ///
+ /// This operator uses deferred execution and streams its results.
///
- public static IEnumerable ZipLongest(
- this IEnumerable first,
- IEnumerable second,
- IEnumerable third,
- IEnumerable fourth,
- Func resultSelector)
+ public static IEnumerable ZipLongest(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ IEnumerable fourth,
+ Func resultSelector)
=> MoreEnumerable.ZipLongest(first, second, third, fourth, resultSelector);
}
@@ -7016,38 +6964,30 @@ public static IEnumerable ZipLongest(
public static partial class ZipShortestExtension
{
///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. The resulting sequence
- /// is as short as the shortest input sequence.
+ ///
+ /// Applies a specified function to the corresponding elements of two sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as short as the shortest of the input sequences.
///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
///
- /// Function to apply to each pair of elements.
+ /// A function that specifies how to merge the elements from the two sequences.
///
- /// A projection of tuples, where each tuple contains the N-th element
- /// from each of the argument sequences.
- ///
+ /// An IEnumerable
that contains merged elements of two input sequences.
///
- /// , , or is .
- ///
- /// n + l);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1A", "2B", "3C", in turn.
- ///
+ /// ,
+ /// or
+ /// is null
.
///
///
- /// If the input sequences are of different lengths, the result sequence
- /// is terminated as soon as the shortest input sequence is exhausted
- /// and remainder elements from the longer sequences are never consumed.
- ///
+ /// If the input sequences are of different lengths, the resulting sequence is terminated
+ /// as soon as the shortest input sequence reaches its end.
+ /// The remaining elements of the other sequences are never consumed.
///
/// This operator uses deferred execution and streams its results.
///
@@ -7059,105 +6999,85 @@ public static IEnumerable ZipShortest(
=> MoreEnumerable.ZipShortest(first, second, resultSelector);
///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. The resulting sequence
- /// is as short as the shortest input sequence.
+ ///
+ /// Applies a specified function to the corresponding elements of three sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as short as the shortest of the input sequences.
///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in third sequence.
- /// Type of elements in result sequence.
- /// First sequence
- /// Second sequence
- /// Third sequence
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
///
- /// Function to apply to each triplet of elements.
+ /// A function that specifies how to merge the elements from the three sequences.
///
- /// A projection of tuples, where each tuple contains the N-th element
- /// from each of the argument sequences.
+ /// An IEnumerable
that contains merged elements of three input sequences.
///
- /// , , , or is .
- ///
- ///
- /// c + n + l);
- /// ]]>
- /// The zipped variable, when iterated over, will yield
- /// "98A", "100B", "102C", in turn.
- ///
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
///
///
- /// If the input sequences are of different lengths, the result sequence
- /// is terminated as soon as the shortest input sequence is exhausted
- /// and remainder elements from the longer sequences are never consumed.
- ///
+ /// If the input sequences are of different lengths, the resulting sequence is terminated
+ /// as soon as the shortest input sequence reaches its end.
+ /// The remaining elements of the other sequences are never consumed.
///
/// This operator uses deferred execution and streams its results.
///
- public static IEnumerable ZipShortest(
- this IEnumerable first,
- IEnumerable second,
- IEnumerable third,
- Func resultSelector)
+ public static IEnumerable ZipShortest(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ Func resultSelector)
=> MoreEnumerable.ZipShortest(first, second, third, resultSelector);
///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. The resulting sequence
- /// is as short as the shortest input sequence.
+ ///
+ /// Applies a specified function to the corresponding elements of four sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as short as the shortest of the input sequences.
///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in third sequence.
- /// Type of elements in fourth sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
- /// The fourth sequence.
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the fourth input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
+ /// The fourth sequence to merge.
///
- /// Function to apply to each quadruplet of elements.
+ /// A function that specifies how to merge the elements from the four sequences.
///
- /// A projection of tuples, where each tuple contains the N-th element
- /// from each of the argument sequences.
+ /// An IEnumerable
that contains merged elements of four input sequences.
///
- /// , , , , or is .
- ///
- ///
- /// n + l + c + f);
- /// ]]>
- /// The zipped variable, when iterated over, will yield
- /// "1AaTrue", "2BbFalse" in turn.
- ///
+ /// ,
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
///
///
- /// If the input sequences are of different lengths, the result sequence
- /// is terminated as soon as the shortest input sequence is exhausted
- /// and remainder elements from the longer sequences are never consumed.
- ///
+ /// If the input sequences are of different lengths, the resulting sequence is terminated
+ /// as soon as the shortest input sequence reaches its end.
+ /// The remaining elements of the other sequences are never consumed.
///
/// This operator uses deferred execution and streams its results.
///
- public static IEnumerable ZipShortest(
- this IEnumerable first,
- IEnumerable second,
- IEnumerable third,
- IEnumerable fourth,
- Func resultSelector)
+ public static IEnumerable ZipShortest(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ IEnumerable fourth,
+ Func resultSelector)
=> MoreEnumerable.ZipShortest(first, second, third, fourth, resultSelector);
}
diff --git a/MoreLinq/MoreLinq.csproj b/MoreLinq/MoreLinq.csproj
index a34d230da..ae09a3c97 100644
--- a/MoreLinq/MoreLinq.csproj
+++ b/MoreLinq/MoreLinq.csproj
@@ -164,6 +164,10 @@
TextTemplatingFileGenerator
Cartesian.g.cs
+
+ TextTemplatingFileGenerator
+ EquiZip.g.cs
+
Aggregate.g.cs
TextTemplatingFileGenerator
@@ -176,6 +180,14 @@
TextTemplatingFileGenerator
ToDelimitedString.g.cs
+
+ TextTemplatingFileGenerator
+ ZipLongest.g.cs
+
+
+ TextTemplatingFileGenerator
+ ZipShortest.g.cs
+
@@ -221,6 +233,11 @@
True
Cartesian.g.tt
+
+ True
+ True
+ EquiZip.g.tt
+
True
True
@@ -244,6 +261,16 @@
True
ToDelimitedString.g.tt
+
+ True
+ True
+ ZipLongest.g.tt
+
+
+ True
+ True
+ ZipShortest.g.tt
+
diff --git a/MoreLinq/ZipImpl.cs b/MoreLinq/ZipImpl.cs
deleted file mode 100644
index 1f008a1dc..000000000
--- a/MoreLinq/ZipImpl.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-#region License and Terms
-// MoreLINQ - Extensions to LINQ to Objects
-// Copyright (c) 2018 Leandro F. Vieira (leandromoh). All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#endregion
-
-namespace MoreLinq
-{
- using System;
- using System.Collections.Generic;
- using System.Collections;
-
- static partial class MoreEnumerable
- {
- delegate TResult Folder(params T[] args);
-
- static IEnumerable ZipImpl(
- IEnumerable s1,
- IEnumerable s2,
- IEnumerable? s3,
- IEnumerable? s4,
- Func resultSelector,
- int limit,
- Folder? errorSelector = null)
- {
- IEnumerator? e1 = null;
- IEnumerator? e2 = null;
- IEnumerator? e3 = null;
- IEnumerator? e4 = null;
- var terminations = 0;
-
- try
- {
- e1 = s1 .GetEnumerator();
- e2 = s2 .GetEnumerator();
- e3 = s3?.GetEnumerator();
- e4 = s4?.GetEnumerator();
-
- while (true)
- {
- var n = 0;
- var v1 = Read(ref e1, ++n);
- var v2 = Read(ref e2, ++n);
- var v3 = Read(ref e3, ++n);
- var v4 = Read(ref e4, ++n);
-
- if (terminations <= limit)
- yield return resultSelector(v1, v2, v3, v4);
- else
- yield break;
- }
- }
- finally
- {
- e1?.Dispose();
- e2?.Dispose();
- e3?.Dispose();
- e4?.Dispose();
- }
-
- T Read(ref IEnumerator? e, int n)
- {
- if (e == null || terminations > limit)
- return default!;
-
- T value;
- if (e.MoveNext())
- {
- value = e.Current;
- }
- else
- {
- e.Dispose();
- e = null;
- terminations++;
- value = default!;
- }
-
- if (errorSelector != null && terminations > 0 && terminations < n)
- throw errorSelector(e1, e2, e3, e4);
-
- return value;
- }
- }
- }
-}
diff --git a/MoreLinq/ZipLongest.cs b/MoreLinq/ZipLongest.cs
deleted file mode 100644
index 38e5fdefc..000000000
--- a/MoreLinq/ZipLongest.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-#region License and Terms
-// MoreLINQ - Extensions to LINQ to Objects
-// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#endregion
-
-namespace MoreLinq
-{
- using System;
- using System.Collections.Generic;
-
- static partial class MoreEnumerable
- {
- ///
- /// 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.
- ///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
- ///
- /// Function to apply to each pair of elements.
- ///
- /// A sequence that contains elements of the two input sequences,
- /// combined by .
- ///
- ///
- /// , , or is .
- ///
- ///
- /// n + l);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1A",
- /// "2B", "3C", "0D" in turn.
- ///
- ///
- /// This operator uses deferred execution and streams its results.
- ///
-
- public static IEnumerable ZipLongest(
- this IEnumerable first,
- IEnumerable second,
- Func resultSelector)
- {
- if (first == null) throw new ArgumentNullException(nameof(first));
- if (second == null) throw new ArgumentNullException(nameof(second));
- if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
-
- return ZipImpl(first, second, null, null, (a, b, _, _) => resultSelector(a, b), 1);
- }
-
- ///
- /// 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.
- ///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in third sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
- ///
- /// Function to apply to each triplet of elements.
- ///
- /// A sequence that contains elements of the three input sequences,
- /// combined by .
- ///
- ///
- /// , , , or is .
- ///
- ///
- /// n + l + c);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1Aa",
- /// "2Bb", "3Cc", "0Dd", "0e" in turn.
- ///
- ///
- /// This operator uses deferred execution and streams its results.
- ///
-
- public static IEnumerable ZipLongest(
- this IEnumerable first,
- IEnumerable second,
- IEnumerable third,
- Func resultSelector)
- {
- if (first == null) throw new ArgumentNullException(nameof(first));
- if (second == null) throw new ArgumentNullException(nameof(second));
- if (third == null) throw new ArgumentNullException(nameof(third));
- if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
-
- return ZipImpl(first, second, third, null, (a, b, c, _) => resultSelector(a, b, c), 2);
- }
-
- ///
- /// 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.
- ///
- /// Type of elements in first sequence
- /// Type of elements in second sequence
- /// Type of elements in third sequence
- /// Type of elements in fourth sequence
- /// Type of elements in result sequence
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
- /// The fourth sequence.
- ///
- /// Function to apply to each quadruplet of elements.
- ///
- /// A sequence that contains elements of the four input sequences,
- /// combined by .
- ///
- ///
- /// , , , , or is .
- ///
- ///
- /// n + l + c + f);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1AaTrue",
- /// "2BbFalse", "3CcTrue", "0DdFalse", "0eTrue", "0\0False" in turn.
- ///
- ///
- /// This operator uses deferred execution and streams its results.
- ///
-
- public static IEnumerable ZipLongest(
- this IEnumerable first,
- IEnumerable second,
- IEnumerable third,
- IEnumerable fourth,
- Func resultSelector)
- {
- if (first == null) throw new ArgumentNullException(nameof(first));
- if (second == null) throw new ArgumentNullException(nameof(second));
- if (third == null) throw new ArgumentNullException(nameof(third));
- if (fourth == null) throw new ArgumentNullException(nameof(fourth));
- if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
-
- return ZipImpl(first, second, third, fourth, resultSelector, 3);
- }
- }
-}
diff --git a/MoreLinq/ZipLongest.g.cs b/MoreLinq/ZipLongest.g.cs
new file mode 100644
index 000000000..0ad199529
--- /dev/null
+++ b/MoreLinq/ZipLongest.g.cs
@@ -0,0 +1,242 @@
+#region License and Terms
+// MoreLINQ - Extensions to LINQ to Objects
+// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+namespace MoreLinq
+{
+ using System;
+ using System.Collections.Generic;
+
+ static partial class MoreEnumerable
+ {
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of two sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as long as the longest of the input sequences.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ ///
+ /// A function that specifies how to merge the elements from the two sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of two input sequences.
+ ///
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ ///
+ /// If the input sequences are of different lengths, the default values of the types
+ /// of the elements of the shortests sequences are used for padding.
+ ///
+ /// This operator uses deferred execution and streams its results.
+ ///
+
+ public static IEnumerable ZipLongest(
+ this IEnumerable first,
+ IEnumerable second,
+ Func resultSelector)
+ {
+ if (first == null) throw new ArgumentNullException(nameof(first));
+ if (second == null) throw new ArgumentNullException(nameof(second));
+ if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
+
+ return _(); IEnumerable _()
+ {
+ IEnumerator e1 = null;
+ IEnumerator e2 = null;
+
+ try
+ {
+ e1 = first.GetEnumerator();
+ e2 = second.GetEnumerator();
+
+ // | is used instead of || in purpose. All operands have to be evaluated.
+ while (
+ Enumerator.TryRead(ref e1, out var v1) |
+ Enumerator.TryRead(ref e2, out var v2))
+ {
+ yield return resultSelector(v1, v2);
+ }
+ }
+ finally
+ {
+ e1?.Dispose();
+ e2?.Dispose();
+ }
+ }
+ }
+
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of three sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as long as the longest of the input sequences.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
+ ///
+ /// A function that specifies how to merge the elements from the three sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of three input sequences.
+ ///
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ ///
+ /// If the input sequences are of different lengths, the default values of the types
+ /// of the elements of the shortests sequences are used for padding.
+ ///
+ /// This operator uses deferred execution and streams its results.
+ ///
+
+ public static IEnumerable ZipLongest(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ Func resultSelector)
+ {
+ if (first == null) throw new ArgumentNullException(nameof(first));
+ if (second == null) throw new ArgumentNullException(nameof(second));
+ if (third == null) throw new ArgumentNullException(nameof(third));
+ if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
+
+ return _(); IEnumerable _()
+ {
+ IEnumerator e1 = null;
+ IEnumerator e2 = null;
+ IEnumerator e3 = null;
+
+ try
+ {
+ e1 = first.GetEnumerator();
+ e2 = second.GetEnumerator();
+ e3 = third.GetEnumerator();
+
+ // | is used instead of || in purpose. All operands have to be evaluated.
+ while (
+ Enumerator.TryRead(ref e1, out var v1) |
+ Enumerator.TryRead(ref e2, out var v2) |
+ Enumerator.TryRead(ref e3, out var v3))
+ {
+ yield return resultSelector(v1, v2, v3);
+ }
+ }
+ finally
+ {
+ e1?.Dispose();
+ e2?.Dispose();
+ e3?.Dispose();
+ }
+ }
+ }
+
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of four sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as long as the longest of the input sequences.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the fourth input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
+ /// The fourth sequence to merge.
+ ///
+ /// A function that specifies how to merge the elements from the four sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of four input sequences.
+ ///
+ /// ,
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ ///
+ /// If the input sequences are of different lengths, the default values of the types
+ /// of the elements of the shortests sequences are used for padding.
+ ///
+ /// This operator uses deferred execution and streams its results.
+ ///
+
+ public static IEnumerable ZipLongest(
+ this IEnumerable first,
+ IEnumerable second,
+ IEnumerable third,
+ IEnumerable fourth,
+ Func resultSelector)
+ {
+ if (first == null) throw new ArgumentNullException(nameof(first));
+ if (second == null) throw new ArgumentNullException(nameof(second));
+ if (third == null) throw new ArgumentNullException(nameof(third));
+ if (fourth == null) throw new ArgumentNullException(nameof(fourth));
+ if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
+
+ return _(); IEnumerable _()
+ {
+ IEnumerator e1 = null;
+ IEnumerator e2 = null;
+ IEnumerator e3 = null;
+ IEnumerator e4 = null;
+
+ try
+ {
+ e1 = first.GetEnumerator();
+ e2 = second.GetEnumerator();
+ e3 = third.GetEnumerator();
+ e4 = fourth.GetEnumerator();
+
+ // | is used instead of || in purpose. All operands have to be evaluated.
+ while (
+ Enumerator.TryRead(ref e1, out var v1) |
+ Enumerator.TryRead(ref e2, out var v2) |
+ Enumerator.TryRead(ref e3, out var v3) |
+ Enumerator.TryRead(ref e4, out var v4))
+ {
+ yield return resultSelector(v1, v2, v3, v4);
+ }
+ }
+ finally
+ {
+ e1?.Dispose();
+ e2?.Dispose();
+ e3?.Dispose();
+ e4?.Dispose();
+ }
+ }
+ }
+
+ }
+}
diff --git a/MoreLinq/ZipLongest.g.tt b/MoreLinq/ZipLongest.g.tt
new file mode 100644
index 000000000..91330bb2b
--- /dev/null
+++ b/MoreLinq/ZipLongest.g.tt
@@ -0,0 +1,146 @@
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ output extension=".cs" #>
+<#@ assembly name="System.Core" #>
+<#@ import namespace="System.Globalization" #>
+<#@ import namespace="System.Linq" #>
+#region License and Terms
+// MoreLINQ - Extensions to LINQ to Objects
+// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+<#
+ var ordinals = new[]
+ {
+ string.Empty,
+ "First", "Second", "Third", "Fourth",
+ "Fifth", "Sixth", "Seventh", "Eighth"
+ };
+
+ var cardinals = new[]
+ {
+ "zero",
+ "one", "two", "three", "four",
+ "five", "six", "seven", "eight"
+ };
+
+ var overloads =
+ from argCount in Enumerable.Range(2, 3)
+ from args in new[]
+ {
+ from argPosition in Enumerable.Range(1, argCount)
+ select new
+ {
+ IsFirst = argPosition == 1,
+ IsLast = argPosition == argCount,
+ Name = ordinals[argPosition].ToLower(),
+ ordinal = ordinals[argPosition].ToLower(),
+ Type = $"T{ordinals[argPosition]}",
+ // Objects associated with the argument
+ Enumerator = $"e{argPosition}",
+ Value = $"v{argPosition}"
+ }
+ }
+ select new
+ {
+ Arguments = args.ToList(),
+ cardinal = cardinals[argCount],
+ TParams = string.Join(", ", from arg in args select arg.Type)
+ };
+#>
+namespace MoreLinq
+{
+ using System;
+ using System.Collections.Generic;
+
+ static partial class MoreEnumerable
+ {
+<# foreach (var o in overloads)
+ {
+#>
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of <#= o.cardinal #> sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as long as the longest of the input sequences.
+ ///
+<# foreach (var arg in o.Arguments) { #>
+ /// The type of the elements of the <#= arg.ordinal #> input sequence.
+<# } #>
+ /// The type of the elements of the result sequence.
+<# foreach (var arg in o.Arguments) { #>
+ /// The <#= arg.ordinal #> sequence to merge.
+<# } #>
+ ///
+ /// A function that specifies how to merge the elements from the <#= o.cardinal #> sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of <#= o.cardinal #> input sequences.
+ ///
+<# foreach (var arg in o.Arguments) { #>
+ /// <#= arg.IsLast ? " or" : "," #>
+<# } #>
+ /// is null
.
+ ///
+ ///
+ /// If the input sequences are of different lengths, the default values of the types
+ /// of the elements of the shortests sequences are used for padding.
+ ///
+ /// This operator uses deferred execution and streams its results.
+ ///
+
+ public static IEnumerable ZipLongest<<#= o.TParams #>, TResult>(
+<# foreach (var arg in o.Arguments) { #>
+ <#= arg.IsFirst ? "this " : "" #>IEnumerable<<#= arg.Type #>> <#= arg.Name #>,
+<# } #>
+ Func<<#= o.TParams #>, TResult> resultSelector)
+ {
+<# foreach (var arg in o.Arguments) { #>
+ if (<#= arg.Name #> == null) throw new ArgumentNullException(nameof(<#= arg.Name #>));
+<# } #>
+ if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
+
+ return _(); IEnumerable _()
+ {
+<# foreach (var arg in o.Arguments) { #>
+ IEnumerator<<#= arg.Type #>> <#= arg.Enumerator #> = null;
+<# } #>
+
+ try
+ {
+<# foreach (var arg in o.Arguments) { #>
+ <#= arg.Enumerator #> = <#= arg.Name #>.GetEnumerator();
+<# } #>
+
+ // | is used instead of || in purpose. All operands have to be evaluated.
+ while (
+<# foreach (var arg in o.Arguments) { #>
+ Enumerator.TryRead(ref <#= arg.Enumerator #>, out var <#= arg.Value #>)<#= arg.IsLast ? ")" : " |" #>
+<# } #>
+ {
+ yield return resultSelector(<# foreach (var arg in o.Arguments) { #><#= arg.Value #><#= arg.IsLast ? "" : ", " #><# } #>);
+ }
+ }
+ finally
+ {
+<# foreach (var arg in o.Arguments) { #>
+ <#= arg.Enumerator #>?.Dispose();
+<# } #>
+ }
+ }
+ }
+
+<# } #>
+ }
+}
diff --git a/MoreLinq/ZipShortest.cs b/MoreLinq/ZipShortest.cs
deleted file mode 100644
index fbb28d046..000000000
--- a/MoreLinq/ZipShortest.cs
+++ /dev/null
@@ -1,201 +0,0 @@
-#region License and Terms
-// MoreLINQ - Extensions to LINQ to Objects
-// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#endregion
-
-namespace MoreLinq
-{
- using System;
- using System.Collections.Generic;
-
- static partial class MoreEnumerable
- {
- ///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. The resulting sequence
- /// is as short as the shortest input sequence.
- ///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
- ///
- /// Function to apply to each pair of elements.
- ///
- /// A projection of tuples, where each tuple contains the N-th element
- /// from each of the argument sequences.
- ///
- ///
- /// , , or is .
- ///
- /// n + l);
- /// ]]>
- /// The zipped variable, when iterated over, will yield "1A", "2B", "3C", in turn.
- ///
- ///
- ///
- /// If the input sequences are of different lengths, the result sequence
- /// is terminated as soon as the shortest input sequence is exhausted
- /// and remainder elements from the longer sequences are never consumed.
- ///
- ///
- /// This operator uses deferred execution and streams its results.
- ///
-
- public static IEnumerable ZipShortest(
- this IEnumerable first,
- IEnumerable second,
- Func resultSelector)
- {
- if (first == null) throw new ArgumentNullException(nameof(first));
- if (second == null) throw new ArgumentNullException(nameof(second));
- if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
-
- return ZipImpl(first, second, null, null, (a, b, _, _) => resultSelector(a, b));
- }
-
- ///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. The resulting sequence
- /// is as short as the shortest input sequence.
- ///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in third sequence.
- /// Type of elements in result sequence.
- /// First sequence
- /// Second sequence
- /// Third sequence
- ///
- /// Function to apply to each triplet of elements.
- ///
- /// A projection of tuples, where each tuple contains the N-th element
- /// from each of the argument sequences.
- ///
- /// , , , or is .
- ///
- ///
- /// c + n + l);
- /// ]]>
- /// The zipped variable, when iterated over, will yield
- /// "98A", "100B", "102C", in turn.
- ///
- ///
- ///
- /// If the input sequences are of different lengths, the result sequence
- /// is terminated as soon as the shortest input sequence is exhausted
- /// and remainder elements from the longer sequences are never consumed.
- ///
- ///
- /// This operator uses deferred execution and streams its results.
- ///
-
- public static IEnumerable ZipShortest(
- this IEnumerable first,
- IEnumerable second,
- IEnumerable third,
- Func resultSelector)
- {
- if (first == null) throw new ArgumentNullException(nameof(first));
- if (second == null) throw new ArgumentNullException(nameof(second));
- if (third == null) throw new ArgumentNullException(nameof(third));
- if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
-
- return ZipImpl(first, second, third, null, (a, b, c, _) => resultSelector(a, b, c));
- }
-
- ///
- /// Returns a projection of tuples, where each tuple contains the N-th
- /// element from each of the argument sequences. The resulting sequence
- /// is as short as the shortest input sequence.
- ///
- /// Type of elements in first sequence.
- /// Type of elements in second sequence.
- /// Type of elements in third sequence.
- /// Type of elements in fourth sequence.
- /// Type of elements in result sequence.
- /// The first sequence.
- /// The second sequence.
- /// The third sequence.
- /// The fourth sequence.
- ///
- /// Function to apply to each quadruplet of elements.
- ///
- /// A projection of tuples, where each tuple contains the N-th element
- /// from each of the argument sequences.
- ///
- /// , , , , or is .
- ///
- ///
- /// n + l + c + f);
- /// ]]>
- /// The zipped variable, when iterated over, will yield
- /// "1AaTrue", "2BbFalse" in turn.
- ///
- ///
- ///
- /// If the input sequences are of different lengths, the result sequence
- /// is terminated as soon as the shortest input sequence is exhausted
- /// and remainder elements from the longer sequences are never consumed.
- ///
- ///
- /// This operator uses deferred execution and streams its results.
- ///
-
- public static IEnumerable ZipShortest(
- this IEnumerable first,
- IEnumerable second,
- IEnumerable third,
- IEnumerable fourth,
- Func resultSelector)
- {
- if (first == null) throw new ArgumentNullException(nameof(first));
- if (second == null) throw new ArgumentNullException(nameof(second));
- if (third == null) throw new ArgumentNullException(nameof(third));
- if (fourth == null) throw new ArgumentNullException(nameof(fourth));
- if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
-
- return ZipImpl(first, second, third, fourth, resultSelector);
- }
-
- static IEnumerable ZipImpl(
- IEnumerable s1,
- IEnumerable s2,
- IEnumerable? s3,
- IEnumerable? s4,
- Func resultSelector)
- {
- return ZipImpl(s1, s2, s3, s4, resultSelector, 0);
- }
- }
-}
diff --git a/MoreLinq/ZipShortest.g.cs b/MoreLinq/ZipShortest.g.cs
new file mode 100644
index 000000000..302511530
--- /dev/null
+++ b/MoreLinq/ZipShortest.g.cs
@@ -0,0 +1,194 @@
+#region License and Terms
+// MoreLINQ - Extensions to LINQ to Objects
+// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+namespace MoreLinq
+{
+ using System;
+ using System.Collections.Generic;
+
+ static partial class MoreEnumerable
+ {
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of two sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as short as the shortest of the input sequences.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ ///
+ /// A function that specifies how to merge the elements from the two sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of two input sequences.
+ ///
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ ///
+ /// If the input sequences are of different lengths, the resulting sequence is terminated
+ /// as soon as the shortest input sequence reaches its end.
+ /// The remaining elements of the other sequences are never consumed.
+ ///
+ /// This operator uses deferred execution and streams its results.
+ ///
+
+ public static IEnumerable ZipShortest(
+ this IEnumerable first,
+ IEnumerable second,
+ Func resultSelector)
+ {
+ if (first == null) throw new ArgumentNullException(nameof(first));
+ if (second == null) throw new ArgumentNullException(nameof(second));
+ if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
+
+ return _(); IEnumerable _()
+ {
+ using var e1 = first.GetEnumerator();
+ using var e2 = second.GetEnumerator();
+
+ while (e1.MoveNext() && e2.MoveNext())
+ {
+ yield return resultSelector(e1.Current, e2.Current);
+ }
+ }
+ }
+
+ ///
+ ///
+ /// Applies a specified function to the corresponding elements of three sequences,
+ /// producing a sequence of the results.
+ ///
+ /// The resulting sequence is as short as the shortest of the input sequences.
+ ///
+ /// The type of the elements of the first input sequence.
+ /// The type of the elements of the second input sequence.
+ /// The type of the elements of the third input sequence.
+ /// The type of the elements of the result sequence.
+ /// The first sequence to merge.
+ /// The second sequence to merge.
+ /// The third sequence to merge.
+ ///
+ /// A function that specifies how to merge the elements from the three sequences.
+ ///
+ /// An IEnumerable
that contains merged elements of three input sequences.
+ ///
+ /// ,
+ /// ,
+ /// or
+ /// is null
.
+ ///
+ ///
+ /// If the input sequences are of different lengths, the resulting sequence is terminated
+ /// as soon as the shortest input sequence reaches its end.
+ /// The remaining elements of the other sequences are never consumed.
+ ///
+ /// This operator uses deferred execution and streams its results.
+ ///
+
+ public static IEnumerable ZipShortest(
+ this IEnumerable first,
+ IEnumerable