瀏覽代碼

Enabling optimizations for combining N predicates

Bart De Smet 6 年之前
父節點
當前提交
be5d8bb438

+ 0 - 2
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Select.Opt.cs

@@ -2,8 +2,6 @@
 // The .NET Foundation licenses this file to you under the Apache 2.0 License.
 // See the LICENSE file in the project root for more information. 
 
-using System.Collections.Generic;
-using System.Diagnostics;
 using System.Threading;
 using System.Threading.Tasks;
 

+ 231 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Where.Opt.Generated.cs

@@ -0,0 +1,231 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Linq
+{
+    public static partial class AsyncEnumerable
+    {
+        private sealed class CombinedPredicates2<TSource> : ICombinedPredicates<TSource>
+        {
+            private readonly Func<TSource, bool> _predicate1;
+            private readonly Func<TSource, bool> _predicate2;
+
+            public CombinedPredicates2(Func<TSource, bool> predicate1, Func<TSource, bool> predicate2)
+            {
+                _predicate1 = predicate1;
+                _predicate2 = predicate2;
+            }
+
+            public ICombinedPredicates<TSource> And(Func<TSource, bool> predicate) =>
+                new CombinedPredicates3<TSource>(
+                    _predicate1,
+                    _predicate2,
+                    predicate
+                );
+
+            public bool Invoke(TSource x) => _predicate1(x) && _predicate2(x);
+        }
+
+        private sealed class CombinedPredicates3<TSource> : ICombinedPredicates<TSource>
+        {
+            private readonly Func<TSource, bool> _predicate1;
+            private readonly Func<TSource, bool> _predicate2;
+            private readonly Func<TSource, bool> _predicate3;
+
+            public CombinedPredicates3(Func<TSource, bool> predicate1, Func<TSource, bool> predicate2, Func<TSource, bool> predicate3)
+            {
+                _predicate1 = predicate1;
+                _predicate2 = predicate2;
+                _predicate3 = predicate3;
+            }
+
+            public ICombinedPredicates<TSource> And(Func<TSource, bool> predicate) =>
+                new CombinedPredicates4<TSource>(
+                    _predicate1,
+                    _predicate2,
+                    _predicate3,
+                    predicate
+                );
+
+            public bool Invoke(TSource x) => _predicate1(x) && _predicate2(x) && _predicate3(x);
+        }
+
+        private sealed class CombinedPredicates4<TSource> : ICombinedPredicates<TSource>
+        {
+            private readonly Func<TSource, bool> _predicate1;
+            private readonly Func<TSource, bool> _predicate2;
+            private readonly Func<TSource, bool> _predicate3;
+            private readonly Func<TSource, bool> _predicate4;
+
+            public CombinedPredicates4(Func<TSource, bool> predicate1, Func<TSource, bool> predicate2, Func<TSource, bool> predicate3, Func<TSource, bool> predicate4)
+            {
+                _predicate1 = predicate1;
+                _predicate2 = predicate2;
+                _predicate3 = predicate3;
+                _predicate4 = predicate4;
+            }
+
+            public ICombinedPredicates<TSource> And(Func<TSource, bool> predicate) =>
+                new CombinedPredicatesN<TSource>(
+                    _predicate1,
+                    _predicate2,
+                    _predicate3,
+                    _predicate4,
+                    predicate
+                );
+
+            public bool Invoke(TSource x) => _predicate1(x) && _predicate2(x) && _predicate3(x) && _predicate4(x);
+        }
+
+        private sealed class CombinedAsyncPredicates2<TSource> : ICombinedAsyncPredicates<TSource>
+        {
+            private readonly Func<TSource, ValueTask<bool>> _predicate1;
+            private readonly Func<TSource, ValueTask<bool>> _predicate2;
+
+            public CombinedAsyncPredicates2(Func<TSource, ValueTask<bool>> predicate1, Func<TSource, ValueTask<bool>> predicate2)
+            {
+                _predicate1 = predicate1;
+                _predicate2 = predicate2;
+            }
+
+            public ICombinedAsyncPredicates<TSource> And(Func<TSource, ValueTask<bool>> predicate) =>
+                new CombinedAsyncPredicates3<TSource>(
+                    _predicate1,
+                    _predicate2,
+                    predicate
+                );
+
+            public async ValueTask<bool> Invoke(TSource x) => await _predicate1(x).ConfigureAwait(false) && await _predicate2(x).ConfigureAwait(false);
+        }
+
+        private sealed class CombinedAsyncPredicates3<TSource> : ICombinedAsyncPredicates<TSource>
+        {
+            private readonly Func<TSource, ValueTask<bool>> _predicate1;
+            private readonly Func<TSource, ValueTask<bool>> _predicate2;
+            private readonly Func<TSource, ValueTask<bool>> _predicate3;
+
+            public CombinedAsyncPredicates3(Func<TSource, ValueTask<bool>> predicate1, Func<TSource, ValueTask<bool>> predicate2, Func<TSource, ValueTask<bool>> predicate3)
+            {
+                _predicate1 = predicate1;
+                _predicate2 = predicate2;
+                _predicate3 = predicate3;
+            }
+
+            public ICombinedAsyncPredicates<TSource> And(Func<TSource, ValueTask<bool>> predicate) =>
+                new CombinedAsyncPredicates4<TSource>(
+                    _predicate1,
+                    _predicate2,
+                    _predicate3,
+                    predicate
+                );
+
+            public async ValueTask<bool> Invoke(TSource x) => await _predicate1(x).ConfigureAwait(false) && await _predicate2(x).ConfigureAwait(false) && await _predicate3(x).ConfigureAwait(false);
+        }
+
+        private sealed class CombinedAsyncPredicates4<TSource> : ICombinedAsyncPredicates<TSource>
+        {
+            private readonly Func<TSource, ValueTask<bool>> _predicate1;
+            private readonly Func<TSource, ValueTask<bool>> _predicate2;
+            private readonly Func<TSource, ValueTask<bool>> _predicate3;
+            private readonly Func<TSource, ValueTask<bool>> _predicate4;
+
+            public CombinedAsyncPredicates4(Func<TSource, ValueTask<bool>> predicate1, Func<TSource, ValueTask<bool>> predicate2, Func<TSource, ValueTask<bool>> predicate3, Func<TSource, ValueTask<bool>> predicate4)
+            {
+                _predicate1 = predicate1;
+                _predicate2 = predicate2;
+                _predicate3 = predicate3;
+                _predicate4 = predicate4;
+            }
+
+            public ICombinedAsyncPredicates<TSource> And(Func<TSource, ValueTask<bool>> predicate) =>
+                new CombinedAsyncPredicatesN<TSource>(
+                    _predicate1,
+                    _predicate2,
+                    _predicate3,
+                    _predicate4,
+                    predicate
+                );
+
+            public async ValueTask<bool> Invoke(TSource x) => await _predicate1(x).ConfigureAwait(false) && await _predicate2(x).ConfigureAwait(false) && await _predicate3(x).ConfigureAwait(false) && await _predicate4(x).ConfigureAwait(false);
+        }
+
+#if !NO_DEEP_CANCELLATION
+        private sealed class CombinedAsyncPredicatesWithCancellation2<TSource> : ICombinedAsyncPredicatesWithCancellation<TSource>
+        {
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate1;
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate2;
+
+            public CombinedAsyncPredicatesWithCancellation2(Func<TSource, CancellationToken, ValueTask<bool>> predicate1, Func<TSource, CancellationToken, ValueTask<bool>> predicate2)
+            {
+                _predicate1 = predicate1;
+                _predicate2 = predicate2;
+            }
+
+            public ICombinedAsyncPredicatesWithCancellation<TSource> And(Func<TSource, CancellationToken, ValueTask<bool>> predicate) =>
+                new CombinedAsyncPredicatesWithCancellation3<TSource>(
+                    _predicate1,
+                    _predicate2,
+                    predicate
+                );
+
+            public async ValueTask<bool> Invoke(TSource x, CancellationToken ct) => await _predicate1(x, ct).ConfigureAwait(false) && await _predicate2(x, ct).ConfigureAwait(false);
+        }
+
+        private sealed class CombinedAsyncPredicatesWithCancellation3<TSource> : ICombinedAsyncPredicatesWithCancellation<TSource>
+        {
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate1;
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate2;
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate3;
+
+            public CombinedAsyncPredicatesWithCancellation3(Func<TSource, CancellationToken, ValueTask<bool>> predicate1, Func<TSource, CancellationToken, ValueTask<bool>> predicate2, Func<TSource, CancellationToken, ValueTask<bool>> predicate3)
+            {
+                _predicate1 = predicate1;
+                _predicate2 = predicate2;
+                _predicate3 = predicate3;
+            }
+
+            public ICombinedAsyncPredicatesWithCancellation<TSource> And(Func<TSource, CancellationToken, ValueTask<bool>> predicate) =>
+                new CombinedAsyncPredicatesWithCancellation4<TSource>(
+                    _predicate1,
+                    _predicate2,
+                    _predicate3,
+                    predicate
+                );
+
+            public async ValueTask<bool> Invoke(TSource x, CancellationToken ct) => await _predicate1(x, ct).ConfigureAwait(false) && await _predicate2(x, ct).ConfigureAwait(false) && await _predicate3(x, ct).ConfigureAwait(false);
+        }
+
+        private sealed class CombinedAsyncPredicatesWithCancellation4<TSource> : ICombinedAsyncPredicatesWithCancellation<TSource>
+        {
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate1;
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate2;
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate3;
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate4;
+
+            public CombinedAsyncPredicatesWithCancellation4(Func<TSource, CancellationToken, ValueTask<bool>> predicate1, Func<TSource, CancellationToken, ValueTask<bool>> predicate2, Func<TSource, CancellationToken, ValueTask<bool>> predicate3, Func<TSource, CancellationToken, ValueTask<bool>> predicate4)
+            {
+                _predicate1 = predicate1;
+                _predicate2 = predicate2;
+                _predicate3 = predicate3;
+                _predicate4 = predicate4;
+            }
+
+            public ICombinedAsyncPredicatesWithCancellation<TSource> And(Func<TSource, CancellationToken, ValueTask<bool>> predicate) =>
+                new CombinedAsyncPredicatesWithCancellationN<TSource>(
+                    _predicate1,
+                    _predicate2,
+                    _predicate3,
+                    _predicate4,
+                    predicate
+                );
+
+            public async ValueTask<bool> Invoke(TSource x, CancellationToken ct) => await _predicate1(x, ct).ConfigureAwait(false) && await _predicate2(x, ct).ConfigureAwait(false) && await _predicate3(x, ct).ConfigureAwait(false) && await _predicate4(x, ct).ConfigureAwait(false);
+        }
+
+#endif
+    }
+}

+ 168 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Where.Opt.Generated.tt

@@ -0,0 +1,168 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ assembly name="System.Core" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Text" #>
+<#@ import namespace="System.Collections.Generic" #>
+<#@ output extension=".cs" #>
+<#
+int maxCombine = 4;
+#>
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Linq
+{
+    public static partial class AsyncEnumerable
+    {
+<#
+for (var i = 2; i <= maxCombine; i++)
+{
+    var applyAll = string.Join(" && ", Enumerable.Range(1, i).Select(j => "_predicate" + j + "(x)"));
+    var allPreds = string.Join(", ", Enumerable.Range(1, i).Select(j => "Func<TSource, bool> predicate" + j));
+#>
+        private sealed class CombinedPredicates<#=i#><TSource> : ICombinedPredicates<TSource>
+        {
+<#
+for (var j = 1; j <= i; j++)
+{
+#>
+            private readonly Func<TSource, bool> _predicate<#=j#>;
+<#
+}
+#>
+
+            public CombinedPredicates<#=i#>(<#=allPreds#>)
+            {
+<#
+for (var j = 1; j <= i; j++)
+{
+#>
+                _predicate<#=j#> = predicate<#=j#>;
+<#
+}
+#>
+            }
+
+            public ICombinedPredicates<TSource> And(Func<TSource, bool> predicate) =>
+                new CombinedPredicates<#=i == maxCombine ? "N" : (i + 1).ToString()#><TSource>(
+<#
+for (var j = 1; j <= i; j++)
+{
+#>
+                    _predicate<#=j#>,
+<#
+}
+#>
+                    predicate
+                );
+
+            public bool Invoke(TSource x) => <#=applyAll#>;
+        }
+
+<#
+}
+#>
+<#
+for (var i = 2; i <= maxCombine; i++)
+{
+    var applyAll = string.Join(" && ", Enumerable.Range(1, i).Select(j => "await _predicate" + j + "(x).ConfigureAwait(false)"));
+    var allPreds = string.Join(", ", Enumerable.Range(1, i).Select(j => "Func<TSource, ValueTask<bool>> predicate" + j));
+#>
+        private sealed class CombinedAsyncPredicates<#=i#><TSource> : ICombinedAsyncPredicates<TSource>
+        {
+<#
+for (var j = 1; j <= i; j++)
+{
+#>
+            private readonly Func<TSource, ValueTask<bool>> _predicate<#=j#>;
+<#
+}
+#>
+
+            public CombinedAsyncPredicates<#=i#>(<#=allPreds#>)
+            {
+<#
+for (var j = 1; j <= i; j++)
+{
+#>
+                _predicate<#=j#> = predicate<#=j#>;
+<#
+}
+#>
+            }
+
+            public ICombinedAsyncPredicates<TSource> And(Func<TSource, ValueTask<bool>> predicate) =>
+                new CombinedAsyncPredicates<#=i == maxCombine ? "N" : (i + 1).ToString()#><TSource>(
+<#
+for (var j = 1; j <= i; j++)
+{
+#>
+                    _predicate<#=j#>,
+<#
+}
+#>
+                    predicate
+                );
+
+            public async ValueTask<bool> Invoke(TSource x) => <#=applyAll#>;
+        }
+
+<#
+}
+#>
+#if !NO_DEEP_CANCELLATION
+<#
+for (var i = 2; i <= maxCombine; i++)
+{
+    var applyAll = string.Join(" && ", Enumerable.Range(1, i).Select(j => "await _predicate" + j + "(x, ct).ConfigureAwait(false)"));
+    var allPreds = string.Join(", ", Enumerable.Range(1, i).Select(j => "Func<TSource, CancellationToken, ValueTask<bool>> predicate" + j));
+#>
+        private sealed class CombinedAsyncPredicatesWithCancellation<#=i#><TSource> : ICombinedAsyncPredicatesWithCancellation<TSource>
+        {
+<#
+for (var j = 1; j <= i; j++)
+{
+#>
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate<#=j#>;
+<#
+}
+#>
+
+            public CombinedAsyncPredicatesWithCancellation<#=i#>(<#=allPreds#>)
+            {
+<#
+for (var j = 1; j <= i; j++)
+{
+#>
+                _predicate<#=j#> = predicate<#=j#>;
+<#
+}
+#>
+            }
+
+            public ICombinedAsyncPredicatesWithCancellation<TSource> And(Func<TSource, CancellationToken, ValueTask<bool>> predicate) =>
+                new CombinedAsyncPredicatesWithCancellation<#=i == maxCombine ? "N" : (i + 1).ToString()#><TSource>(
+<#
+for (var j = 1; j <= i; j++)
+{
+#>
+                    _predicate<#=j#>,
+<#
+}
+#>
+                    predicate
+                );
+
+            public async ValueTask<bool> Invoke(TSource x, CancellationToken ct) => <#=applyAll#>;
+        }
+
+<#
+}
+#>
+#endif
+    }
+}

+ 138 - 5
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Where.Opt.cs

@@ -2,8 +2,6 @@
 // The .NET Foundation licenses this file to you under the Apache 2.0 License.
 // See the LICENSE file in the project root for more information. 
 
-using System.Collections.Generic;
-using System.Diagnostics;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -13,18 +11,153 @@ namespace System.Linq
     {
         private static Func<TSource, bool> CombinePredicates<TSource>(Func<TSource, bool> predicate1, Func<TSource, bool> predicate2)
         {
-            return x => predicate1(x) && predicate2(x);
+            if (predicate1.Target is ICombinedPredicates<TSource> c)
+            {
+                return c.And(predicate2).Invoke;
+            }
+            else
+            {
+                return new CombinedPredicates2<TSource>(predicate1, predicate2).Invoke;
+            }
+        }
+
+        private interface ICombinedPredicates<TSource>
+        {
+            ICombinedPredicates<TSource> And(Func<TSource, bool> predicate);
+            bool Invoke(TSource x);
+        }
+
+        private sealed class CombinedPredicatesN<TSource> : ICombinedPredicates<TSource>
+        {
+            private readonly Func<TSource, bool>[] _predicates;
+
+            public CombinedPredicatesN(params Func<TSource, bool>[] predicates)
+            {
+                _predicates = predicates;
+            }
+
+            public ICombinedPredicates<TSource> And(Func<TSource, bool> predicate)
+            {
+                var predicates = new Func<TSource, bool>[_predicates.Length + 1];
+                Array.Copy(_predicates, predicates, _predicates.Length);
+                predicates[_predicates.Length] = predicate;
+
+                return new CombinedPredicatesN<TSource>(predicates);
+            }
+
+            public bool Invoke(TSource x)
+            {
+                foreach (var predicate in _predicates)
+                {
+                    if (!predicate(x))
+                    {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
         }
 
         private static Func<TSource, ValueTask<bool>> CombinePredicates<TSource>(Func<TSource, ValueTask<bool>> predicate1, Func<TSource, ValueTask<bool>> predicate2)
         {
-            return async x => await predicate1(x).ConfigureAwait(false) && await predicate2(x).ConfigureAwait(false);
+            if (predicate1.Target is ICombinedAsyncPredicates<TSource> c)
+            {
+                return c.And(predicate2).Invoke;
+            }
+            else
+            {
+                return new CombinedAsyncPredicates2<TSource>(predicate1, predicate2).Invoke;
+            }
+        }
+
+        private interface ICombinedAsyncPredicates<TSource>
+        {
+            ICombinedAsyncPredicates<TSource> And(Func<TSource, ValueTask<bool>> predicate);
+            ValueTask<bool> Invoke(TSource x);
+        }
+
+        private sealed class CombinedAsyncPredicatesN<TSource> : ICombinedAsyncPredicates<TSource>
+        {
+            private readonly Func<TSource, ValueTask<bool>>[] _predicates;
+
+            public CombinedAsyncPredicatesN(params Func<TSource, ValueTask<bool>>[] predicates)
+            {
+                _predicates = predicates;
+            }
+
+            public ICombinedAsyncPredicates<TSource> And(Func<TSource, ValueTask<bool>> predicate)
+            {
+                var predicates = new Func<TSource, ValueTask<bool>>[_predicates.Length + 1];
+                Array.Copy(_predicates, predicates, _predicates.Length);
+                predicates[_predicates.Length] = predicate;
+
+                return new CombinedAsyncPredicatesN<TSource>(predicates);
+            }
+
+            public async ValueTask<bool> Invoke(TSource x)
+            {
+                foreach (var predicate in _predicates)
+                {
+                    if (!await predicate(x).ConfigureAwait(false))
+                    {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
         }
 
 #if !NO_DEEP_CANCELLATION
         private static Func<TSource, CancellationToken, ValueTask<bool>> CombinePredicates<TSource>(Func<TSource, CancellationToken, ValueTask<bool>> predicate1, Func<TSource, CancellationToken, ValueTask<bool>> predicate2)
         {
-            return async (x, ct) => await predicate1(x, ct).ConfigureAwait(false) && await predicate2(x, ct).ConfigureAwait(false);
+            if (predicate1.Target is ICombinedAsyncPredicatesWithCancellation<TSource> c)
+            {
+                return c.And(predicate2).Invoke;
+            }
+            else
+            {
+                return new CombinedAsyncPredicatesWithCancellation2<TSource>(predicate1, predicate2).Invoke;
+            }
+        }
+
+        private interface ICombinedAsyncPredicatesWithCancellation<TSource>
+        {
+            ICombinedAsyncPredicatesWithCancellation<TSource> And(Func<TSource, CancellationToken, ValueTask<bool>> predicate);
+            ValueTask<bool> Invoke(TSource x, CancellationToken ct);
+        }
+
+        private sealed class CombinedAsyncPredicatesWithCancellationN<TSource> : ICombinedAsyncPredicatesWithCancellation<TSource>
+        {
+            private readonly Func<TSource, CancellationToken, ValueTask<bool>>[] _predicates;
+
+            public CombinedAsyncPredicatesWithCancellationN(params Func<TSource, CancellationToken, ValueTask<bool>>[] predicates)
+            {
+                _predicates = predicates;
+            }
+
+            public ICombinedAsyncPredicatesWithCancellation<TSource> And(Func<TSource, CancellationToken, ValueTask<bool>> predicate)
+            {
+                var predicates = new Func<TSource, CancellationToken, ValueTask<bool>>[_predicates.Length + 1];
+                Array.Copy(_predicates, predicates, _predicates.Length);
+                predicates[_predicates.Length] = predicate;
+
+                return new CombinedAsyncPredicatesWithCancellationN<TSource>(predicates);
+            }
+
+            public async ValueTask<bool> Invoke(TSource x, CancellationToken ct)
+            {
+                foreach (var predicate in _predicates)
+                {
+                    if (!await predicate(x, ct).ConfigureAwait(false))
+                    {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
         }
 #endif
     }