private static IEnumerable <IFusionOperator> Optimize(IFusionOperator[] chain) { // TODO: these optimizations can be moved to the expression space above the plan var cur = default(IFusionOperator); foreach (var op in chain) { if (cur != null) { if (cur is WhereFactory where1 && op is WhereFactory where2) { var p1 = where1.Predicate; var p2 = where2.Predicate; var x = Expression.Parameter(cur.OutputType); var p = Expression.Lambda(Expression.AndAlso(Expression.Invoke(p1, x), Expression.Invoke(p2, x)), x); cur = new WhereFactory { Predicate = p }; } else if (cur is TakeFactory take1 && op is TakeFactory take2) { // TODO: Count should be an expression (which could be constant, allowing for this optimization) var n1 = take1.Count; var n2 = take2.Count; var n = Math.Min(n1, n2); cur = new TakeFactory { Count = n }; }
private static void Take() { var tf = new TakeFactory { Count = 3, OutputType = typeof(int) }; var ff = new SinkFactory { OutputType = typeof(int) }; var chain = new IFusionOperator[] { tf, // .Take(3) ff }; var ivt = Compile(typeof(int), chain); var res = new List <int>(); var err = default(Exception); var fin = false; var otp = Observer.Create <int>(res.Add, ex => err = ex, () => fin = true); var dsp = System.Reactive.Disposables.Disposable.Empty; var iv = (IObserver <int>)Activator.CreateInstance(ivt, new object[] { otp, dsp }); iv.OnNext(0); iv.OnNext(1); iv.OnNext(2); iv.OnNext(3); iv.OnNext(4); iv.OnCompleted(); Assert(res.SequenceEqual(new[] { 0, 1, 2 })); Assert(err == null); Assert(fin); }
private static void Old() { // TODO: implement a few operators in terms of others and see fusion emit the same code // e.g. xs.Last() == xs.Aggreggate((a, x) => x) // // Aggregate // - Count/LongCount // Average/Sum/Min/Max // Any/All/IsEmpty // - First // - Last // Single // Contains // ElementAt // - IgnoreElements // Scan // Sample // - Take // Skip // TakeWhile/SkipWhile // Finally // // CombineLatest // SequenceEqual // TakeUntil // // SkipUntil // StartWith // // Merge // SelectMany // Switch // var wf1 = new WhereFactory { Predicate = (Expression <Func <int, bool> >)(x => x > 0) }; var wf2 = new WhereIndexedFactory { Predicate = (Expression <Func <int, int, bool> >)((x, i) => x != 0 && i < int.MaxValue) }; var df = new DistinctUntilChangedFactory { OutputType = typeof(int) }; var sf1 = new SelectFactory { Selector = (Expression <Func <int, int> >)(x => x * 2) }; var sf2 = new SelectIndexedFactory { Selector = (Expression <Func <int, int, int> >)((x, i) => x * 3 + i) }; var tf1 = new TakeFactory { OutputType = typeof(int), Count = 1000 }; var tf2 = new TakeFactory { OutputType = typeof(int), Count = 2000 }; var af = new SumFactory(typeof(int)); var ff = new SinkFactory { OutputType = typeof(int) }; var chain = new IFusionOperator[] { wf1, // .Where(x => x > 0) wf2, // .Where((x, i) => x != 0 && i < int.MaxValue) df, // .DistinctUntilChanged() sf1, // .Select(x => x * 2) sf2, // .Select((x, i) => x * 3 + i) tf1, // .Take(1000) tf2, // .Take(2000) af, // .Sum() ff }; var ivt = Compile(typeof(int), chain); Test(ivt); }