From 2235883e39b773e194bb1a0b954dc3a884475f85 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 13:54:30 -0700 Subject: [PATCH 01/95] First steps to reduce operator object layouts. --- .../System.Reactive/Linq/Observable/All.cs | 12 +- .../System.Reactive/Linq/Observable/Any.cs | 144 +++++++------ .../System.Reactive/Linq/Observable/Count.cs | 158 +++++++------- .../Linq/Observable/FirstAsync.cs | 150 ++++++-------- .../Linq/Observable/FirstOrDefaultAsync.cs | 120 +++++++++++ .../Linq/Observable/LastAsync.cs | 184 ++++++++-------- .../Linq/Observable/LastOrDefaultAsync.cs | 128 ++++++++++++ .../Linq/Observable/LongCount.cs | 158 +++++++------- .../System.Reactive/Linq/Observable/Select.cs | 164 ++++++++------- .../Linq/Observable/SingleAsync.cs | 196 +++++++++--------- .../Linq/Observable/SingleOrDefaultAsync.cs | 142 +++++++++++++ .../System.Reactive/Linq/Observable/Where.cs | 183 ++++++++-------- .../Linq/QueryLanguage.Aggregates.cs | 36 ++-- ...QueryLanguage.StandardSequenceOperators.cs | 12 +- 14 files changed, 1107 insertions(+), 680 deletions(-) create mode 100644 Rx.NET/Source/src/System.Reactive/Linq/Observable/FirstOrDefaultAsync.cs create mode 100644 Rx.NET/Source/src/System.Reactive/Linq/Observable/LastOrDefaultAsync.cs create mode 100644 Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleOrDefaultAsync.cs diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/All.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/All.cs index 2b18d0553..b48028cfb 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/All.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/All.cs @@ -17,19 +17,19 @@ public All(IObservable source, Func predicate) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_predicate, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly All _parent; + private readonly Func _predicate; - public _(All parent, IObserver observer, IDisposable cancel) + public _(Func predicate, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _predicate = predicate; } public void OnNext(TSource value) @@ -37,7 +37,7 @@ public void OnNext(TSource value) var res = false; try { - res = _parent._predicate(value); + res = _predicate(value); } catch (Exception ex) { diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Any.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Any.cs index adf3c9fc6..af02bd4d8 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Any.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Any.cs @@ -4,110 +4,116 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Any : Producer + internal static class Any { - private readonly IObservable _source; - private readonly Func _predicate; - - public Any(IObservable source) + internal sealed class Count : Producer { - _source = source; - } + private readonly IObservable _source; - public Any(IObservable source, Func predicate) - { - _source = source; - _predicate = predicate; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_predicate != null) + public Count(IObservable source) { - var sink = new AnyImpl(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { var sink = new _(observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - class _ : Sink, IObserver - { - public _(IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver { - } + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } - public void OnNext(TSource value) - { - base._observer.OnNext(true); - base._observer.OnCompleted(); - base.Dispose(); - } + public void OnNext(TSource value) + { + base._observer.OnNext(true); + base._observer.OnCompleted(); + base.Dispose(); + } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } - public void OnCompleted() - { - base._observer.OnNext(false); - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnNext(false); + base._observer.OnCompleted(); + base.Dispose(); + } } } - class AnyImpl : Sink, IObserver + internal sealed class Predicate : Producer { - private readonly Any _parent; + private readonly IObservable _source; + private readonly Func _predicate; - public AnyImpl(Any parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Predicate(IObservable source, Func predicate) { - _parent = parent; + _source = source; + _predicate = predicate; } - public void OnNext(TSource value) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var res = false; - try + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly Func _predicate; + + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - res = _parent._predicate(value); + _predicate = predicate; } - catch (Exception ex) + + public void OnNext(TSource value) + { + var res = false; + try + { + res = _predicate(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + if (res) + { + base._observer.OnNext(true); + base._observer.OnCompleted(); + base.Dispose(); + } + } + + public void OnError(Exception error) { - base._observer.OnError(ex); + base._observer.OnError(error); base.Dispose(); - return; } - if (res) + public void OnCompleted() { - base._observer.OnNext(true); + base._observer.OnNext(false); base._observer.OnCompleted(); base.Dispose(); } } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - - public void OnCompleted() - { - base._observer.OnNext(false); - base._observer.OnCompleted(); - base.Dispose(); - } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Count.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Count.cs index c3865e0a5..d8927dfcb 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Count.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Count.cs @@ -4,118 +4,126 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Count : Producer + internal static class Count { - private readonly IObservable _source; - private readonly Func _predicate; - - public Count(IObservable source) + internal sealed class All : Producer { - _source = source; - } + private readonly IObservable _source; - public Count(IObservable source, Func predicate) - { - _source = source; - _predicate = predicate; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_predicate == null) + public All(IObservable source) { - var sink = new _(observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new CountImpl(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - - class _ : Sink, IObserver - { - private int _count; - public _(IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver { - _count = 0; - } + private int _count; - public void OnNext(TSource value) - { - try + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) { - checked + _count = 0; + } + + public void OnNext(TSource value) + { + try { - _count++; + checked + { + _count++; + } + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); } } - catch (Exception ex) + + public void OnError(Exception error) { - base._observer.OnError(ex); + base._observer.OnError(error); base.Dispose(); } - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - public void OnCompleted() - { - base._observer.OnNext(_count); - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnNext(_count); + base._observer.OnCompleted(); + base.Dispose(); + } } } - class CountImpl : Sink, IObserver + internal sealed class Predicate : Producer { - private readonly Count _parent; - private int _count; + private readonly IObservable _source; + private readonly Func _predicate; - public CountImpl(Count parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Predicate(IObservable source, Func predicate) { - _parent = parent; - _count = 0; + _source = source; + _predicate = predicate; } - public void OnNext(TSource value) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - try + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly Func _predicate; + private int _count; + + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _predicate = predicate; + _count = 0; + } + + public void OnNext(TSource value) { - checked + try { - if (_parent._predicate(value)) - _count++; + checked + { + if (_predicate(value)) + { + _count++; + } + } + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); } } - catch (Exception ex) + + public void OnError(Exception error) { - base._observer.OnError(ex); + base._observer.OnError(error); base.Dispose(); } - } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - - public void OnCompleted() - { - base._observer.OnNext(_count); - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnNext(_count); + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/FirstAsync.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/FirstAsync.cs index 92d9aadde..71f5ed95a 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/FirstAsync.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/FirstAsync.cs @@ -4,126 +4,114 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class FirstAsync : Producer + internal static class FirstAsync { - private readonly IObservable _source; - private readonly Func _predicate; - private readonly bool _throwOnEmpty; - - public FirstAsync(IObservable source, Func predicate, bool throwOnEmpty) + internal sealed class Sequence : Producer { - _source = source; - _predicate = predicate; - _throwOnEmpty = throwOnEmpty; - } + private readonly IObservable _source; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_predicate != null) + public Sequence(IObservable source) { - var sink = new FirstAsyncImpl(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - class _ : Sink, IObserver - { - private readonly FirstAsync _parent; - - public _(FirstAsync parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - } - - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - base._observer.OnNext(value); - base._observer.OnCompleted(); - base.Dispose(); - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - - public void OnCompleted() - { - if (_parent._throwOnEmpty) + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_ELEMENTS)); } - else + + public void OnNext(TSource value) { - base._observer.OnNext(default(TSource)); + base._observer.OnNext(value); base._observer.OnCompleted(); + base.Dispose(); } - base.Dispose(); + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_ELEMENTS)); + base.Dispose(); + } } } - class FirstAsyncImpl : Sink, IObserver + internal sealed class Predicate : Producer { - private readonly FirstAsync _parent; + private readonly IObservable _source; + private readonly Func _predicate; + + public Predicate(IObservable source, Func predicate) + { + _source = source; + _predicate = predicate; + } - public FirstAsyncImpl(FirstAsync parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _parent = parent; + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var b = false; + private readonly Func _predicate; - try + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - b = _parent._predicate(value); + _predicate = predicate; } - catch (Exception ex) + + public void OnNext(TSource value) { - base._observer.OnError(ex); - base.Dispose(); - return; + var b = false; + + try + { + b = _predicate(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + if (b) + { + base._observer.OnNext(value); + base._observer.OnCompleted(); + base.Dispose(); + } } - if (b) + public void OnError(Exception error) { - base._observer.OnNext(value); - base._observer.OnCompleted(); + base._observer.OnError(error); base.Dispose(); } - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - public void OnCompleted() - { - if (_parent._throwOnEmpty) + public void OnCompleted() { base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_MATCHING_ELEMENTS)); + base.Dispose(); } - else - { - base._observer.OnNext(default(TSource)); - base._observer.OnCompleted(); - } - - base.Dispose(); } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/FirstOrDefaultAsync.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/FirstOrDefaultAsync.cs new file mode 100644 index 000000000..820045afd --- /dev/null +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/FirstOrDefaultAsync.cs @@ -0,0 +1,120 @@ +// 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. + +namespace System.Reactive.Linq.ObservableImpl +{ + internal static class FirstOrDefaultAsync + { + internal sealed class Sequence : Producer + { + private readonly IObservable _source; + + public Sequence(IObservable source) + { + _source = source; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public void OnNext(TSource value) + { + base._observer.OnNext(value); + base._observer.OnCompleted(); + base.Dispose(); + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnNext(default(TSource)); + base._observer.OnCompleted(); + base.Dispose(); + } + } + } + + internal sealed class Predicate : Producer + { + private readonly IObservable _source; + private readonly Func _predicate; + + public Predicate(IObservable source, Func predicate) + { + _source = source; + _predicate = predicate; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly Func _predicate; + + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _predicate = predicate; + } + + public void OnNext(TSource value) + { + var b = false; + + try + { + b = _predicate(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + if (b) + { + base._observer.OnNext(value); + base._observer.OnCompleted(); + base.Dispose(); + } + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnNext(default(TSource)); + base._observer.OnCompleted(); + base.Dispose(); + } + } + } + } +} diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastAsync.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastAsync.cs index 460baff76..eb84b9e74 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastAsync.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastAsync.cs @@ -4,134 +4,140 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class LastAsync : Producer + internal static class LastAsync { - private readonly IObservable _source; - private readonly Func _predicate; - private readonly bool _throwOnEmpty; - - public LastAsync(IObservable source, Func predicate, bool throwOnEmpty) + internal sealed class Sequence : Producer { - _source = source; - _predicate = predicate; - _throwOnEmpty = throwOnEmpty; - } + private readonly IObservable _source; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_predicate != null) + public Sequence(IObservable source) { - var sink = new LastAsyncImpl(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - - class _ : Sink, IObserver - { - private readonly LastAsync _parent; - private TSource _value; - private bool _seenValue; - - public _(LastAsync parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - - _value = default(TSource); - _seenValue = false; - } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - _value = value; - _seenValue = true; - } + private TSource _value; + private bool _seenValue; - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _value = default(TSource); + _seenValue = false; + } - public void OnCompleted() - { - if (!_seenValue && _parent._throwOnEmpty) + public void OnNext(TSource value) { - base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_ELEMENTS)); + _value = value; + _seenValue = true; } - else + + public void OnError(Exception error) { - base._observer.OnNext(_value); - base._observer.OnCompleted(); + base._observer.OnError(error); + base.Dispose(); } - base.Dispose(); + public void OnCompleted() + { + if (!_seenValue) + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_ELEMENTS)); + } + else + { + base._observer.OnNext(_value); + base._observer.OnCompleted(); + } + + base.Dispose(); + } } } - class LastAsyncImpl : Sink, IObserver + internal sealed class Predicate : Producer { - private readonly LastAsync _parent; - private TSource _value; - private bool _seenValue; + private readonly IObservable _source; + private readonly Func _predicate; - public LastAsyncImpl(LastAsync parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Predicate(IObservable source, Func predicate) { - _parent = parent; + _source = source; + _predicate = predicate; + } - _value = default(TSource); - _seenValue = false; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var b = false; + private readonly Func _predicate; + private TSource _value; + private bool _seenValue; - try - { - b = _parent._predicate(value); - } - catch (Exception ex) + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnError(ex); - base.Dispose(); - return; + _predicate = predicate; + + _value = default(TSource); + _seenValue = false; } - if (b) + public void OnNext(TSource value) { - _value = value; - _seenValue = true; + var b = false; + + try + { + b = _predicate(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + if (b) + { + _value = value; + _seenValue = true; + } } - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - public void OnCompleted() - { - if (!_seenValue && _parent._throwOnEmpty) + public void OnError(Exception error) { - base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_MATCHING_ELEMENTS)); + base._observer.OnError(error); + base.Dispose(); } - else + + public void OnCompleted() { - base._observer.OnNext(_value); - base._observer.OnCompleted(); - } + if (!_seenValue) + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_MATCHING_ELEMENTS)); + } + else + { + base._observer.OnNext(_value); + base._observer.OnCompleted(); + } - base.Dispose(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastOrDefaultAsync.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastOrDefaultAsync.cs new file mode 100644 index 000000000..bdbb095ea --- /dev/null +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastOrDefaultAsync.cs @@ -0,0 +1,128 @@ +// 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. + +namespace System.Reactive.Linq.ObservableImpl +{ + internal static class LastOrDefaultAsync + { + internal sealed class Sequence : Producer + { + private readonly IObservable _source; + + public Sequence(IObservable source) + { + _source = source; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private TSource _value; + private bool _seenValue; + + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _value = default(TSource); + _seenValue = false; + } + + public void OnNext(TSource value) + { + _value = value; + _seenValue = true; + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnNext(_value); + base._observer.OnCompleted(); + base.Dispose(); + } + } + } + + internal sealed class Predicate : Producer + { + private readonly IObservable _source; + private readonly Func _predicate; + + public Predicate(IObservable source, Func predicate) + { + _source = source; + _predicate = predicate; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly Func _predicate; + private TSource _value; + private bool _seenValue; + + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _predicate = predicate; + + _value = default(TSource); + _seenValue = false; + } + + public void OnNext(TSource value) + { + var b = false; + + try + { + b = _predicate(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + if (b) + { + _value = value; + _seenValue = true; + } + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnNext(_value); + base._observer.OnCompleted(); + base.Dispose(); + } + } + } + } +} diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/LongCount.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/LongCount.cs index ab033788d..20f10c5dc 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/LongCount.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/LongCount.cs @@ -4,118 +4,126 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class LongCount : Producer + internal static class LongCount { - private readonly IObservable _source; - private readonly Func _predicate; - - public LongCount(IObservable source) + internal sealed class All : Producer { - _source = source; - } + private readonly IObservable _source; - public LongCount(IObservable source, Func predicate) - { - _source = source; - _predicate = predicate; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_predicate == null) + public All(IObservable source) { - var sink = new _(observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new LongCountImpl(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - - class _ : Sink, IObserver - { - private long _count; - public _(IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver { - _count = 0L; - } + private long _count; - public void OnNext(TSource value) - { - try + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) { - checked + _count = 0L; + } + + public void OnNext(TSource value) + { + try { - _count++; + checked + { + _count++; + } + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); } } - catch (Exception ex) + + public void OnError(Exception error) { - base._observer.OnError(ex); + base._observer.OnError(error); base.Dispose(); } - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - public void OnCompleted() - { - base._observer.OnNext(_count); - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnNext(_count); + base._observer.OnCompleted(); + base.Dispose(); + } } } - class LongCountImpl : Sink, IObserver + internal sealed class Predicate : Producer { - private readonly LongCount _parent; - private long _count; + private readonly IObservable _source; + private readonly Func _predicate; - public LongCountImpl(LongCount parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Predicate(IObservable source, Func predicate) { - _parent = parent; - _count = 0L; + _source = source; + _predicate = predicate; } - public void OnNext(TSource value) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - try + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly Func _predicate; + private long _count; + + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _predicate = predicate; + _count = 0L; + } + + public void OnNext(TSource value) { - checked + try { - if (_parent._predicate(value)) - _count++; + checked + { + if (_predicate(value)) + { + _count++; + } + } + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); } } - catch (Exception ex) + + public void OnError(Exception error) { - base._observer.OnError(ex); + base._observer.OnError(error); base.Dispose(); } - } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - - public void OnCompleted() - { - base._observer.OnNext(_count); - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnNext(_count); + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Select.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Select.cs index 4fd33eb57..cc7833039 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Select.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Select.cs @@ -4,119 +4,125 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Select : Producer + internal static class Select { - private readonly IObservable _source; - private readonly Func _selector; - private readonly Func _selectorI; - - public Select(IObservable source, Func selector) - { - _source = source; - _selector = selector; - } - - public Select(IObservable source, Func selector) + internal sealed class Selector : Producer { - _source = source; - _selectorI = selector; - } + private readonly IObservable _source; + private readonly Func _selector; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_selector != null) + public Selector(IObservable source, Func selector) { - var sink = new _(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; + _selector = selector; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new SelectImpl(this, observer, cancel); + var sink = new _(_selector, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - - class _ : Sink, IObserver - { - private readonly Select _parent; - public _(Select parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver { - _parent = parent; - } + private readonly Func _selector; - public void OnNext(TSource value) - { - var result = default(TResult); - try + public _(Func selector, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - result = _parent._selector(value); + _selector = selector; } - catch (Exception exception) + + public void OnNext(TSource value) { - base._observer.OnError(exception); + var result = default(TResult); + try + { + result = _selector(value); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + base._observer.OnNext(result); + } + + public void OnError(Exception error) + { + base._observer.OnError(error); base.Dispose(); - return; } - base._observer.OnNext(result); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } + } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + internal sealed class SelectorIndexed : Producer + { + private readonly IObservable _source; + private readonly Func _selector; - public void OnCompleted() + public SelectorIndexed(IObservable source, Func selector) { - base._observer.OnCompleted(); - base.Dispose(); + _source = source; + _selector = selector; } - } - - class SelectImpl : Sink, IObserver - { - private readonly Select _parent; - private int _index; - public SelectImpl(Select parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _parent = parent; - _index = 0; + var sink = new _(_selector, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var result = default(TResult); - try + private readonly Func _selector; + private int _index; + + public _(Func selector, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - result = _parent._selectorI(value, checked(_index++)); + _selector = selector; + _index = 0; } - catch (Exception exception) + + public void OnNext(TSource value) { - base._observer.OnError(exception); - base.Dispose(); - return; + var result = default(TResult); + try + { + result = _selector(value, checked(_index++)); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + base._observer.OnNext(result); } - base._observer.OnNext(result); - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleAsync.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleAsync.cs index 782d2e30e..5e3c4bc2e 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleAsync.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleAsync.cs @@ -4,148 +4,154 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class SingleAsync : Producer + internal static class SingleAsync { - private readonly IObservable _source; - private readonly Func _predicate; - private readonly bool _throwOnEmpty; - - public SingleAsync(IObservable source, Func predicate, bool throwOnEmpty) + internal sealed class Sequence : Producer { - _source = source; - _predicate = predicate; - _throwOnEmpty = throwOnEmpty; - } + private readonly IObservable _source; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_predicate != null) + public Sequence(IObservable source) { - var sink = new SingleAsyncImpl(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - - class _ : Sink, IObserver - { - private readonly SingleAsync _parent; - private TSource _value; - private bool _seenValue; - public _(SingleAsync parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver { - _parent = parent; + private TSource _value; + private bool _seenValue; - _value = default(TSource); - _seenValue = false; - } - - public void OnNext(TSource value) - { - if (_seenValue) + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnError(new InvalidOperationException(Strings_Linq.MORE_THAN_ONE_ELEMENT)); - base.Dispose(); - return; + _value = default(TSource); + _seenValue = false; } - _value = value; - _seenValue = true; - } + public void OnNext(TSource value) + { + if (_seenValue) + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.MORE_THAN_ONE_ELEMENT)); + base.Dispose(); + return; + } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + _value = value; + _seenValue = true; + } - public void OnCompleted() - { - if (!_seenValue && _parent._throwOnEmpty) + public void OnError(Exception error) { - base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_ELEMENTS)); + base._observer.OnError(error); + base.Dispose(); } - else + + public void OnCompleted() { - base._observer.OnNext(_value); - base._observer.OnCompleted(); - } + if (!_seenValue) + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_ELEMENTS)); + } + else + { + base._observer.OnNext(_value); + base._observer.OnCompleted(); + } - base.Dispose(); + base.Dispose(); + } } } - class SingleAsyncImpl : Sink, IObserver + internal sealed class Predicate : Producer { - private readonly SingleAsync _parent; - private TSource _value; - private bool _seenValue; + private readonly IObservable _source; + private readonly Func _predicate; - public SingleAsyncImpl(SingleAsync parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Predicate(IObservable source, Func predicate) { - _parent = parent; + _source = source; + _predicate = predicate; + } - _value = default(TSource); - _seenValue = false; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var b = false; + private readonly Func _predicate; + private TSource _value; + private bool _seenValue; - try - { - b = _parent._predicate(value); - } - catch (Exception ex) + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnError(ex); - base.Dispose(); - return; + _predicate = predicate; + + _value = default(TSource); + _seenValue = false; } - if (b) + public void OnNext(TSource value) { - if (_seenValue) + var b = false; + + try { - base._observer.OnError(new InvalidOperationException(Strings_Linq.MORE_THAN_ONE_MATCHING_ELEMENT)); + b = _predicate(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); base.Dispose(); return; } - _value = value; - _seenValue = true; + if (b) + { + if (_seenValue) + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.MORE_THAN_ONE_MATCHING_ELEMENT)); + base.Dispose(); + return; + } + + _value = value; + _seenValue = true; + } } - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - public void OnCompleted() - { - if (!_seenValue && _parent._throwOnEmpty) + public void OnError(Exception error) { - base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_MATCHING_ELEMENTS)); + base._observer.OnError(error); + base.Dispose(); } - else + + public void OnCompleted() { - base._observer.OnNext(_value); - base._observer.OnCompleted(); - } + if (!_seenValue) + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_MATCHING_ELEMENTS)); + } + else + { + base._observer.OnNext(_value); + base._observer.OnCompleted(); + } - base.Dispose(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleOrDefaultAsync.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleOrDefaultAsync.cs new file mode 100644 index 000000000..2844329f6 --- /dev/null +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleOrDefaultAsync.cs @@ -0,0 +1,142 @@ +// 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. + +namespace System.Reactive.Linq.ObservableImpl +{ + internal static class SingleOrDefaultAsync + { + internal sealed class Sequence : Producer + { + private readonly IObservable _source; + + public Sequence(IObservable source) + { + _source = source; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private TSource _value; + private bool _seenValue; + + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _value = default(TSource); + _seenValue = false; + } + + public void OnNext(TSource value) + { + if (_seenValue) + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.MORE_THAN_ONE_ELEMENT)); + base.Dispose(); + return; + } + + _value = value; + _seenValue = true; + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnNext(_value); + base._observer.OnCompleted(); + base.Dispose(); + } + } + } + + internal sealed class Predicate : Producer + { + private readonly IObservable _source; + private readonly Func _predicate; + + public Predicate(IObservable source, Func predicate) + { + _source = source; + _predicate = predicate; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly Func _predicate; + private TSource _value; + private bool _seenValue; + + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _predicate = predicate; + + _value = default(TSource); + _seenValue = false; + } + + public void OnNext(TSource value) + { + var b = false; + + try + { + b = _predicate(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + if (b) + { + if (_seenValue) + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.MORE_THAN_ONE_MATCHING_ELEMENT)); + base.Dispose(); + return; + } + + _value = value; + _seenValue = true; + } + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnNext(_value); + base._observer.OnCompleted(); + base.Dispose(); + } + } + } + } +} diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Where.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Where.cs index 95bd47985..95373be9a 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Where.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Where.cs @@ -4,129 +4,136 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Where : Producer + internal static class Where { - private readonly IObservable _source; - private readonly Func _predicate; - private readonly Func _predicateI; - - public Where(IObservable source, Func predicate) - { - _source = source; - _predicate = predicate; - } - - public Where(IObservable source, Func predicate) + internal sealed class Predicate : Producer { - _source = source; - _predicateI = predicate; - } + private readonly IObservable _source; + private readonly Func _predicate; - public IObservable Combine(Func predicate) - { - if (_predicate != null) - return new Where(_source, x => _predicate(x) && predicate(x)); - else - return new Where(this, predicate); - } + public Predicate(IObservable source, Func predicate) + { + _source = source; + _predicate = predicate; + } - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_predicate != null) + public IObservable Combine(Func predicate) { - var sink = new _(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + return new Predicate(_source, x => _predicate(x) && predicate(x)); } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new WhereImpl(this, observer, cancel); + var sink = new _(_predicate, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - - class _ : Sink, IObserver - { - private readonly Where _parent; - public _(Where parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver { - _parent = parent; - } + private readonly Func _predicate; - public void OnNext(TSource value) - { - var shouldRun = default(bool); - try + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - shouldRun = _parent._predicate(value); + _predicate = predicate; } - catch (Exception exception) + + public void OnNext(TSource value) + { + var shouldRun = default(bool); + try + { + shouldRun = _predicate(value); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + if (shouldRun) + { + base._observer.OnNext(value); + } + } + + public void OnError(Exception error) { - base._observer.OnError(exception); + base._observer.OnError(error); base.Dispose(); - return; } - if (shouldRun) - base._observer.OnNext(value); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } + } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + internal sealed class PredicateIndexed : Producer + { + private readonly IObservable _source; + private readonly Func _predicate; - public void OnCompleted() + public PredicateIndexed(IObservable source, Func predicate) { - base._observer.OnCompleted(); - base.Dispose(); + _source = source; + _predicate = predicate; } - } - class WhereImpl : Sink, IObserver - { - private readonly Where _parent; - private int _index; - - public WhereImpl(Where parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _parent = parent; - _index = 0; + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var shouldRun = default(bool); - try + private readonly Func _predicate; + private int _index; + + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _predicate = predicate; + _index = 0; + } + + public void OnNext(TSource value) { - shouldRun = _parent._predicateI(value, checked(_index++)); + var shouldRun = default(bool); + try + { + shouldRun = _predicate(value, checked(_index++)); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + if (shouldRun) + { + base._observer.OnNext(value); + } } - catch (Exception exception) + + public void OnError(Exception error) { - base._observer.OnError(exception); + base._observer.OnError(error); base.Dispose(); - return; } - if (shouldRun) - base._observer.OnNext(value); - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs index a1b0163d9..9218bfbd9 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs @@ -94,12 +94,12 @@ public virtual IObservable All(IObservable source, Func< public virtual IObservable Any(IObservable source) { - return new Any(source); + return new Any.Count(source); } public virtual IObservable Any(IObservable source, Func predicate) { - return new Any(source, predicate); + return new Any.Predicate(source, predicate); } #endregion @@ -176,12 +176,12 @@ public virtual IObservable Contains(IObservable source, public virtual IObservable Count(IObservable source) { - return new Count(source); + return new Count.All(source); } public virtual IObservable Count(IObservable source, Func predicate) { - return new Count(source, predicate); + return new Count.Predicate(source, predicate); } #endregion @@ -208,12 +208,12 @@ public virtual IObservable ElementAtOrDefault(IObservable FirstAsync(IObservable source) { - return new FirstAsync(source, null, true); + return new FirstAsync.Sequence(source); } public virtual IObservable FirstAsync(IObservable source, Func predicate) { - return new FirstAsync(source, predicate, true); + return new FirstAsync.Predicate(source, predicate); } #endregion @@ -222,12 +222,12 @@ public virtual IObservable FirstAsync(IObservable sou public virtual IObservable FirstOrDefaultAsync(IObservable source) { - return new FirstAsync(source, null, false); + return new FirstOrDefaultAsync.Sequence(source); } public virtual IObservable FirstOrDefaultAsync(IObservable source, Func predicate) { - return new FirstAsync(source, predicate, false); + return new FirstOrDefaultAsync.Predicate(source, predicate); } #endregion @@ -245,12 +245,12 @@ public virtual IObservable IsEmpty(IObservable source) public virtual IObservable LastAsync(IObservable source) { - return new LastAsync(source, null, true); + return new LastAsync.Sequence(source); } public virtual IObservable LastAsync(IObservable source, Func predicate) { - return new LastAsync(source, predicate, true); + return new LastAsync.Predicate(source, predicate); } #endregion @@ -259,12 +259,12 @@ public virtual IObservable LastAsync(IObservable sour public virtual IObservable LastOrDefaultAsync(IObservable source) { - return new LastAsync(source, null, false); + return new LastOrDefaultAsync.Sequence(source); } public virtual IObservable LastOrDefaultAsync(IObservable source, Func predicate) { - return new LastAsync(source, predicate, false); + return new LastOrDefaultAsync.Predicate(source, predicate); } #endregion @@ -273,12 +273,12 @@ public virtual IObservable LastOrDefaultAsync(IObservable LongCount(IObservable source) { - return new LongCount(source); + return new LongCount.All(source); } public virtual IObservable LongCount(IObservable source, Func predicate) { - return new LongCount(source, predicate); + return new LongCount.Predicate(source, predicate); } #endregion @@ -591,12 +591,12 @@ public virtual IObservable SequenceEqual(IObservable fir public virtual IObservable SingleAsync(IObservable source) { - return new SingleAsync(source, null, true); + return new SingleAsync.Sequence(source); } public virtual IObservable SingleAsync(IObservable source, Func predicate) { - return new SingleAsync(source, predicate, true); + return new SingleAsync.Predicate(source, predicate); } #endregion @@ -605,12 +605,12 @@ public virtual IObservable SingleAsync(IObservable so public virtual IObservable SingleOrDefaultAsync(IObservable source) { - return new SingleAsync(source, null, false); + return new SingleOrDefaultAsync.Sequence(source); } public virtual IObservable SingleOrDefaultAsync(IObservable source, Func predicate) { - return new SingleAsync(source, predicate, false); + return new SingleOrDefaultAsync.Predicate(source, predicate); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs index 6b2f40a78..e68df38a1 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs @@ -199,12 +199,14 @@ public virtual IObservable OfType(IObservable source) public virtual IObservable Select(IObservable source, Func selector) { - return new Select(source, selector); + // CONSIDER: Add fusion for Select/Select pairs. + + return new Select.Selector(source, selector); } public virtual IObservable Select(IObservable source, Func selector) { - return new Select(source, selector); + return new Select.SelectorIndexed(source, selector); } #endregion @@ -412,16 +414,16 @@ public virtual IObservable TakeWhile(IObservable sour public virtual IObservable Where(IObservable source, Func predicate) { - var where = source as Where; + var where = source as Where.Predicate; if (where != null) return where.Combine(predicate); - return new Where(source, predicate); + return new Where.Predicate(source, predicate); } public virtual IObservable Where(IObservable source, Func predicate) { - return new Where(source, predicate); + return new Where.PredicateIndexed(source, predicate); } #endregion From ca2276d0b115205c3fa9d9b5aafecbb2720591ba Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 15:22:05 -0700 Subject: [PATCH 02/95] Optimize Aggregate layout. --- .../Linq/Observable/Aggregate.cs | 168 ++++++++++++------ .../Linq/QueryLanguage.Aggregates.cs | 2 +- 2 files changed, 115 insertions(+), 55 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs index c0ade29e6..68dcdefd7 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs @@ -4,50 +4,56 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Aggregate : Producer + internal sealed class Aggregate : Producer { private readonly IObservable _source; - private readonly TAccumulate _seed; - private readonly Func _accumulator; - private readonly Func _resultSelector; + private readonly Func _accumulator; - public Aggregate(IObservable source, TAccumulate seed, Func accumulator, Func resultSelector) + public Aggregate(IObservable source, Func accumulator) { _source = source; - _seed = seed; _accumulator = accumulator; - _resultSelector = resultSelector; } - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_accumulator, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Aggregate _parent; - private TAccumulate _accumulation; + private readonly Func _accumulator; + private TSource _accumulation; + private bool _hasAccumulation; - public _(Aggregate parent, IObserver observer, IDisposable cancel) + public _(Func accumulator, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - _accumulation = _parent._seed; + _accumulator = accumulator; + _accumulation = default(TSource); + _hasAccumulation = false; } public void OnNext(TSource value) { - try + if (!_hasAccumulation) { - _accumulation = _parent._accumulator(_accumulation, value); + _accumulation = value; + _hasAccumulation = true; } - catch (Exception exception) + else { - base._observer.OnError(exception); - base.Dispose(); + try + { + _accumulation = _accumulator(_accumulation, value); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + } } } @@ -59,75 +65,125 @@ public void OnError(Exception error) public void OnCompleted() { - var result = default(TResult); + if (!_hasAccumulation) + { + base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_ELEMENTS)); + base.Dispose(); + } + else + { + base._observer.OnNext(_accumulation); + base._observer.OnCompleted(); + base.Dispose(); + } + } + } + } + + internal sealed class Aggregate : Producer + { + private readonly IObservable _source; + private readonly TAccumulate _seed; + private readonly Func _accumulator; + + public Aggregate(IObservable source, TAccumulate seed, Func accumulator) + { + _source = source; + _seed = seed; + _accumulator = accumulator; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_seed, _accumulator, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly Func _accumulator; + private TAccumulate _accumulation; + + public _(TAccumulate seed, Func accumulator, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _accumulator = accumulator; + _accumulation = seed; + } + + public void OnNext(TSource value) + { try { - result = _parent._resultSelector(_accumulation); + _accumulation = _accumulator(_accumulation, value); } catch (Exception exception) { base._observer.OnError(exception); base.Dispose(); - return; } + } - base._observer.OnNext(result); + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnNext(_accumulation); base._observer.OnCompleted(); base.Dispose(); } } } - internal sealed class Aggregate : Producer + internal sealed class Aggregate : Producer { private readonly IObservable _source; - private readonly Func _accumulator; + private readonly TAccumulate _seed; + private readonly Func _accumulator; + private readonly Func _resultSelector; - public Aggregate(IObservable source, Func accumulator) + public Aggregate(IObservable source, TAccumulate seed, Func accumulator, Func resultSelector) { _source = source; + _seed = seed; _accumulator = accumulator; + _resultSelector = resultSelector; } - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { var sink = new _(this, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Aggregate _parent; - private TSource _accumulation; - private bool _hasAccumulation; + private readonly Aggregate _parent; + private TAccumulate _accumulation; - public _(Aggregate parent, IObserver observer, IDisposable cancel) + public _(Aggregate parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { _parent = parent; - _accumulation = default(TSource); - _hasAccumulation = false; + _accumulation = _parent._seed; } public void OnNext(TSource value) { - if (!_hasAccumulation) + try { - _accumulation = value; - _hasAccumulation = true; + _accumulation = _parent._accumulator(_accumulation, value); } - else + catch (Exception exception) { - try - { - _accumulation = _parent._accumulator(_accumulation, value); - } - catch (Exception exception) - { - base._observer.OnError(exception); - base.Dispose(); - } + base._observer.OnError(exception); + base.Dispose(); } } @@ -139,17 +195,21 @@ public void OnError(Exception error) public void OnCompleted() { - if (!_hasAccumulation) + var result = default(TResult); + try { - base._observer.OnError(new InvalidOperationException(Strings_Linq.NO_ELEMENTS)); - base.Dispose(); + result = _parent._resultSelector(_accumulation); } - else + catch (Exception exception) { - base._observer.OnNext(_accumulation); - base._observer.OnCompleted(); + base._observer.OnError(exception); base.Dispose(); + return; } + + base._observer.OnNext(result); + base._observer.OnCompleted(); + base.Dispose(); } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs index 9218bfbd9..75f98fa35 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs @@ -16,7 +16,7 @@ internal partial class QueryLanguage public virtual IObservable Aggregate(IObservable source, TAccumulate seed, Func accumulator) { - return new Aggregate(source, seed, accumulator, Stubs.I); + return new Aggregate(source, seed, accumulator); } public virtual IObservable Aggregate(IObservable source, TAccumulate seed, Func accumulator, Func resultSelector) From e3801c14ff888e8152982b7f4b708dee763af188 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 15:22:18 -0700 Subject: [PATCH 03/95] Optimize Catch layout. --- .../System.Reactive/Linq/Observable/Catch.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Catch.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Catch.cs index 34a87afb7..2b7e9b58c 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Catch.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Catch.cs @@ -23,7 +23,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return sink.Run(_sources); } - class _ : TailRecursiveSink + private sealed class _ : TailRecursiveSink { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) @@ -94,30 +94,30 @@ public Catch(IObservable source, Func> protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_handler, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Catch _parent; + private readonly Func> _handler; - public _(Catch parent, IObserver observer, IDisposable cancel) + public _(Func> handler, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _handler = handler; } private SerialDisposable _subscription; - public IDisposable Run() + public IDisposable Run(IObservable source) { _subscription = new SerialDisposable(); var d1 = new SingleAssignmentDisposable(); _subscription.Disposable = d1; - d1.Disposable = _parent._source.SubscribeSafe(this); + d1.Disposable = source.SubscribeSafe(this); return _subscription; } @@ -135,7 +135,7 @@ public void OnError(Exception error) var result = default(IObservable); try { - result = _parent._handler(e); + result = _handler(e); } catch (Exception ex) { @@ -146,7 +146,7 @@ public void OnError(Exception error) var d = new SingleAssignmentDisposable(); _subscription.Disposable = d; - d.Disposable = result.SubscribeSafe(new Impl(this)); + d.Disposable = result.SubscribeSafe(new HandlerObserver(this)); } else { @@ -161,11 +161,11 @@ public void OnCompleted() base.Dispose(); } - class Impl : IObserver + private sealed class HandlerObserver : IObserver { private readonly _ _parent; - public Impl(_ parent) + public HandlerObserver(_ parent) { _parent = parent; } From 71f078a6216a86ed3d1ec530e1ad43c2a32617ac Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 15:33:53 -0700 Subject: [PATCH 04/95] Optimizing CombineLatest layouts. --- .../Observable/CombineLatest.Generated.cs | 562 ++++++++---------- .../Observable/CombineLatest.Generated.tt | 24 +- .../Linq/Observable/CombineLatest.cs | 75 ++- 3 files changed, 307 insertions(+), 354 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.Generated.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.Generated.cs index d3ded501e..6d2a4af41 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.Generated.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.Generated.cs @@ -10,7 +10,7 @@ namespace System.Reactive.Linq.ObservableImpl /* The following code is generated by a T4 template. */ - #region CombineLatest auto-generated code (4/14/2017 12:18:58 PM) + #region CombineLatest auto-generated code (4/17/2017 3:25:27 PM) internal sealed class CombineLatest : Producer { @@ -29,26 +29,26 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(3, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; private CombineLatestObserver _observer2; private CombineLatestObserver _observer3; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3) { var subscriptions = new SingleAssignmentDisposable[3]; for (int i = 0; i < 3; i++) @@ -57,18 +57,15 @@ public IDisposable Run() _observer1 = new CombineLatestObserver(_gate, this, 0, subscriptions[0]); _observer2 = new CombineLatestObserver(_gate, this, 1, subscriptions[1]); _observer3 = new CombineLatestObserver(_gate, this, 2, subscriptions[2]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value); } } @@ -91,19 +88,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(4, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -111,7 +108,7 @@ public _(CombineLatest parent, IObserver obser private CombineLatestObserver _observer3; private CombineLatestObserver _observer4; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4) { var subscriptions = new SingleAssignmentDisposable[4]; for (int i = 0; i < 4; i++) @@ -121,19 +118,16 @@ public IDisposable Run() _observer2 = new CombineLatestObserver(_gate, this, 1, subscriptions[1]); _observer3 = new CombineLatestObserver(_gate, this, 2, subscriptions[2]); _observer4 = new CombineLatestObserver(_gate, this, 3, subscriptions[3]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value); } } @@ -158,19 +152,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(5, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -179,7 +173,7 @@ public _(CombineLatest parent, IObserver o private CombineLatestObserver _observer4; private CombineLatestObserver _observer5; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5) { var subscriptions = new SingleAssignmentDisposable[5]; for (int i = 0; i < 5; i++) @@ -190,20 +184,17 @@ public IDisposable Run() _observer3 = new CombineLatestObserver(_gate, this, 2, subscriptions[2]); _observer4 = new CombineLatestObserver(_gate, this, 3, subscriptions[3]); _observer5 = new CombineLatestObserver(_gate, this, 4, subscriptions[4]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value); } } @@ -230,19 +221,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(6, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -252,7 +243,7 @@ public _(CombineLatest parent, IObserver _observer5; private CombineLatestObserver _observer6; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6) { var subscriptions = new SingleAssignmentDisposable[6]; for (int i = 0; i < 6; i++) @@ -264,21 +255,18 @@ public IDisposable Run() _observer4 = new CombineLatestObserver(_gate, this, 3, subscriptions[3]); _observer5 = new CombineLatestObserver(_gate, this, 4, subscriptions[4]); _observer6 = new CombineLatestObserver(_gate, this, 5, subscriptions[5]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value); } } @@ -307,19 +295,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(7, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -330,7 +318,7 @@ public _(CombineLatest parent, IObserver _observer6; private CombineLatestObserver _observer7; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7) { var subscriptions = new SingleAssignmentDisposable[7]; for (int i = 0; i < 7; i++) @@ -343,22 +331,19 @@ public IDisposable Run() _observer5 = new CombineLatestObserver(_gate, this, 4, subscriptions[4]); _observer6 = new CombineLatestObserver(_gate, this, 5, subscriptions[5]); _observer7 = new CombineLatestObserver(_gate, this, 6, subscriptions[6]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value); } } @@ -389,19 +374,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(8, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -413,7 +398,7 @@ public _(CombineLatest parent, IObserve private CombineLatestObserver _observer7; private CombineLatestObserver _observer8; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8) { var subscriptions = new SingleAssignmentDisposable[8]; for (int i = 0; i < 8; i++) @@ -427,23 +412,20 @@ public IDisposable Run() _observer6 = new CombineLatestObserver(_gate, this, 5, subscriptions[5]); _observer7 = new CombineLatestObserver(_gate, this, 6, subscriptions[6]); _observer8 = new CombineLatestObserver(_gate, this, 7, subscriptions[7]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); - subscriptions[7].Disposable = _parent._source8.SubscribeSafe(_observer8); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); + subscriptions[7].Disposable = source8.SubscribeSafe(_observer8); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value); } } @@ -476,19 +458,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(9, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -501,7 +483,7 @@ public _(CombineLatest parent, IObs private CombineLatestObserver _observer8; private CombineLatestObserver _observer9; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9) { var subscriptions = new SingleAssignmentDisposable[9]; for (int i = 0; i < 9; i++) @@ -516,24 +498,21 @@ public IDisposable Run() _observer7 = new CombineLatestObserver(_gate, this, 6, subscriptions[6]); _observer8 = new CombineLatestObserver(_gate, this, 7, subscriptions[7]); _observer9 = new CombineLatestObserver(_gate, this, 8, subscriptions[8]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); - subscriptions[7].Disposable = _parent._source8.SubscribeSafe(_observer8); - subscriptions[8].Disposable = _parent._source9.SubscribeSafe(_observer9); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); + subscriptions[7].Disposable = source8.SubscribeSafe(_observer8); + subscriptions[8].Disposable = source9.SubscribeSafe(_observer9); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value); } } @@ -568,19 +547,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(10, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -594,7 +573,7 @@ public _(CombineLatest parent, private CombineLatestObserver _observer9; private CombineLatestObserver _observer10; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10) { var subscriptions = new SingleAssignmentDisposable[10]; for (int i = 0; i < 10; i++) @@ -610,25 +589,22 @@ public IDisposable Run() _observer8 = new CombineLatestObserver(_gate, this, 7, subscriptions[7]); _observer9 = new CombineLatestObserver(_gate, this, 8, subscriptions[8]); _observer10 = new CombineLatestObserver(_gate, this, 9, subscriptions[9]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); - subscriptions[7].Disposable = _parent._source8.SubscribeSafe(_observer8); - subscriptions[8].Disposable = _parent._source9.SubscribeSafe(_observer9); - subscriptions[9].Disposable = _parent._source10.SubscribeSafe(_observer10); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); + subscriptions[7].Disposable = source8.SubscribeSafe(_observer8); + subscriptions[8].Disposable = source9.SubscribeSafe(_observer9); + subscriptions[9].Disposable = source10.SubscribeSafe(_observer10); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value); } } @@ -665,19 +641,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(11, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -692,7 +668,7 @@ public _(CombineLatest pa private CombineLatestObserver _observer10; private CombineLatestObserver _observer11; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11) { var subscriptions = new SingleAssignmentDisposable[11]; for (int i = 0; i < 11; i++) @@ -709,26 +685,23 @@ public IDisposable Run() _observer9 = new CombineLatestObserver(_gate, this, 8, subscriptions[8]); _observer10 = new CombineLatestObserver(_gate, this, 9, subscriptions[9]); _observer11 = new CombineLatestObserver(_gate, this, 10, subscriptions[10]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); - subscriptions[7].Disposable = _parent._source8.SubscribeSafe(_observer8); - subscriptions[8].Disposable = _parent._source9.SubscribeSafe(_observer9); - subscriptions[9].Disposable = _parent._source10.SubscribeSafe(_observer10); - subscriptions[10].Disposable = _parent._source11.SubscribeSafe(_observer11); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); + subscriptions[7].Disposable = source8.SubscribeSafe(_observer8); + subscriptions[8].Disposable = source9.SubscribeSafe(_observer9); + subscriptions[9].Disposable = source10.SubscribeSafe(_observer10); + subscriptions[10].Disposable = source11.SubscribeSafe(_observer11); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value); } } @@ -767,19 +740,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(12, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -795,7 +768,7 @@ public _(CombineLatest _observer11; private CombineLatestObserver _observer12; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12) { var subscriptions = new SingleAssignmentDisposable[12]; for (int i = 0; i < 12; i++) @@ -813,27 +786,24 @@ public IDisposable Run() _observer10 = new CombineLatestObserver(_gate, this, 9, subscriptions[9]); _observer11 = new CombineLatestObserver(_gate, this, 10, subscriptions[10]); _observer12 = new CombineLatestObserver(_gate, this, 11, subscriptions[11]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); - subscriptions[7].Disposable = _parent._source8.SubscribeSafe(_observer8); - subscriptions[8].Disposable = _parent._source9.SubscribeSafe(_observer9); - subscriptions[9].Disposable = _parent._source10.SubscribeSafe(_observer10); - subscriptions[10].Disposable = _parent._source11.SubscribeSafe(_observer11); - subscriptions[11].Disposable = _parent._source12.SubscribeSafe(_observer12); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); + subscriptions[7].Disposable = source8.SubscribeSafe(_observer8); + subscriptions[8].Disposable = source9.SubscribeSafe(_observer9); + subscriptions[9].Disposable = source10.SubscribeSafe(_observer10); + subscriptions[10].Disposable = source11.SubscribeSafe(_observer11); + subscriptions[11].Disposable = source12.SubscribeSafe(_observer12); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value); } } @@ -874,19 +844,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12, _source13); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(13, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -903,7 +873,7 @@ public _(CombineLatest _observer12; private CombineLatestObserver _observer13; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12, IObservable source13) { var subscriptions = new SingleAssignmentDisposable[13]; for (int i = 0; i < 13; i++) @@ -922,28 +892,25 @@ public IDisposable Run() _observer11 = new CombineLatestObserver(_gate, this, 10, subscriptions[10]); _observer12 = new CombineLatestObserver(_gate, this, 11, subscriptions[11]); _observer13 = new CombineLatestObserver(_gate, this, 12, subscriptions[12]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); - subscriptions[7].Disposable = _parent._source8.SubscribeSafe(_observer8); - subscriptions[8].Disposable = _parent._source9.SubscribeSafe(_observer9); - subscriptions[9].Disposable = _parent._source10.SubscribeSafe(_observer10); - subscriptions[10].Disposable = _parent._source11.SubscribeSafe(_observer11); - subscriptions[11].Disposable = _parent._source12.SubscribeSafe(_observer12); - subscriptions[12].Disposable = _parent._source13.SubscribeSafe(_observer13); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); + subscriptions[7].Disposable = source8.SubscribeSafe(_observer8); + subscriptions[8].Disposable = source9.SubscribeSafe(_observer9); + subscriptions[9].Disposable = source10.SubscribeSafe(_observer10); + subscriptions[10].Disposable = source11.SubscribeSafe(_observer11); + subscriptions[11].Disposable = source12.SubscribeSafe(_observer12); + subscriptions[12].Disposable = source13.SubscribeSafe(_observer13); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value, _observer13.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value, _observer13.Value); } } @@ -986,19 +953,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12, _source13, _source14); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(14, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -1016,7 +983,7 @@ public _(CombineLatest _observer13; private CombineLatestObserver _observer14; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12, IObservable source13, IObservable source14) { var subscriptions = new SingleAssignmentDisposable[14]; for (int i = 0; i < 14; i++) @@ -1036,29 +1003,26 @@ public IDisposable Run() _observer12 = new CombineLatestObserver(_gate, this, 11, subscriptions[11]); _observer13 = new CombineLatestObserver(_gate, this, 12, subscriptions[12]); _observer14 = new CombineLatestObserver(_gate, this, 13, subscriptions[13]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); - subscriptions[7].Disposable = _parent._source8.SubscribeSafe(_observer8); - subscriptions[8].Disposable = _parent._source9.SubscribeSafe(_observer9); - subscriptions[9].Disposable = _parent._source10.SubscribeSafe(_observer10); - subscriptions[10].Disposable = _parent._source11.SubscribeSafe(_observer11); - subscriptions[11].Disposable = _parent._source12.SubscribeSafe(_observer12); - subscriptions[12].Disposable = _parent._source13.SubscribeSafe(_observer13); - subscriptions[13].Disposable = _parent._source14.SubscribeSafe(_observer14); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); + subscriptions[7].Disposable = source8.SubscribeSafe(_observer8); + subscriptions[8].Disposable = source9.SubscribeSafe(_observer9); + subscriptions[9].Disposable = source10.SubscribeSafe(_observer10); + subscriptions[10].Disposable = source11.SubscribeSafe(_observer11); + subscriptions[11].Disposable = source12.SubscribeSafe(_observer12); + subscriptions[12].Disposable = source13.SubscribeSafe(_observer13); + subscriptions[13].Disposable = source14.SubscribeSafe(_observer14); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value, _observer13.Value, _observer14.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value, _observer13.Value, _observer14.Value); } } @@ -1103,19 +1067,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12, _source13, _source14, _source15); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(15, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -1134,7 +1098,7 @@ public _(CombineLatest _observer14; private CombineLatestObserver _observer15; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12, IObservable source13, IObservable source14, IObservable source15) { var subscriptions = new SingleAssignmentDisposable[15]; for (int i = 0; i < 15; i++) @@ -1155,30 +1119,27 @@ public IDisposable Run() _observer13 = new CombineLatestObserver(_gate, this, 12, subscriptions[12]); _observer14 = new CombineLatestObserver(_gate, this, 13, subscriptions[13]); _observer15 = new CombineLatestObserver(_gate, this, 14, subscriptions[14]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); - subscriptions[7].Disposable = _parent._source8.SubscribeSafe(_observer8); - subscriptions[8].Disposable = _parent._source9.SubscribeSafe(_observer9); - subscriptions[9].Disposable = _parent._source10.SubscribeSafe(_observer10); - subscriptions[10].Disposable = _parent._source11.SubscribeSafe(_observer11); - subscriptions[11].Disposable = _parent._source12.SubscribeSafe(_observer12); - subscriptions[12].Disposable = _parent._source13.SubscribeSafe(_observer13); - subscriptions[13].Disposable = _parent._source14.SubscribeSafe(_observer14); - subscriptions[14].Disposable = _parent._source15.SubscribeSafe(_observer15); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); + subscriptions[7].Disposable = source8.SubscribeSafe(_observer8); + subscriptions[8].Disposable = source9.SubscribeSafe(_observer9); + subscriptions[9].Disposable = source10.SubscribeSafe(_observer10); + subscriptions[10].Disposable = source11.SubscribeSafe(_observer11); + subscriptions[11].Disposable = source12.SubscribeSafe(_observer12); + subscriptions[12].Disposable = source13.SubscribeSafe(_observer13); + subscriptions[13].Disposable = source14.SubscribeSafe(_observer14); + subscriptions[14].Disposable = source15.SubscribeSafe(_observer15); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value, _observer13.Value, _observer14.Value, _observer15.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value, _observer13.Value, _observer14.Value, _observer15.Value); } } @@ -1225,19 +1186,19 @@ public CombineLatest(IObservable source1, IObservable source2, IObservab protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12, _source13, _source14, _source15, _source16); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(16, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private CombineLatestObserver _observer1; @@ -1257,7 +1218,7 @@ public _(CombineLatest _observer15; private CombineLatestObserver _observer16; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12, IObservable source13, IObservable source14, IObservable source15, IObservable source16) { var subscriptions = new SingleAssignmentDisposable[16]; for (int i = 0; i < 16; i++) @@ -1279,31 +1240,28 @@ public IDisposable Run() _observer14 = new CombineLatestObserver(_gate, this, 13, subscriptions[13]); _observer15 = new CombineLatestObserver(_gate, this, 14, subscriptions[14]); _observer16 = new CombineLatestObserver(_gate, this, 15, subscriptions[15]); - - subscriptions[0].Disposable = _parent._source1.SubscribeSafe(_observer1); - subscriptions[1].Disposable = _parent._source2.SubscribeSafe(_observer2); - subscriptions[2].Disposable = _parent._source3.SubscribeSafe(_observer3); - subscriptions[3].Disposable = _parent._source4.SubscribeSafe(_observer4); - subscriptions[4].Disposable = _parent._source5.SubscribeSafe(_observer5); - subscriptions[5].Disposable = _parent._source6.SubscribeSafe(_observer6); - subscriptions[6].Disposable = _parent._source7.SubscribeSafe(_observer7); - subscriptions[7].Disposable = _parent._source8.SubscribeSafe(_observer8); - subscriptions[8].Disposable = _parent._source9.SubscribeSafe(_observer9); - subscriptions[9].Disposable = _parent._source10.SubscribeSafe(_observer10); - subscriptions[10].Disposable = _parent._source11.SubscribeSafe(_observer11); - subscriptions[11].Disposable = _parent._source12.SubscribeSafe(_observer12); - subscriptions[12].Disposable = _parent._source13.SubscribeSafe(_observer13); - subscriptions[13].Disposable = _parent._source14.SubscribeSafe(_observer14); - subscriptions[14].Disposable = _parent._source15.SubscribeSafe(_observer15); - subscriptions[15].Disposable = _parent._source16.SubscribeSafe(_observer16); + + subscriptions[0].Disposable = source1.SubscribeSafe(_observer1); + subscriptions[1].Disposable = source2.SubscribeSafe(_observer2); + subscriptions[2].Disposable = source3.SubscribeSafe(_observer3); + subscriptions[3].Disposable = source4.SubscribeSafe(_observer4); + subscriptions[4].Disposable = source5.SubscribeSafe(_observer5); + subscriptions[5].Disposable = source6.SubscribeSafe(_observer6); + subscriptions[6].Disposable = source7.SubscribeSafe(_observer7); + subscriptions[7].Disposable = source8.SubscribeSafe(_observer8); + subscriptions[8].Disposable = source9.SubscribeSafe(_observer9); + subscriptions[9].Disposable = source10.SubscribeSafe(_observer10); + subscriptions[10].Disposable = source11.SubscribeSafe(_observer11); + subscriptions[11].Disposable = source12.SubscribeSafe(_observer12); + subscriptions[12].Disposable = source13.SubscribeSafe(_observer13); + subscriptions[13].Disposable = source14.SubscribeSafe(_observer14); + subscriptions[14].Disposable = source15.SubscribeSafe(_observer15); + subscriptions[15].Disposable = source16.SubscribeSafe(_observer16); return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value, _observer13.Value, _observer14.Value, _observer15.Value, _observer16.Value); - } + protected override TResult GetResult() => _resultSelector(_observer1.Value, _observer2.Value, _observer3.Value, _observer4.Value, _observer5.Value, _observer6.Value, _observer7.Value, _observer8.Value, _observer9.Value, _observer10.Value, _observer11.Value, _observer12.Value, _observer13.Value, _observer14.Value, _observer15.Value, _observer16.Value); } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.Generated.tt b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.Generated.tt index 73bcaa64e..edf0dcb68 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.Generated.tt +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.Generated.tt @@ -24,6 +24,7 @@ for (var i = 3; i <= 16; i++) var ts = string.Join(", ", Enumerable.Range(1, i).Select(j => "T" + j)); var os = string.Join(", ", Enumerable.Range(1, i).Select(j => "IObservable source" + j)); var vs = string.Join(", ", Enumerable.Range(1, i).Select(j => "_observer" + j + ".Value")); + var ss = string.Join(", ", Enumerable.Range(1, i).Select(j => "_source" + j)); #> internal sealed class CombineLatest<<#=ts#>, TResult> : Producer { @@ -52,19 +53,19 @@ for (var j = 1; j <= i; j++) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(<#=ss#>); } - class _ : CombineLatestSink + private sealed class _ : CombineLatestSink { - private readonly CombineLatest<<#=ts#>, TResult> _parent; + private readonly Func<<#=ts#>, TResult> _resultSelector; - public _(CombineLatest<<#=ts#>, TResult> parent, IObserver observer, IDisposable cancel) + public _(Func<<#=ts#>, TResult> resultSelector, IObserver observer, IDisposable cancel) : base(<#=i#>, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } <# @@ -76,7 +77,7 @@ for (var j = 1; j <= i; j++) } #> - public IDisposable Run() + public IDisposable Run(<#=os#>) { var subscriptions = new SingleAssignmentDisposable[<#=i#>]; for (int i = 0; i < <#=i#>; i++) @@ -90,12 +91,12 @@ for (var j = 1; j <= i; j++) <# } #> - + <# for (var j = 1; j <= i; j++) { #> - subscriptions[<#=j - 1#>].Disposable = _parent._source<#=j#>.SubscribeSafe(_observer<#=j#>); + subscriptions[<#=j - 1#>].Disposable = source<#=j#>.SubscribeSafe(_observer<#=j#>); <# } #> @@ -103,10 +104,7 @@ for (var j = 1; j <= i; j++) return StableCompositeDisposable.Create(subscriptions); } - protected override TResult GetResult() - { - return _parent._resultSelector(<#=vs#>); - } + protected override TResult GetResult() => _resultSelector(<#=vs#>); } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs index b1668cd49..7690ed84a 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs @@ -26,55 +26,55 @@ public CombineLatest(IObservable first, IObservable second, Fun protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_first, _second); } - class _ : Sink + private sealed class _ : Sink { - private readonly CombineLatest _parent; + private readonly Func _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private object _gate; - public IDisposable Run() + public IDisposable Run(IObservable first, IObservable second) { _gate = new object(); var fstSubscription = new SingleAssignmentDisposable(); var sndSubscription = new SingleAssignmentDisposable(); - var fstO = new F(this, fstSubscription); - var sndO = new S(this, sndSubscription); + var fstO = new FirstObserver(this, fstSubscription); + var sndO = new SecondObserver(this, sndSubscription); fstO.Other = sndO; sndO.Other = fstO; - fstSubscription.Disposable = _parent._first.SubscribeSafe(fstO); - sndSubscription.Disposable = _parent._second.SubscribeSafe(sndO); + fstSubscription.Disposable = first.SubscribeSafe(fstO); + sndSubscription.Disposable = second.SubscribeSafe(sndO); return StableCompositeDisposable.Create(fstSubscription, sndSubscription); } - class F : IObserver + private sealed class FirstObserver : IObserver { private readonly _ _parent; private readonly IDisposable _self; - private S _other; + private SecondObserver _other; - public F(_ parent, IDisposable self) + public FirstObserver(_ parent, IDisposable self) { _parent = parent; _self = self; } - public S Other { set { _other = value; } } + public SecondObserver Other { set { _other = value; } } public bool HasValue { get; private set; } public TFirst Value { get; private set; } @@ -92,7 +92,7 @@ public void OnNext(TFirst value) var res = default(TResult); try { - res = _parent._parent._resultSelector(value, _other.Value); + res = _parent._resultSelector(value, _other.Value); } catch (Exception ex) { @@ -141,19 +141,19 @@ public void OnCompleted() } } - class S : IObserver + private sealed class SecondObserver : IObserver { private readonly _ _parent; private readonly IDisposable _self; - private F _other; + private FirstObserver _other; - public S(_ parent, IDisposable self) + public SecondObserver(_ parent, IDisposable self) { _parent = parent; _self = self; } - public F Other { set { _other = value; } } + public FirstObserver Other { set { _other = value; } } public bool HasValue { get; private set; } public TSecond Value { get; private set; } @@ -171,7 +171,7 @@ public void OnNext(TSecond value) var res = default(TResult); try { - res = _parent._parent._resultSelector(_other.Value, value); + res = _parent._resultSelector(_other.Value, value); } catch (Exception ex) { @@ -228,14 +228,14 @@ public void OnCompleted() #region Helpers for n-ary overloads - interface ICombineLatest + internal interface ICombineLatest { void Next(int index); void Fail(Exception error); void Done(int index); } - abstract class CombineLatestSink : Sink, ICombineLatest + internal abstract class CombineLatestSink : Sink, ICombineLatest { protected readonly object _gate; @@ -354,10 +354,7 @@ public CombineLatestObserver(object gate, ICombineLatest parent, int index, IDis _self = self; } - public T Value - { - get { return _value; } - } + public T Value => _value; public void OnNext(T value) { @@ -408,19 +405,19 @@ public CombineLatest(IEnumerable> sources, Func observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_sources); } - class _ : Sink + private sealed class _ : Sink { - private readonly CombineLatest _parent; + private readonly Func, TResult> _resultSelector; - public _(CombineLatest parent, IObserver observer, IDisposable cancel) + public _(Func, TResult> resultSelector, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private object _gate; @@ -430,9 +427,9 @@ public _(CombineLatest parent, IObserver observer, ID private bool[] _isDone; private IDisposable[] _subscriptions; - public IDisposable Run() + public IDisposable Run(IEnumerable> sources) { - var srcs = _parent._sources.ToArray(); + var srcs = sources.ToArray(); var N = srcs.Length; @@ -456,7 +453,7 @@ public IDisposable Run() var d = new SingleAssignmentDisposable(); _subscriptions[j] = d; - var o = new O(this, j); + var o = new SourceObserver(this, j); d.Disposable = srcs[j].SubscribeSafe(o); } @@ -476,7 +473,7 @@ private void OnNext(int index, TSource value) var res = default(TResult); try { - res = _parent._resultSelector(new ReadOnlyCollection(_values)); + res = _resultSelector(new ReadOnlyCollection(_values)); } catch (Exception ex) { @@ -524,12 +521,12 @@ private void OnCompleted(int index) } } - class O : IObserver + private sealed class SourceObserver : IObserver { private readonly _ _parent; private readonly int _index; - public O(_ parent, int index) + public SourceObserver(_ parent, int index) { _parent = parent; _index = index; From 5d7f07d809722bc786f086acd55681cb9964a387 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 15:40:26 -0700 Subject: [PATCH 05/95] Reducing usage of LINQ in CombineLatest. --- .../Linq/Observable/CombineLatest.cs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs index 7690ed84a..2fbf638bc 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs @@ -468,7 +468,7 @@ private void OnNext(int index, TSource value) _hasValue[index] = true; - if (_hasValueAll || (_hasValueAll = _hasValue.All(Stubs.I))) + if (_hasValueAll || (_hasValueAll = All(_hasValue))) { var res = default(TResult); try @@ -484,7 +484,7 @@ private void OnNext(int index, TSource value) _observer.OnNext(res); } - else if (_isDone.Where((x, i) => i != index).All(Stubs.I)) + else if (AllExcept(_isDone, index)) { base._observer.OnCompleted(); base.Dispose(); @@ -508,7 +508,7 @@ private void OnCompleted(int index) { _isDone[index] = true; - if (_isDone.All(Stubs.I)) + if (All(_isDone)) { base._observer.OnCompleted(); base.Dispose(); @@ -521,6 +521,35 @@ private void OnCompleted(int index) } } + private static bool All(bool[] values) + { + foreach (var value in values) + { + if (!value) + { + return false; + } + } + + return true; + } + + private static bool AllExcept(bool[] values, int index) + { + for (var i = 0; i < values.Length; i++) + { + if (i != index) + { + if (!values[i]) + { + return false; + } + } + } + + return true; + } + private sealed class SourceObserver : IObserver { private readonly _ _parent; From 73d9a3d6ed616740d8f08d7bd0641a83389c99c4 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 15:45:01 -0700 Subject: [PATCH 06/95] Optimizing layout of DefaultIfEmpty. --- .../Linq/Observable/DefaultIfEmpty.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DefaultIfEmpty.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DefaultIfEmpty.cs index 92d8d27e0..4a1473a20 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DefaultIfEmpty.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DefaultIfEmpty.cs @@ -17,20 +17,20 @@ public DefaultIfEmpty(IObservable source, TSource defaultValue) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_defaultValue, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly DefaultIfEmpty _parent; + private readonly TSource _defaultValue; private bool _found; - public _(DefaultIfEmpty parent, IObserver observer, IDisposable cancel) + public _(TSource defaultValue, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _defaultValue = defaultValue; _found = false; } @@ -49,7 +49,7 @@ public void OnError(Exception error) public void OnCompleted() { if (!_found) - base._observer.OnNext(_parent._defaultValue); + base._observer.OnNext(_defaultValue); base._observer.OnCompleted(); base.Dispose(); } From 3e806862e5aeaebfa3b9236fb43d6b6636e53284 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 15:45:12 -0700 Subject: [PATCH 07/95] Optimizing layout of Defer. --- .../System.Reactive/Linq/Observable/Defer.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Defer.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Defer.cs index c53ab6e31..87ba5932c 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Defer.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Defer.cs @@ -17,24 +17,21 @@ public Defer(Func> observableFactory) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_observableFactory, observer, cancel); setSink(sink); return sink.Run(); } - public IObservable Eval() - { - return _observableFactory(); - } + public IObservable Eval() => _observableFactory(); - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Defer _parent; + private readonly Func> _observableFactory; - public _(Defer parent, IObserver observer, IDisposable cancel) + public _(Func> observableFactory, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _observableFactory = observableFactory; } public IDisposable Run() @@ -42,7 +39,7 @@ public IDisposable Run() var result = default(IObservable); try { - result = _parent.Eval(); + result = _observableFactory(); } catch (Exception exception) { From 46db24cc40606a35534a5880c7fae2c7a49e2270 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 15:51:43 -0700 Subject: [PATCH 08/95] Sealing sinks of Materialize and Dematerialize. --- .../src/System.Reactive/Linq/Observable/Dematerialize.cs | 2 +- .../src/System.Reactive/Linq/Observable/Materialize.cs | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Dematerialize.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Dematerialize.cs index 0bcb6531c..ebf0e6b6f 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Dematerialize.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Dematerialize.cs @@ -20,7 +20,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver> + private sealed class _ : Sink, IObserver> { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Materialize.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Materialize.cs index f1fa7bd38..5c5c12495 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Materialize.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Materialize.cs @@ -13,10 +13,7 @@ public Materialize(IObservable source) _source = source; } - public IObservable Dematerialize() - { - return _source.AsObservable(); - } + public IObservable Dematerialize() => _source.AsObservable(); protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { @@ -25,7 +22,7 @@ protected override IDisposable Run(IObserver> observer, ID return _source.SubscribeSafe(sink); } - class _ : Sink>, IObserver + private sealed class _ : Sink>, IObserver { public _(IObserver> observer, IDisposable cancel) : base(observer, cancel) From fba2b05159fde120a7a830bb6e35c96bc118b415 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 15:53:24 -0700 Subject: [PATCH 09/95] Optimizing layout of Distinct. --- .../src/System.Reactive/Linq/Observable/Distinct.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Distinct.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Distinct.cs index 1c3ff41ee..ea0c07954 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Distinct.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Distinct.cs @@ -28,14 +28,14 @@ protected override IDisposable Run(IObserver observer, IDisposable canc class _ : Sink, IObserver { - private readonly Distinct _parent; + private readonly Func _keySelector; private HashSet _hashSet; public _(Distinct parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - _hashSet = new HashSet(_parent._comparer); + _keySelector = parent._keySelector; + _hashSet = new HashSet(parent._comparer); } public void OnNext(TSource value) @@ -44,7 +44,7 @@ public void OnNext(TSource value) var hasAdded = false; try { - key = _parent._keySelector(value); + key = _keySelector(value); hasAdded = _hashSet.Add(key); } catch (Exception exception) From 83da56e9c94931efdece591a89424ffefb893482 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:02:03 -0700 Subject: [PATCH 10/95] Specializing layouts of Do. --- .../src/System.Reactive/Linq/Observable/Do.cs | 237 ++++++++++++++---- .../Linq/QueryLanguage.Single.cs | 6 +- 2 files changed, 192 insertions(+), 51 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs index b7187b5ff..6c443645b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs @@ -4,86 +4,227 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Do : Producer + internal static class Do { - private readonly IObservable _source; - private readonly Action _onNext; - private readonly Action _onError; - private readonly Action _onCompleted; - - public Do(IObservable source, Action onNext, Action onError, Action onCompleted) - { - _source = source; - _onNext = onNext; - _onError = onError; - _onCompleted = onCompleted; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + internal sealed class OnNext : Producer { - var sink = new _(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); - } + private readonly IObservable _source; + private readonly Action _onNext; - class _ : Sink, IObserver - { - private readonly Do _parent; + public OnNext(IObservable source, Action onNext) + { + _source = source; + _onNext = onNext; + } - public _(Do parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _parent = parent; + var sink = new _(_onNext, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - try + private readonly Action _onNext; + + public _(Action onNext, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - _parent._onNext(value); + _onNext = onNext; } - catch (Exception ex) + + public void OnNext(TSource value) { - base._observer.OnError(ex); + try + { + _onNext(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + base._observer.OnNext(value); + } + + public void OnError(Exception error) + { + base._observer.OnError(error); base.Dispose(); - return; } - base._observer.OnNext(value); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } + } + } + + internal sealed class Observer : Producer + { + private readonly IObservable _source; + private readonly IObserver _observer; + + public Observer(IObservable source, IObserver observer) + { + _source = source; + _observer = observer; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_observer, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnError(Exception error) + private sealed class _ : Sink, IObserver { - try + private readonly IObserver _doObserver; + + public _(IObserver doObserver, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - _parent._onError(error); + _doObserver = doObserver; } - catch (Exception ex) + + public void OnNext(TSource value) { - base._observer.OnError(ex); + try + { + _doObserver.OnNext(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + base._observer.OnNext(value); + } + + public void OnError(Exception error) + { + try + { + _doObserver.OnError(error); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + try + { + _doObserver.OnCompleted(); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + base._observer.OnCompleted(); base.Dispose(); - return; } + } + } + + internal sealed class Actions : Producer + { + private readonly IObservable _source; + private readonly Action _onNext; + private readonly Action _onError; + private readonly Action _onCompleted; + + public Actions(IObservable source, Action onNext, Action onError, Action onCompleted) + { + _source = source; + _onNext = onNext; + _onError = onError; + _onCompleted = onCompleted; + } - base._observer.OnError(error); - base.Dispose(); + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnCompleted() + private sealed class _ : Sink, IObserver { - try + private readonly Actions _parent; + + public _(Actions parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _parent = parent; + } + + public void OnNext(TSource value) { - _parent._onCompleted(); + try + { + _parent._onNext(value); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + base._observer.OnNext(value); } - catch (Exception ex) + + public void OnError(Exception error) { - base._observer.OnError(ex); + try + { + _parent._onError(error); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + base._observer.OnError(error); base.Dispose(); - return; } - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + try + { + _parent._onCompleted(); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs index 91e0681a4..c62762a83 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs @@ -92,7 +92,7 @@ private static IObservable DistinctUntilChanged_(IObserv public virtual IObservable Do(IObservable source, Action onNext) { - return Do_(source, onNext, Stubs.Ignore, Stubs.Nop); + return new Do.OnNext(source, onNext); } public virtual IObservable Do(IObservable source, Action onNext, Action onCompleted) @@ -112,12 +112,12 @@ public virtual IObservable Do(IObservable source, Act public virtual IObservable Do(IObservable source, IObserver observer) { - return Do_(source, observer.OnNext, observer.OnError, observer.OnCompleted); + return new Do.Observer(source, observer); } private static IObservable Do_(IObservable source, Action onNext, Action onError, Action onCompleted) { - return new Do(source, onNext, onError, onCompleted); + return new Do.Actions(source, onNext, onError, onCompleted); } #endregion From 40fdad300db12ae1dade8be782bc0287bbf9c2b7 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:09:24 -0700 Subject: [PATCH 11/95] Sealing some sinks. --- .../System.Reactive/Linq/Observable/AddRef.cs | 2 +- .../Linq/Observable/AsObservable.cs | 7 ++----- .../Linq/Observable/Average.cs | 20 +++++++++---------- .../System.Reactive/Linq/Observable/Case.cs | 2 +- .../System.Reactive/Linq/Observable/Cast.cs | 2 +- .../Linq/Observable/Collect.cs | 2 +- .../System.Reactive/Linq/Observable/Concat.cs | 7 ++----- .../Linq/Observable/Contains.cs | 2 +- .../Linq/Observable/DelaySubscription.cs | 2 +- .../Linq/Observable/DoWhile.cs | 2 +- 10 files changed, 21 insertions(+), 27 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/AddRef.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/AddRef.cs index edaf838db..8b1e3ff2d 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/AddRef.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/AddRef.cs @@ -26,7 +26,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/AsObservable.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/AsObservable.cs index 537d76d96..891100cdb 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/AsObservable.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/AsObservable.cs @@ -13,10 +13,7 @@ public AsObservable(IObservable source) _source = source; } - public IObservable Eval() - { - return _source; - } + public IObservable Eval() => _source; protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { @@ -25,7 +22,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Average.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Average.cs index fbab56c26..c608eb308 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Average.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Average.cs @@ -20,7 +20,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double _sum; private long _count; @@ -88,7 +88,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double _sum; // NOTE: Uses a different accumulator type (double), conform LINQ to Objects. private long _count; @@ -156,7 +156,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private decimal _sum; private long _count; @@ -224,7 +224,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private long _sum; private long _count; @@ -292,7 +292,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private long _sum; private long _count; @@ -360,7 +360,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double _sum; private long _count; @@ -431,7 +431,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double _sum; // NOTE: Uses a different accumulator type (double), conform LINQ to Objects. private long _count; @@ -502,7 +502,7 @@ protected override IDisposable Run(IObserver observer, IDisposable can return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private decimal _sum; private long _count; @@ -573,7 +573,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private long _sum; private long _count; @@ -644,7 +644,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private long _sum; private long _count; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Case.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Case.cs index 9c67036b4..60405eda3 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Case.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Case.cs @@ -36,7 +36,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return sink.Run(); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private readonly Case _parent; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Cast.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Cast.cs index 8f3b12667..5b4247383 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Cast.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Cast.cs @@ -20,7 +20,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Collect.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Collect.cs index 7e18bd159..64011836b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Collect.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Collect.cs @@ -25,7 +25,7 @@ protected override PushToPullSink Run(IDisposable subscription return sink; } - class _ : PushToPullSink + private sealed class _ : PushToPullSink { private readonly Collect _parent; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Concat.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Concat.cs index b80b19f12..018fab163 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Concat.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Concat.cs @@ -22,12 +22,9 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return sink.Run(_sources); } - public IEnumerable> GetSources() - { - return _sources; - } + public IEnumerable> GetSources() => _sources; - class _ : ConcatSink + private sealed class _ : ConcatSink { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs index 70fb40d0a..e22568352 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs @@ -26,7 +26,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private readonly Contains _parent; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DelaySubscription.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DelaySubscription.cs index 2398b88be..6878b8a94 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DelaySubscription.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DelaySubscription.cs @@ -47,7 +47,7 @@ private IDisposable Subscribe(IScheduler _, _ sink) return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DoWhile.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DoWhile.cs index 7841a3545..3435d673b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DoWhile.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DoWhile.cs @@ -31,7 +31,7 @@ public IEnumerable> GetSources() yield return _source; } - class _ : ConcatSink + private sealed class _ : ConcatSink { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) From ad3ed2dc86be12c927868d18beafcaa107426c97 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:09:32 -0700 Subject: [PATCH 12/95] Optimizing ElementAt layouts. --- .../Linq/Observable/ElementAt.cs | 25 ++------ .../Linq/Observable/ElementAtOrDefault.cs | 61 +++++++++++++++++++ .../Linq/QueryLanguage.Aggregates.cs | 4 +- 3 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 Rx.NET/Source/src/System.Reactive/Linq/Observable/ElementAtOrDefault.cs diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ElementAt.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ElementAt.cs index f6c5b81c8..228f3691b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ElementAt.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ElementAt.cs @@ -8,32 +8,28 @@ internal sealed class ElementAt : Producer { private readonly IObservable _source; private readonly int _index; - private readonly bool _throwOnEmpty; - public ElementAt(IObservable source, int index, bool throwOnEmpty) + public ElementAt(IObservable source, int index) { _source = source; _index = index; - _throwOnEmpty = throwOnEmpty; } protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_index, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly ElementAt _parent; private int _i; - public _(ElementAt parent, IObserver observer, IDisposable cancel) + public _(int index, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - _i = _parent._index; + _i = index; } public void OnNext(TSource value) @@ -56,16 +52,7 @@ public void OnError(Exception error) public void OnCompleted() { - if (_parent._throwOnEmpty) - { - base._observer.OnError(new ArgumentOutOfRangeException("index")); - } - else - { - base._observer.OnNext(default(TSource)); - base._observer.OnCompleted(); - } - + base._observer.OnError(new ArgumentOutOfRangeException("index")); base.Dispose(); } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ElementAtOrDefault.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ElementAtOrDefault.cs new file mode 100644 index 000000000..090ee8ca7 --- /dev/null +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ElementAtOrDefault.cs @@ -0,0 +1,61 @@ +// 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. + +namespace System.Reactive.Linq.ObservableImpl +{ + internal sealed class ElementAtOrDefault : Producer + { + private readonly IObservable _source; + private readonly int _index; + + public ElementAtOrDefault(IObservable source, int index) + { + _source = source; + _index = index; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_index, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private int _i; + + public _(int index, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _i = index; + } + + public void OnNext(TSource value) + { + if (_i == 0) + { + base._observer.OnNext(value); + base._observer.OnCompleted(); + base.Dispose(); + } + + _i--; + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnNext(default(TSource)); + base._observer.OnCompleted(); + base.Dispose(); + } + } + } +} diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs index 75f98fa35..f24f8afe1 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs @@ -190,7 +190,7 @@ public virtual IObservable Count(IObservable source, Func public virtual IObservable ElementAt(IObservable source, int index) { - return new ElementAt(source, index, true); + return new ElementAt(source, index); } #endregion @@ -199,7 +199,7 @@ public virtual IObservable ElementAt(IObservable sour public virtual IObservable ElementAtOrDefault(IObservable source, int index) { - return new ElementAt(source, index, false); + return new ElementAtOrDefault(source, index); } #endregion From 8b8ae3f89c7623b48058354766e4b54d637d108f Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:26:15 -0700 Subject: [PATCH 13/95] Optimizing layouts of Min and Max. --- .../System.Reactive/Linq/Observable/Max.cs | 44 +++++++++---------- .../System.Reactive/Linq/Observable/Min.cs | 44 +++++++++---------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Max.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Max.cs index bf035fa55..fa1e5b596 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Max.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Max.cs @@ -22,28 +22,28 @@ protected override IDisposable Run(IObserver observer, IDisposable canc // LINQ to Objects makes this distinction in order to make [Max|Max] of an empty collection of reference type objects equal to null. if (default(TSource) == null) { - var sink = new _(this, observer, cancel); + var sink = new Null(_comparer, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } else { - var sink = new Delta(this, observer, cancel); + var sink = new NonNull(_comparer, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } } - class Delta : Sink, IObserver + private sealed class NonNull : Sink, IObserver { - private readonly Max _parent; + private readonly IComparer _comparer; private bool _hasValue; private TSource _lastValue; - public Delta(Max parent, IObserver observer, IDisposable cancel) + public NonNull(IComparer comparer, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _comparer = comparer; _hasValue = false; _lastValue = default(TSource); @@ -57,7 +57,7 @@ public void OnNext(TSource value) try { - comparison = _parent._comparer.Compare(value, _lastValue); + comparison = _comparer.Compare(value, _lastValue); } catch (Exception ex) { @@ -100,15 +100,15 @@ public void OnCompleted() } } - class _ : Sink, IObserver + private sealed class Null : Sink, IObserver { - private readonly Max _parent; + private readonly IComparer _comparer; private TSource _lastValue; - public _(Max parent, IObserver observer, IDisposable cancel) + public Null(IComparer comparer, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _comparer = comparer; _lastValue = default(TSource); } @@ -127,7 +127,7 @@ public void OnNext(TSource value) try { - comparison = _parent._comparer.Compare(value, _lastValue); + comparison = _comparer.Compare(value, _lastValue); } catch (Exception ex) { @@ -175,7 +175,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private double _lastValue; @@ -242,7 +242,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private float _lastValue; @@ -309,7 +309,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private decimal _lastValue; @@ -376,7 +376,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private int _lastValue; @@ -443,7 +443,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private long _lastValue; @@ -510,7 +510,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double? _lastValue; @@ -569,7 +569,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private float? _lastValue; @@ -628,7 +628,7 @@ protected override IDisposable Run(IObserver observer, IDisposable can return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private decimal? _lastValue; @@ -687,7 +687,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private int? _lastValue; @@ -746,7 +746,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private long? _lastValue; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Min.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Min.cs index 265d0b244..7417b0f81 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Min.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Min.cs @@ -22,28 +22,28 @@ protected override IDisposable Run(IObserver observer, IDisposable canc // LINQ to Objects makes this distinction in order to make [Min|Max] of an empty collection of reference type objects equal to null. if (default(TSource) == null) { - var sink = new _(this, observer, cancel); + var sink = new Null(_comparer, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } else { - var sink = new Delta(this, observer, cancel); + var sink = new NonNull(_comparer, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } } - class Delta : Sink, IObserver + private sealed class NonNull : Sink, IObserver { - private readonly Min _parent; + private readonly IComparer _comparer; private bool _hasValue; private TSource _lastValue; - public Delta(Min parent, IObserver observer, IDisposable cancel) + public NonNull(IComparer comparer, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _comparer = comparer; _hasValue = false; _lastValue = default(TSource); @@ -57,7 +57,7 @@ public void OnNext(TSource value) try { - comparison = _parent._comparer.Compare(value, _lastValue); + comparison = _comparer.Compare(value, _lastValue); } catch (Exception ex) { @@ -100,15 +100,15 @@ public void OnCompleted() } } - class _ : Sink, IObserver + private sealed class Null : Sink, IObserver { - private readonly Min _parent; + private readonly IComparer _comparer; private TSource _lastValue; - public _(Min parent, IObserver observer, IDisposable cancel) + public Null(IComparer comparer, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _comparer = comparer; _lastValue = default(TSource); } @@ -127,7 +127,7 @@ public void OnNext(TSource value) try { - comparison = _parent._comparer.Compare(value, _lastValue); + comparison = _comparer.Compare(value, _lastValue); } catch (Exception ex) { @@ -175,7 +175,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private double _lastValue; @@ -242,7 +242,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private float _lastValue; @@ -309,7 +309,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private decimal _lastValue; @@ -376,7 +376,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private int _lastValue; @@ -443,7 +443,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private bool _hasValue; private long _lastValue; @@ -510,7 +510,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double? _lastValue; @@ -569,7 +569,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private float? _lastValue; @@ -628,7 +628,7 @@ protected override IDisposable Run(IObserver observer, IDisposable can return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private decimal? _lastValue; @@ -687,7 +687,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private int? _lastValue; @@ -746,7 +746,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private long? _lastValue; From 269b2b2a95022c6ab6c9d0f080fd86b06b3e7a81 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:26:48 -0700 Subject: [PATCH 14/95] Renaming observers in ForEach. --- .../Linq/Observable/ForEach.cs | 20 +++++++------------ .../Linq/QueryLanguage.Blocking.cs | 4 ++-- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ForEach.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ForEach.cs index f2933952f..18cd3b5a4 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ForEach.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ForEach.cs @@ -8,7 +8,7 @@ namespace System.Reactive.Linq.ObservableImpl { internal sealed class ForEach { - public class _ : IObserver + public sealed class Observer : IObserver { private readonly Action _onNext; private readonly Action _done; @@ -16,7 +16,7 @@ public class _ : IObserver private Exception _exception; private int _stopped; - public _(Action onNext, Action done) + public Observer(Action onNext, Action done) { _onNext = onNext; _done = done; @@ -24,10 +24,7 @@ public _(Action onNext, Action done) _stopped = 0; } - public Exception Error - { - get { return _exception; } - } + public Exception Error => _exception; public void OnNext(TSource value) { @@ -62,7 +59,7 @@ public void OnCompleted() } } - public class ForEachImpl : IObserver + public sealed class ObserverIndexed : IObserver { private readonly Action _onNext; private readonly Action _done; @@ -71,19 +68,16 @@ public class ForEachImpl : IObserver private Exception _exception; private int _stopped; - public ForEachImpl(Action onNext, Action done) + public ObserverIndexed(Action onNext, Action done) { _onNext = onNext; _done = done; - + _index = 0; _stopped = 0; } - public Exception Error - { - get { return _exception; } - } + public Exception Error => _exception; public void OnNext(TSource value) { diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Blocking.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Blocking.cs index 703b4e27b..3218e8fad 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Blocking.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Blocking.cs @@ -118,7 +118,7 @@ public virtual void ForEach(IObservable source, Action._(onNext, () => evt.Set()); + var sink = new ForEach.Observer(onNext, () => evt.Set()); using (source.SubscribeSafe(sink)) { @@ -133,7 +133,7 @@ public virtual void ForEach(IObservable source, Action.ForEachImpl(onNext, () => evt.Set()); + var sink = new ForEach.ObserverIndexed(onNext, () => evt.Set()); using (source.SubscribeSafe(sink)) { From 608addb0e79b6b68edeaaec26f410e10de642d12 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:30:11 -0700 Subject: [PATCH 15/95] Optimizing layout of Multicast. --- .../Linq/Observable/Multicast.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Multicast.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Multicast.cs index bd1d1ec6c..6cacb9afb 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Multicast.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Multicast.cs @@ -22,30 +22,27 @@ public Multicast(IObservable source, Func observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Multicast _parent; - - public _(Multicast parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - public IDisposable Run() + public IDisposable Run(Multicast parent) { var observable = default(IObservable); var connectable = default(IConnectableObservable); try { - var subject = _parent._subjectSelector(); - connectable = new ConnectableObservable(_parent._source, subject); - observable = _parent._selector(connectable); + var subject =parent._subjectSelector(); + connectable = new ConnectableObservable(parent._source, subject); + observable = parent._selector(connectable); } catch (Exception exception) { From c2da1f01cf0aedb62ffc0b3a4fa5525918ce3d63 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:34:37 -0700 Subject: [PATCH 16/95] Optimizing layout of ObserveOn. --- .../System.Reactive/Linq/Observable/ObserveOn.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs index ad2f486be..f0192b04b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs @@ -29,7 +29,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { if (_context != null) { - var sink = new ObserveOnImpl(this, observer, cancel); + var sink = new Context(_context, observer, cancel); setSink(sink); return _source.Subscribe(sink); } @@ -41,19 +41,19 @@ protected override IDisposable Run(IObserver observer, IDisposable canc } } - class ObserveOnImpl : Sink, IObserver + private sealed class Context : Sink, IObserver { - private readonly ObserveOn _parent; + private readonly SynchronizationContext _context; - public ObserveOnImpl(ObserveOn parent, IObserver observer, IDisposable cancel) + public Context(SynchronizationContext context, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _context = context; } public void OnNext(TSource value) { - _parent._context.PostWithStartComplete(() => + _context.PostWithStartComplete(() => { base._observer.OnNext(value); }); @@ -61,7 +61,7 @@ public void OnNext(TSource value) public void OnError(Exception error) { - _parent._context.PostWithStartComplete(() => + _context.PostWithStartComplete(() => { base._observer.OnError(error); base.Dispose(); @@ -70,7 +70,7 @@ public void OnError(Exception error) public void OnCompleted() { - _parent._context.PostWithStartComplete(() => + _context.PostWithStartComplete(() => { base._observer.OnCompleted(); base.Dispose(); From 3fe870b2f9ecb8c812ef51fc9de934a2b9c8dd9e Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:44:07 -0700 Subject: [PATCH 17/95] Optimizing layouts of Empty, Return, and Throw. --- .../System.Reactive/Linq/Observable/Empty.cs | 15 ++++++--------- .../System.Reactive/Linq/Observable/Return.cs | 18 +++++++++--------- .../System.Reactive/Linq/Observable/Throw.cs | 18 +++++++++--------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Empty.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Empty.cs index c01838c74..d3fa37910 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Empty.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Empty.cs @@ -17,24 +17,21 @@ public Empty(IScheduler scheduler) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_scheduler); } - class _ : Sink + private sealed class _ : Sink { - private readonly Empty _parent; - - public _(Empty parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - public IDisposable Run() + public IDisposable Run(IScheduler scheduler) { - return _parent._scheduler.Schedule(Invoke); + return scheduler.Schedule(Invoke); } private void Invoke() diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Return.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Return.cs index 479631906..061b583ff 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Return.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Return.cs @@ -19,29 +19,29 @@ public Return(TResult value, IScheduler scheduler) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_value, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_scheduler); } - class _ : Sink + private sealed class _ : Sink { - private readonly Return _parent; + private readonly TResult _value; - public _(Return parent, IObserver observer, IDisposable cancel) + public _(TResult value, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _value = value; } - public IDisposable Run() + public IDisposable Run(IScheduler scheduler) { - return _parent._scheduler.Schedule(Invoke); + return scheduler.Schedule(Invoke); } private void Invoke() { - base._observer.OnNext(_parent._value); + base._observer.OnNext(_value); base._observer.OnCompleted(); base.Dispose(); } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throw.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throw.cs index dcbb791d0..f85e7f688 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throw.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throw.cs @@ -19,29 +19,29 @@ public Throw(Exception exception, IScheduler scheduler) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_exception, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_scheduler); } - class _ : Sink + private sealed class _ : Sink { - private readonly Throw _parent; + private readonly Exception _exception; - public _(Throw parent, IObserver observer, IDisposable cancel) + public _(Exception exception, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _exception = exception; } - public IDisposable Run() + public IDisposable Run(IScheduler scheduler) { - return _parent._scheduler.Schedule(Invoke); + return scheduler.Schedule(Invoke); } private void Invoke() { - base._observer.OnError(_parent._exception); + base._observer.OnError(_exception); base.Dispose(); } } From 45ed06dad980c04f591ea9239a887929e84a6509 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:51:59 -0700 Subject: [PATCH 18/95] Optimizing Zip layouts. --- .../Linq/Observable/Zip.Generated.cs | 534 ++++++++---------- .../Linq/Observable/Zip.Generated.tt | 22 +- .../System.Reactive/Linq/Observable/Zip.cs | 55 +- 3 files changed, 295 insertions(+), 316 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.Generated.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.Generated.cs index 810cd4db3..1c8cb0aef 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.Generated.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.Generated.cs @@ -10,7 +10,7 @@ namespace System.Reactive.Linq.ObservableImpl /* The following code is generated by a T4 template. */ - #region Zip auto-generated code (4/14/2017 12:34:48 PM) + #region Zip auto-generated code (4/17/2017 4:46:17 PM) internal sealed class Zip : Producer { @@ -29,26 +29,26 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(3, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; private ZipObserver _observer2; private ZipObserver _observer3; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3) { var disposables = new IDisposable[4]; @@ -67,9 +67,9 @@ public IDisposable Run() _observer3 = new ZipObserver(_gate, this, 2, d3); base.Queues[2] = _observer3.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); disposables[3] = Disposable.Create(() => { @@ -81,10 +81,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue()); } } @@ -107,19 +104,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(4, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -127,7 +124,7 @@ public _(Zip parent, IObserver observer, IDisp private ZipObserver _observer3; private ZipObserver _observer4; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4) { var disposables = new IDisposable[5]; @@ -151,10 +148,10 @@ public IDisposable Run() _observer4 = new ZipObserver(_gate, this, 3, d4); base.Queues[3] = _observer4.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); disposables[4] = Disposable.Create(() => { @@ -167,10 +164,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue()); } } @@ -195,19 +189,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(5, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -216,7 +210,7 @@ public _(Zip parent, IObserver observer, I private ZipObserver _observer4; private ZipObserver _observer5; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5) { var disposables = new IDisposable[6]; @@ -245,11 +239,11 @@ public IDisposable Run() _observer5 = new ZipObserver(_gate, this, 4, d5); base.Queues[4] = _observer5.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); disposables[5] = Disposable.Create(() => { @@ -263,10 +257,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue()); } } @@ -293,19 +284,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(6, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -315,7 +306,7 @@ public _(Zip parent, IObserver observe private ZipObserver _observer5; private ZipObserver _observer6; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6) { var disposables = new IDisposable[7]; @@ -349,12 +340,12 @@ public IDisposable Run() _observer6 = new ZipObserver(_gate, this, 5, d6); base.Queues[5] = _observer6.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); disposables[6] = Disposable.Create(() => { @@ -369,10 +360,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue()); } } @@ -401,19 +389,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(7, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -424,7 +412,7 @@ public _(Zip parent, IObserver obs private ZipObserver _observer6; private ZipObserver _observer7; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7) { var disposables = new IDisposable[8]; @@ -463,13 +451,13 @@ public IDisposable Run() _observer7 = new ZipObserver(_gate, this, 6, d7); base.Queues[6] = _observer7.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); disposables[7] = Disposable.Create(() => { @@ -485,10 +473,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue()); } } @@ -519,19 +504,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(8, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -543,7 +528,7 @@ public _(Zip parent, IObserver private ZipObserver _observer7; private ZipObserver _observer8; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8) { var disposables = new IDisposable[9]; @@ -587,14 +572,14 @@ public IDisposable Run() _observer8 = new ZipObserver(_gate, this, 7, d8); base.Queues[7] = _observer8.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); - d8.Disposable = _parent._source8.SubscribeSafe(_observer8); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); + d8.Disposable = source8.SubscribeSafe(_observer8); disposables[8] = Disposable.Create(() => { @@ -611,10 +596,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue()); } } @@ -647,19 +629,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(9, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -672,7 +654,7 @@ public _(Zip parent, IObserver _observer8; private ZipObserver _observer9; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9) { var disposables = new IDisposable[10]; @@ -721,15 +703,15 @@ public IDisposable Run() _observer9 = new ZipObserver(_gate, this, 8, d9); base.Queues[8] = _observer9.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); - d8.Disposable = _parent._source8.SubscribeSafe(_observer8); - d9.Disposable = _parent._source9.SubscribeSafe(_observer9); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); + d8.Disposable = source8.SubscribeSafe(_observer8); + d9.Disposable = source9.SubscribeSafe(_observer9); disposables[9] = Disposable.Create(() => { @@ -747,10 +729,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue()); } } @@ -785,19 +764,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(10, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -811,7 +790,7 @@ public _(Zip parent, IObserver private ZipObserver _observer9; private ZipObserver _observer10; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10) { var disposables = new IDisposable[11]; @@ -865,16 +844,16 @@ public IDisposable Run() _observer10 = new ZipObserver(_gate, this, 9, d10); base.Queues[9] = _observer10.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); - d8.Disposable = _parent._source8.SubscribeSafe(_observer8); - d9.Disposable = _parent._source9.SubscribeSafe(_observer9); - d10.Disposable = _parent._source10.SubscribeSafe(_observer10); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); + d8.Disposable = source8.SubscribeSafe(_observer8); + d9.Disposable = source9.SubscribeSafe(_observer9); + d10.Disposable = source10.SubscribeSafe(_observer10); disposables[10] = Disposable.Create(() => { @@ -893,10 +872,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue()); } } @@ -933,19 +909,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(11, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -960,7 +936,7 @@ public _(Zip parent, IObs private ZipObserver _observer10; private ZipObserver _observer11; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11) { var disposables = new IDisposable[12]; @@ -1019,17 +995,17 @@ public IDisposable Run() _observer11 = new ZipObserver(_gate, this, 10, d11); base.Queues[10] = _observer11.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); - d8.Disposable = _parent._source8.SubscribeSafe(_observer8); - d9.Disposable = _parent._source9.SubscribeSafe(_observer9); - d10.Disposable = _parent._source10.SubscribeSafe(_observer10); - d11.Disposable = _parent._source11.SubscribeSafe(_observer11); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); + d8.Disposable = source8.SubscribeSafe(_observer8); + d9.Disposable = source9.SubscribeSafe(_observer9); + d10.Disposable = source10.SubscribeSafe(_observer10); + d11.Disposable = source11.SubscribeSafe(_observer11); disposables[11] = Disposable.Create(() => { @@ -1049,10 +1025,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue()); } } @@ -1091,19 +1064,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(12, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -1119,7 +1092,7 @@ public _(Zip parent, private ZipObserver _observer11; private ZipObserver _observer12; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12) { var disposables = new IDisposable[13]; @@ -1183,18 +1156,18 @@ public IDisposable Run() _observer12 = new ZipObserver(_gate, this, 11, d12); base.Queues[11] = _observer12.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); - d8.Disposable = _parent._source8.SubscribeSafe(_observer8); - d9.Disposable = _parent._source9.SubscribeSafe(_observer9); - d10.Disposable = _parent._source10.SubscribeSafe(_observer10); - d11.Disposable = _parent._source11.SubscribeSafe(_observer11); - d12.Disposable = _parent._source12.SubscribeSafe(_observer12); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); + d8.Disposable = source8.SubscribeSafe(_observer8); + d9.Disposable = source9.SubscribeSafe(_observer9); + d10.Disposable = source10.SubscribeSafe(_observer10); + d11.Disposable = source11.SubscribeSafe(_observer11); + d12.Disposable = source12.SubscribeSafe(_observer12); disposables[12] = Disposable.Create(() => { @@ -1215,10 +1188,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue()); } } @@ -1259,19 +1229,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12, _source13); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(13, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -1288,7 +1258,7 @@ public _(Zip pa private ZipObserver _observer12; private ZipObserver _observer13; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12, IObservable source13) { var disposables = new IDisposable[14]; @@ -1357,19 +1327,19 @@ public IDisposable Run() _observer13 = new ZipObserver(_gate, this, 12, d13); base.Queues[12] = _observer13.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); - d8.Disposable = _parent._source8.SubscribeSafe(_observer8); - d9.Disposable = _parent._source9.SubscribeSafe(_observer9); - d10.Disposable = _parent._source10.SubscribeSafe(_observer10); - d11.Disposable = _parent._source11.SubscribeSafe(_observer11); - d12.Disposable = _parent._source12.SubscribeSafe(_observer12); - d13.Disposable = _parent._source13.SubscribeSafe(_observer13); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); + d8.Disposable = source8.SubscribeSafe(_observer8); + d9.Disposable = source9.SubscribeSafe(_observer9); + d10.Disposable = source10.SubscribeSafe(_observer10); + d11.Disposable = source11.SubscribeSafe(_observer11); + d12.Disposable = source12.SubscribeSafe(_observer12); + d13.Disposable = source13.SubscribeSafe(_observer13); disposables[13] = Disposable.Create(() => { @@ -1391,10 +1361,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue(), _observer13.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue(), _observer13.Values.Dequeue()); } } @@ -1437,19 +1404,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12, _source13, _source14); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(14, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -1467,7 +1434,7 @@ public _(Zip _observer13; private ZipObserver _observer14; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12, IObservable source13, IObservable source14) { var disposables = new IDisposable[15]; @@ -1541,20 +1508,20 @@ public IDisposable Run() _observer14 = new ZipObserver(_gate, this, 13, d14); base.Queues[13] = _observer14.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); - d8.Disposable = _parent._source8.SubscribeSafe(_observer8); - d9.Disposable = _parent._source9.SubscribeSafe(_observer9); - d10.Disposable = _parent._source10.SubscribeSafe(_observer10); - d11.Disposable = _parent._source11.SubscribeSafe(_observer11); - d12.Disposable = _parent._source12.SubscribeSafe(_observer12); - d13.Disposable = _parent._source13.SubscribeSafe(_observer13); - d14.Disposable = _parent._source14.SubscribeSafe(_observer14); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); + d8.Disposable = source8.SubscribeSafe(_observer8); + d9.Disposable = source9.SubscribeSafe(_observer9); + d10.Disposable = source10.SubscribeSafe(_observer10); + d11.Disposable = source11.SubscribeSafe(_observer11); + d12.Disposable = source12.SubscribeSafe(_observer12); + d13.Disposable = source13.SubscribeSafe(_observer13); + d14.Disposable = source14.SubscribeSafe(_observer14); disposables[14] = Disposable.Create(() => { @@ -1577,10 +1544,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue(), _observer13.Values.Dequeue(), _observer14.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue(), _observer13.Values.Dequeue(), _observer14.Values.Dequeue()); } } @@ -1625,19 +1589,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12, _source13, _source14, _source15); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(15, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -1656,7 +1620,7 @@ public _(Zip _observer14; private ZipObserver _observer15; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12, IObservable source13, IObservable source14, IObservable source15) { var disposables = new IDisposable[16]; @@ -1735,21 +1699,21 @@ public IDisposable Run() _observer15 = new ZipObserver(_gate, this, 14, d15); base.Queues[14] = _observer15.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); - d8.Disposable = _parent._source8.SubscribeSafe(_observer8); - d9.Disposable = _parent._source9.SubscribeSafe(_observer9); - d10.Disposable = _parent._source10.SubscribeSafe(_observer10); - d11.Disposable = _parent._source11.SubscribeSafe(_observer11); - d12.Disposable = _parent._source12.SubscribeSafe(_observer12); - d13.Disposable = _parent._source13.SubscribeSafe(_observer13); - d14.Disposable = _parent._source14.SubscribeSafe(_observer14); - d15.Disposable = _parent._source15.SubscribeSafe(_observer15); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); + d8.Disposable = source8.SubscribeSafe(_observer8); + d9.Disposable = source9.SubscribeSafe(_observer9); + d10.Disposable = source10.SubscribeSafe(_observer10); + d11.Disposable = source11.SubscribeSafe(_observer11); + d12.Disposable = source12.SubscribeSafe(_observer12); + d13.Disposable = source13.SubscribeSafe(_observer13); + d14.Disposable = source14.SubscribeSafe(_observer14); + d15.Disposable = source15.SubscribeSafe(_observer15); disposables[15] = Disposable.Create(() => { @@ -1773,10 +1737,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue(), _observer13.Values.Dequeue(), _observer14.Values.Dequeue(), _observer15.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue(), _observer13.Values.Dequeue(), _observer14.Values.Dequeue(), _observer15.Values.Dequeue()); } } @@ -1823,19 +1784,19 @@ public Zip(IObservable source1, IObservable source2, IObservable sou protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source1, _source2, _source3, _source4, _source5, _source6, _source7, _source8, _source9, _source10, _source11, _source12, _source13, _source14, _source15, _source16); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip _parent; + private readonly Func _resultSelector; - public _(Zip parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(16, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private ZipObserver _observer1; @@ -1855,7 +1816,7 @@ public _(Zip _observer15; private ZipObserver _observer16; - public IDisposable Run() + public IDisposable Run(IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, IObservable source8, IObservable source9, IObservable source10, IObservable source11, IObservable source12, IObservable source13, IObservable source14, IObservable source15, IObservable source16) { var disposables = new IDisposable[17]; @@ -1939,22 +1900,22 @@ public IDisposable Run() _observer16 = new ZipObserver(_gate, this, 15, d16); base.Queues[15] = _observer16.Values; - d1.Disposable = _parent._source1.SubscribeSafe(_observer1); - d2.Disposable = _parent._source2.SubscribeSafe(_observer2); - d3.Disposable = _parent._source3.SubscribeSafe(_observer3); - d4.Disposable = _parent._source4.SubscribeSafe(_observer4); - d5.Disposable = _parent._source5.SubscribeSafe(_observer5); - d6.Disposable = _parent._source6.SubscribeSafe(_observer6); - d7.Disposable = _parent._source7.SubscribeSafe(_observer7); - d8.Disposable = _parent._source8.SubscribeSafe(_observer8); - d9.Disposable = _parent._source9.SubscribeSafe(_observer9); - d10.Disposable = _parent._source10.SubscribeSafe(_observer10); - d11.Disposable = _parent._source11.SubscribeSafe(_observer11); - d12.Disposable = _parent._source12.SubscribeSafe(_observer12); - d13.Disposable = _parent._source13.SubscribeSafe(_observer13); - d14.Disposable = _parent._source14.SubscribeSafe(_observer14); - d15.Disposable = _parent._source15.SubscribeSafe(_observer15); - d16.Disposable = _parent._source16.SubscribeSafe(_observer16); + d1.Disposable = source1.SubscribeSafe(_observer1); + d2.Disposable = source2.SubscribeSafe(_observer2); + d3.Disposable = source3.SubscribeSafe(_observer3); + d4.Disposable = source4.SubscribeSafe(_observer4); + d5.Disposable = source5.SubscribeSafe(_observer5); + d6.Disposable = source6.SubscribeSafe(_observer6); + d7.Disposable = source7.SubscribeSafe(_observer7); + d8.Disposable = source8.SubscribeSafe(_observer8); + d9.Disposable = source9.SubscribeSafe(_observer9); + d10.Disposable = source10.SubscribeSafe(_observer10); + d11.Disposable = source11.SubscribeSafe(_observer11); + d12.Disposable = source12.SubscribeSafe(_observer12); + d13.Disposable = source13.SubscribeSafe(_observer13); + d14.Disposable = source14.SubscribeSafe(_observer14); + d15.Disposable = source15.SubscribeSafe(_observer15); + d16.Disposable = source16.SubscribeSafe(_observer16); disposables[16] = Disposable.Create(() => { @@ -1979,10 +1940,7 @@ public IDisposable Run() return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue(), _observer13.Values.Dequeue(), _observer14.Values.Dequeue(), _observer15.Values.Dequeue(), _observer16.Values.Dequeue()); - } + protected override TResult GetResult() => _resultSelector(_observer1.Values.Dequeue(), _observer2.Values.Dequeue(), _observer3.Values.Dequeue(), _observer4.Values.Dequeue(), _observer5.Values.Dequeue(), _observer6.Values.Dequeue(), _observer7.Values.Dequeue(), _observer8.Values.Dequeue(), _observer9.Values.Dequeue(), _observer10.Values.Dequeue(), _observer11.Values.Dequeue(), _observer12.Values.Dequeue(), _observer13.Values.Dequeue(), _observer14.Values.Dequeue(), _observer15.Values.Dequeue(), _observer16.Values.Dequeue()); } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.Generated.tt b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.Generated.tt index c8dea7ac1..20b396325 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.Generated.tt +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.Generated.tt @@ -24,6 +24,7 @@ for (var i = 3; i <= 16; i++) var ts = string.Join(", ", Enumerable.Range(1, i).Select(j => "T" + j)); var os = string.Join(", ", Enumerable.Range(1, i).Select(j => "IObservable source" + j)); var vs = string.Join(", ", Enumerable.Range(1, i).Select(j => "_observer" + j + ".Values.Dequeue()")); + var ss = string.Join(", ", Enumerable.Range(1, i).Select(j => "_source" + j)); #> internal sealed class Zip<<#=ts#>, TResult> : Producer { @@ -52,19 +53,19 @@ for (var j = 1; j <= i; j++) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(<#=ss#>); } - class _ : ZipSink + private sealed class _ : ZipSink { - private readonly Zip<<#=ts#>, TResult> _parent; + private readonly Func<<#=ts#>, TResult> _resultSelector; - public _(Zip<<#=ts#>, TResult> parent, IObserver observer, IDisposable cancel) + public _(Func<<#=ts#>, TResult> resultSelector, IObserver observer, IDisposable cancel) : base(<#=i#>, observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } <# @@ -76,7 +77,7 @@ for (var j = 1; j <= i; j++) } #> - public IDisposable Run() + public IDisposable Run(<#=os#>) { var disposables = new IDisposable[<#=i + 1#>]; @@ -95,7 +96,7 @@ for (var j = 1; j <= i; j++) for (var j = 1; j <= i; j++) { #> - d<#=j#>.Disposable = _parent._source<#=j#>.SubscribeSafe(_observer<#=j#>); + d<#=j#>.Disposable = source<#=j#>.SubscribeSafe(_observer<#=j#>); <# } #> @@ -115,10 +116,7 @@ for (var j = 1; j <= i; j++) return StableCompositeDisposable.Create(disposables); } - protected override TResult GetResult() - { - return _parent._resultSelector(<#=vs#>); - } + protected override TResult GetResult() => _resultSelector(<#=vs#>); } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs index 6996d35f2..918343475 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs @@ -364,14 +364,14 @@ public void OnCompleted() #region Helpers for n-ary overloads - interface IZip + internal interface IZip { void Next(int index); void Fail(Exception error); void Done(int index); } - abstract class ZipSink : Sink, IZip + internal abstract class ZipSink : Sink, IZip { protected readonly object _gate; @@ -387,10 +387,7 @@ public ZipSink(int arity, IObserver observer, IDisposable cancel) _queues = new ICollection[arity]; } - public ICollection[] Queues - { - get { return _queues; } - } + public ICollection[] Queues => _queues; public void Next(int index) { @@ -488,10 +485,7 @@ public ZipObserver(object gate, IZip parent, int index, IDisposable self) _values = new Queue(); } - public Queue Values - { - get { return _values; } - } + public Queue Values => _values; public void OnNext(T value) { @@ -545,7 +539,7 @@ protected override IDisposable Run(IObserver> observer, IDisposab return sink.Run(); } - class _ : Sink> + private sealed class _ : Sink> { private readonly Zip _parent; @@ -583,7 +577,7 @@ public IDisposable Run() var d = new SingleAssignmentDisposable(); _subscriptions[j] = d; - var o = new O(this, j); + var o = new SourceObserver(this, j); d.Disposable = srcs[j].SubscribeSafe(o); } @@ -601,7 +595,7 @@ private void OnNext(int index, TSource value) var res = _queues.Select(q => q.Dequeue()).ToList(); base._observer.OnNext(res); } - else if (_isDone.Where((x, i) => i != index).All(Stubs.I)) + else if (AllExcept(_isDone, index)) { base._observer.OnCompleted(); base.Dispose(); @@ -625,7 +619,7 @@ private void OnCompleted(int index) { _isDone[index] = true; - if (_isDone.All(Stubs.I)) + if (All(_isDone)) { base._observer.OnCompleted(); base.Dispose(); @@ -638,12 +632,41 @@ private void OnCompleted(int index) } } - class O : IObserver + private static bool All(bool[] values) + { + foreach (var value in values) + { + if (!value) + { + return false; + } + } + + return true; + } + + private static bool AllExcept(bool[] values, int index) + { + for (var i = 0; i < values.Length; i++) + { + if (i != index) + { + if (!values[i]) + { + return false; + } + } + } + + return true; + } + + private sealed class SourceObserver : IObserver { private readonly _ _parent; private readonly int _index; - public O(_ parent, int index) + public SourceObserver(_ parent, int index) { _parent = parent; _index = index; From 2559fd5b80e4fbf06a8da944b2b1fca7df7f9a8a Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:53:58 -0700 Subject: [PATCH 19/95] Refactoring some helper methods. --- .../src/System.Reactive/Internal/Helpers.cs | 29 ++++++++++++++++ .../Linq/Observable/CombineLatest.cs | 6 ++-- .../System.Reactive/Linq/Observable/Zip.cs | 33 ++----------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Internal/Helpers.cs b/Rx.NET/Source/src/System.Reactive/Internal/Helpers.cs index 99ba1ed5b..06bd0d41e 100644 --- a/Rx.NET/Source/src/System.Reactive/Internal/Helpers.cs +++ b/Rx.NET/Source/src/System.Reactive/Internal/Helpers.cs @@ -39,5 +39,34 @@ public static IObservable Unpack(IObservable source) return source; } + + public static bool All(this bool[] values) + { + foreach (var value in values) + { + if (!value) + { + return false; + } + } + + return true; + } + + public static bool AllExcept(this bool[] values, int index) + { + for (var i = 0; i < values.Length; i++) + { + if (i != index) + { + if (!values[i]) + { + return false; + } + } + } + + return true; + } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs index 2fbf638bc..50b08761d 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/CombineLatest.cs @@ -468,7 +468,7 @@ private void OnNext(int index, TSource value) _hasValue[index] = true; - if (_hasValueAll || (_hasValueAll = All(_hasValue))) + if (_hasValueAll || (_hasValueAll = _hasValue.All())) { var res = default(TResult); try @@ -484,7 +484,7 @@ private void OnNext(int index, TSource value) _observer.OnNext(res); } - else if (AllExcept(_isDone, index)) + else if (_isDone.AllExcept(index)) { base._observer.OnCompleted(); base.Dispose(); @@ -508,7 +508,7 @@ private void OnCompleted(int index) { _isDone[index] = true; - if (All(_isDone)) + if (_isDone.All()) { base._observer.OnCompleted(); base.Dispose(); diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs index 918343475..477a112ec 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs @@ -595,7 +595,7 @@ private void OnNext(int index, TSource value) var res = _queues.Select(q => q.Dequeue()).ToList(); base._observer.OnNext(res); } - else if (AllExcept(_isDone, index)) + else if (_isDone.AllExcept(index)) { base._observer.OnCompleted(); base.Dispose(); @@ -619,7 +619,7 @@ private void OnCompleted(int index) { _isDone[index] = true; - if (All(_isDone)) + if (_isDone.All()) { base._observer.OnCompleted(); base.Dispose(); @@ -632,35 +632,6 @@ private void OnCompleted(int index) } } - private static bool All(bool[] values) - { - foreach (var value in values) - { - if (!value) - { - return false; - } - } - - return true; - } - - private static bool AllExcept(bool[] values, int index) - { - for (var i = 0; i < values.Length; i++) - { - if (i != index) - { - if (!values[i]) - { - return false; - } - } - } - - return true; - } - private sealed class SourceObserver : IObserver { private readonly _ _parent; From 053ad767f382bff34ccaada3a13ac606a5de58a5 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 16:55:50 -0700 Subject: [PATCH 20/95] Optimizing list creation in Zip. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs index 477a112ec..859a282bb 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs @@ -592,7 +592,14 @@ private void OnNext(int index, TSource value) if (_queues.All(q => q.Count > 0)) { - var res = _queues.Select(q => q.Dequeue()).ToList(); + var n = _queues.Length; + + var res = new List(n); + for (var i = 0; i < n; i++) + { + res.Add(_queues[i].Dequeue()); + } + base._observer.OnNext(res); } else if (_isDone.AllExcept(index)) From a4ed2682cee33c6a5dd95267418fd1ef163de1c2 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:06:09 -0700 Subject: [PATCH 21/95] Removing unused fields. --- .../System.Reactive/Linq/Observable/LastOrDefaultAsync.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastOrDefaultAsync.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastOrDefaultAsync.cs index bdbb095ea..d4f99a02d 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastOrDefaultAsync.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/LastOrDefaultAsync.cs @@ -25,19 +25,16 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { private TSource _value; - private bool _seenValue; public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { _value = default(TSource); - _seenValue = false; } public void OnNext(TSource value) { _value = value; - _seenValue = true; } public void OnError(Exception error) @@ -77,7 +74,6 @@ private sealed class _ : Sink, IObserver { private readonly Func _predicate; private TSource _value; - private bool _seenValue; public _(Func predicate, IObserver observer, IDisposable cancel) : base(observer, cancel) @@ -85,7 +81,6 @@ public _(Func predicate, IObserver observer, IDisposable _predicate = predicate; _value = default(TSource); - _seenValue = false; } public void OnNext(TSource value) @@ -106,7 +101,6 @@ public void OnNext(TSource value) if (b) { _value = value; - _seenValue = true; } } From 381904c9d2982d95a240c641dc17cfcccb7c340f Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:11:30 -0700 Subject: [PATCH 22/95] Further optimizations to Zip. --- .../System.Reactive/Linq/Observable/Zip.cs | 471 +++++++++--------- .../Linq/QueryLanguage.Multiple.cs | 4 +- 2 files changed, 241 insertions(+), 234 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs index 859a282bb..b2452426b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Zip.cs @@ -11,310 +11,302 @@ namespace System.Reactive.Linq.ObservableImpl { #region Binary - internal sealed class Zip : Producer + internal static class Zip { - private readonly IObservable _first; - private readonly IObservable _second; - private readonly IEnumerable _secondE; - private readonly Func _resultSelector; - - public Zip(IObservable first, IObservable second, Func resultSelector) - { - _first = first; - _second = second; - _resultSelector = resultSelector; - } - - public Zip(IObservable first, IEnumerable second, Func resultSelector) + internal sealed class Observable : Producer { - _first = first; - _secondE = second; - _resultSelector = resultSelector; - } + private readonly IObservable _first; + private readonly IObservable _second; + private readonly Func _resultSelector; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_second != null) + public Observable(IObservable first, IObservable second, Func resultSelector) { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); + _first = first; + _second = second; + _resultSelector = resultSelector; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new ZipImpl(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_first, _second); } - } - - class _ : Sink - { - private readonly Zip _parent; - public _(Zip parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink { - _parent = parent; - } + private readonly Func _resultSelector; - private object _gate; + public _(Func resultSelector, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _resultSelector = resultSelector; + } - public IDisposable Run() - { - _gate = new object(); + private object _gate; - var fstSubscription = new SingleAssignmentDisposable(); - var sndSubscription = new SingleAssignmentDisposable(); + public IDisposable Run(IObservable first, IObservable second) + { + _gate = new object(); - var fstO = new F(this, fstSubscription); - var sndO = new S(this, sndSubscription); + var fstSubscription = new SingleAssignmentDisposable(); + var sndSubscription = new SingleAssignmentDisposable(); - fstO.Other = sndO; - sndO.Other = fstO; + var fstO = new FirstObserver(this, fstSubscription); + var sndO = new SecondObserver(this, sndSubscription); - fstSubscription.Disposable = _parent._first.SubscribeSafe(fstO); - sndSubscription.Disposable = _parent._second.SubscribeSafe(sndO); + fstO.Other = sndO; + sndO.Other = fstO; - return StableCompositeDisposable.Create(fstSubscription, sndSubscription, fstO, sndO); - } + fstSubscription.Disposable = first.SubscribeSafe(fstO); + sndSubscription.Disposable = second.SubscribeSafe(sndO); - class F : IObserver, IDisposable - { - private readonly _ _parent; - private readonly IDisposable _self; - private S _other; - private Queue _queue; + return StableCompositeDisposable.Create(fstSubscription, sndSubscription, fstO, sndO); + } - public F(_ parent, IDisposable self) + private sealed class FirstObserver : IObserver, IDisposable { - _parent = parent; - _self = self; - _queue = new Queue(); - } + private readonly _ _parent; + private readonly IDisposable _self; + private SecondObserver _other; + private Queue _queue; - public S Other { set { _other = value; } } + public FirstObserver(_ parent, IDisposable self) + { + _parent = parent; + _self = self; + _queue = new Queue(); + } - public Queue Queue { get { return _queue; } } - public bool Done { get; private set; } + public SecondObserver Other { set { _other = value; } } - public void OnNext(TFirst value) - { - lock (_parent._gate) + public Queue Queue => _queue; + public bool Done { get; private set; } + + public void OnNext(TFirst value) { - if (_other.Queue.Count > 0) + lock (_parent._gate) { - var r = _other.Queue.Dequeue(); - - var res = default(TResult); - try + if (_other.Queue.Count > 0) { - res = _parent._parent._resultSelector(value, r); + var r = _other.Queue.Dequeue(); + + var res = default(TResult); + try + { + res = _parent._resultSelector(value, r); + } + catch (Exception ex) + { + _parent._observer.OnError(ex); + _parent.Dispose(); + return; + } + + _parent._observer.OnNext(res); } - catch (Exception ex) + else { - _parent._observer.OnError(ex); - _parent.Dispose(); - return; + if (_other.Done) + { + _parent._observer.OnCompleted(); + _parent.Dispose(); + return; + } + + _queue.Enqueue(value); } + } + } - _parent._observer.OnNext(res); + public void OnError(Exception error) + { + lock (_parent._gate) + { + _parent._observer.OnError(error); + _parent.Dispose(); } - else + } + + public void OnCompleted() + { + lock (_parent._gate) { + Done = true; + if (_other.Done) { _parent._observer.OnCompleted(); _parent.Dispose(); return; } - - _queue.Enqueue(value); + else + { + _self.Dispose(); + } } } - } - public void OnError(Exception error) - { - lock (_parent._gate) + public void Dispose() { - _parent._observer.OnError(error); - _parent.Dispose(); + _queue.Clear(); } } - public void OnCompleted() + private sealed class SecondObserver : IObserver, IDisposable { - lock (_parent._gate) - { - Done = true; + private readonly _ _parent; + private readonly IDisposable _self; + private FirstObserver _other; + private Queue _queue; - if (_other.Done) - { - _parent._observer.OnCompleted(); - _parent.Dispose(); - return; - } - else - { - _self.Dispose(); - } + public SecondObserver(_ parent, IDisposable self) + { + _parent = parent; + _self = self; + _queue = new Queue(); } - } - public void Dispose() - { - _queue.Clear(); - } - } + public FirstObserver Other { set { _other = value; } } - class S : IObserver, IDisposable - { - private readonly _ _parent; - private readonly IDisposable _self; - private F _other; - private Queue _queue; - - public S(_ parent, IDisposable self) - { - _parent = parent; - _self = self; - _queue = new Queue(); - } - - public F Other { set { _other = value; } } + public Queue Queue => _queue; + public bool Done { get; private set; } - public Queue Queue { get { return _queue; } } - public bool Done { get; private set; } - - public void OnNext(TSecond value) - { - lock (_parent._gate) + public void OnNext(TSecond value) { - if (_other.Queue.Count > 0) + lock (_parent._gate) { - var l = _other.Queue.Dequeue(); - - var res = default(TResult); - try + if (_other.Queue.Count > 0) { - res = _parent._parent._resultSelector(l, value); + var l = _other.Queue.Dequeue(); + + var res = default(TResult); + try + { + res = _parent._resultSelector(l, value); + } + catch (Exception ex) + { + _parent._observer.OnError(ex); + _parent.Dispose(); + return; + } + + _parent._observer.OnNext(res); } - catch (Exception ex) + else { - _parent._observer.OnError(ex); - _parent.Dispose(); - return; + if (_other.Done) + { + _parent._observer.OnCompleted(); + _parent.Dispose(); + return; + } + + _queue.Enqueue(value); } + } + } - _parent._observer.OnNext(res); + public void OnError(Exception error) + { + lock (_parent._gate) + { + _parent._observer.OnError(error); + _parent.Dispose(); } - else + } + + public void OnCompleted() + { + lock (_parent._gate) { + Done = true; + if (_other.Done) { _parent._observer.OnCompleted(); _parent.Dispose(); return; } - - _queue.Enqueue(value); + else + { + _self.Dispose(); + } } } - } - public void OnError(Exception error) - { - lock (_parent._gate) - { - _parent._observer.OnError(error); - _parent.Dispose(); - } - } - - public void OnCompleted() - { - lock (_parent._gate) + public void Dispose() { - Done = true; - - if (_other.Done) - { - _parent._observer.OnCompleted(); - _parent.Dispose(); - return; - } - else - { - _self.Dispose(); - } + _queue.Clear(); } } - - public void Dispose() - { - _queue.Clear(); - } } } - class ZipImpl : Sink, IObserver + internal sealed class Enumerable : Producer { - private readonly Zip _parent; + private readonly IObservable _first; + private readonly IEnumerable _second; + private readonly Func _resultSelector; - public ZipImpl(Zip parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Enumerable(IObservable first, IEnumerable second, Func resultSelector) { - _parent = parent; + _first = first; + _second = second; + _resultSelector = resultSelector; } - private IEnumerator _rightEnumerator; - - public IDisposable Run() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - // - // Notice the evaluation order of obtaining the enumerator and subscribing to the - // observable sequence is reversed compared to the operator's signature. This is - // required to make sure the enumerator is available as soon as the observer can - // be called. Otherwise, we end up having a race for the initialization and use - // of the _rightEnumerator field. - // - try - { - _rightEnumerator = _parent._secondE.GetEnumerator(); - } - catch (Exception exception) - { - base._observer.OnError(exception); - base.Dispose(); - return Disposable.Empty; - } - - var leftSubscription = _parent._first.SubscribeSafe(this); - - return StableCompositeDisposable.Create(leftSubscription, _rightEnumerator); + var sink = new _(_resultSelector, observer, cancel); + setSink(sink); + return sink.Run(_first, _second); } - public void OnNext(TFirst value) + private sealed class _ : Sink, IObserver { - var hasNext = false; - try + private readonly Func _resultSelector; + + public _(Func resultSelector, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - hasNext = _rightEnumerator.MoveNext(); + _resultSelector = resultSelector; } - catch (Exception ex) + + private IEnumerator _rightEnumerator; + + public IDisposable Run(IObservable first, IEnumerable second) { - base._observer.OnError(ex); - base.Dispose(); - return; + // + // Notice the evaluation order of obtaining the enumerator and subscribing to the + // observable sequence is reversed compared to the operator's signature. This is + // required to make sure the enumerator is available as soon as the observer can + // be called. Otherwise, we end up having a race for the initialization and use + // of the _rightEnumerator field. + // + try + { + _rightEnumerator = second.GetEnumerator(); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return Disposable.Empty; + } + + var leftSubscription = first.SubscribeSafe(this); + + return StableCompositeDisposable.Create(leftSubscription, _rightEnumerator); } - if (hasNext) + public void OnNext(TFirst value) { - var right = default(TSecond); + var hasNext = false; try { - right = _rightEnumerator.Current; + hasNext = _rightEnumerator.MoveNext(); } catch (Exception ex) { @@ -323,38 +315,53 @@ public void OnNext(TFirst value) return; } - TResult result; - try + if (hasNext) { - result = _parent._resultSelector(value, right); + var right = default(TSecond); + try + { + right = _rightEnumerator.Current; + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + TResult result; + try + { + result = _resultSelector(value, right); + } + catch (Exception ex) + { + base._observer.OnError(ex); + base.Dispose(); + return; + } + + base._observer.OnNext(result); } - catch (Exception ex) + else { - base._observer.OnError(ex); + base._observer.OnCompleted(); base.Dispose(); - return; } + } - base._observer.OnNext(result); + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); } - else + + public void OnCompleted() { base._observer.OnCompleted(); base.Dispose(); } } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); - } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs index 7b2f7ba7e..532329476 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs @@ -401,7 +401,7 @@ public virtual IObservable WithLatestFrom(IOb public virtual IObservable Zip(IObservable first, IObservable second, Func resultSelector) { - return new Zip(first, second, resultSelector); + return new Zip.Observable(first, second, resultSelector); } public virtual IObservable Zip(IEnumerable> sources, Func, TResult> resultSelector) @@ -502,7 +502,7 @@ public virtual IObservable Zip Zip(IObservable first, IEnumerable second, Func resultSelector) { - return new Zip(first, second, resultSelector); + return new Zip.Enumerable(first, second, resultSelector); } #endregion From 21b8d55db46ac52ce4f1f6cc768fb161423dd9ff Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:25:49 -0700 Subject: [PATCH 23/95] Optimizing layouts of Skip and Take. --- .../System.Reactive/Linq/Observable/Skip.cs | 220 ++++++++-------- .../System.Reactive/Linq/Observable/Take.cs | 240 +++++++++--------- ...QueryLanguage.StandardSequenceOperators.cs | 12 +- .../Linq/QueryLanguage.Time.cs | 8 +- 4 files changed, 242 insertions(+), 238 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Skip.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Skip.cs index 8d47d300f..7d051d47f 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Skip.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Skip.cs @@ -7,143 +7,145 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Skip : Producer + internal static class Skip { - private readonly IObservable _source; - private readonly int _count; - private readonly TimeSpan _duration; - internal readonly IScheduler _scheduler; - - public Skip(IObservable source, int count) - { - _source = source; - _count = count; - } - - public Skip(IObservable source, TimeSpan duration, IScheduler scheduler) - { - _source = source; - _duration = duration; - _scheduler = scheduler; - } - - public IObservable Combine(int count) - { - // - // Sum semantics: - // - // xs --o--o--o--o--o--o--| xs --o--o--o--o--o--o--| - // xs.Skip(2) --x--x--o--o--o--o--| xs.Skip(3) --x--x--x--o--o--o--| - // xs.Skip(2).Skip(3) --------x--x--x--o--| xs.Skip(3).Skip(2) -----------x--x--o--| - // - return new Skip(_source, _count + count); - } - - public IObservable Combine(TimeSpan duration) - { - // - // Maximum semantics: - // - // t 0--1--2--3--4--5--6--7-> t 0--1--2--3--4--5--6--7-> - // - // xs --o--o--o--o--o--o--| xs --o--o--o--o--o--o--| - // xs.Skip(2s) xxxxxxx-o--o--o--o--| xs.Skip(3s) xxxxxxxxxx-o--o--o--| - // xs.Skip(2s).Skip(3s) xxxxxxxxxx-o--o--o--| xs.Skip(3s).Skip(2s) xxxxxxx----o--o--o--| - // - if (duration <= _duration) - return this; - else - return new Skip(_source, duration, _scheduler); - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_scheduler == null) - { - var sink = new _(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); - } - else - { - var sink = new SkipImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - } - - class _ : Sink, IObserver + internal sealed class Count : Producer { - private readonly Skip _parent; - private int _remaining; + private readonly IObservable _source; + private readonly int _count; - public _(Skip parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Count(IObservable source, int count) { - _parent = parent; - _remaining = _parent._count; + _source = source; + _count = count; } - public void OnNext(TSource value) + public IObservable Combine(int count) { - if (_remaining <= 0) - base._observer.OnNext(value); - else - _remaining--; + // + // Sum semantics: + // + // xs --o--o--o--o--o--o--| xs --o--o--o--o--o--o--| + // xs.Skip(2) --x--x--o--o--o--o--| xs.Skip(3) --x--x--x--o--o--o--| + // xs.Skip(2).Skip(3) --------x--x--x--o--| xs.Skip(3).Skip(2) -----------x--x--o--| + // + return new Count(_source, _count + count); } - public void OnError(Exception error) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - base._observer.OnError(error); - base.Dispose(); + var sink = new _(_count, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnCompleted() + private sealed class _ : Sink, IObserver { - base._observer.OnCompleted(); - base.Dispose(); + private int _remaining; + + public _(int count, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _remaining = count; + } + + public void OnNext(TSource value) + { + if (_remaining <= 0) + base._observer.OnNext(value); + else + _remaining--; + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } - class SkipImpl : Sink, IObserver + internal sealed class Time : Producer { - private readonly Skip _parent; - private volatile bool _open; + private readonly IObservable _source; + private readonly TimeSpan _duration; + internal readonly IScheduler _scheduler; - public SkipImpl(Skip parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Time(IObservable source, TimeSpan duration, IScheduler scheduler) { - _parent = parent; + _source = source; + _duration = duration; + _scheduler = scheduler; } - public IDisposable Run() + public IObservable Combine(TimeSpan duration) { - var t = _parent._scheduler.Schedule(_parent._duration, Tick); - var d = _parent._source.SubscribeSafe(this); - return StableCompositeDisposable.Create(t, d); - } - - private void Tick() - { - _open = true; - } - - public void OnNext(TSource value) - { - if (_open) - base._observer.OnNext(value); + // + // Maximum semantics: + // + // t 0--1--2--3--4--5--6--7-> t 0--1--2--3--4--5--6--7-> + // + // xs --o--o--o--o--o--o--| xs --o--o--o--o--o--o--| + // xs.Skip(2s) xxxxxxx-o--o--o--o--| xs.Skip(3s) xxxxxxxxxx-o--o--o--| + // xs.Skip(2s).Skip(3s) xxxxxxxxxx-o--o--o--| xs.Skip(3s).Skip(2s) xxxxxxx----o--o--o--| + // + if (duration <= _duration) + return this; + else + return new Time(_source, duration, _scheduler); } - public void OnError(Exception error) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - base._observer.OnError(error); - base.Dispose(); + var sink = new _(observer, cancel); + setSink(sink); + return sink.Run(this); } - public void OnCompleted() + private sealed class _ : Sink, IObserver { - base._observer.OnCompleted(); - base.Dispose(); + private volatile bool _open; + + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public IDisposable Run(Time parent) + { + var t = parent._scheduler.Schedule(parent._duration, Tick); + var d = parent._source.SubscribeSafe(this); + return StableCompositeDisposable.Create(t, d); + } + + private void Tick() + { + _open = true; + } + + public void OnNext(TSource value) + { + if (_open) + base._observer.OnNext(value); + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Take.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Take.cs index bb0c40611..7700f9a29 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Take.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Take.cs @@ -7,167 +7,169 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Take : Producer + internal static class Take { - private readonly IObservable _source; - private readonly int _count; - private readonly TimeSpan _duration; - internal readonly IScheduler _scheduler; - - public Take(IObservable source, int count) - { - _source = source; - _count = count; - } - - public Take(IObservable source, TimeSpan duration, IScheduler scheduler) - { - _source = source; - _duration = duration; - _scheduler = scheduler; - } - - public IObservable Combine(int count) + internal sealed class Count : Producer { - // - // Minimum semantics: - // - // xs --o--o--o--o--o--o--| xs --o--o--o--o--o--o--| - // xs.Take(5) --o--o--o--o--o| xs.Take(3) --o--o--o| - // xs.Take(5).Take(3) --o--o--o| xs.Take(3).Take(5) --o--o--o| - // - if (_count <= count) - return this; - else - return new Take(_source, count); - } + private readonly IObservable _source; + private readonly int _count; - public IObservable Combine(TimeSpan duration) - { - // - // Minimum semantics: - // - // t 0--1--2--3--4--5--6--7-> t 0--1--2--3--4--5--6--7-> - // - // xs --o--o--o--o--o--o--| xs --o--o--o--o--o--o--| - // xs.Take(5s) --o--o--o--o--o| xs.Take(3s) --o--o--o| - // xs.Take(5s).Take(3s) --o--o--o| xs.Take(3s).Take(5s) --o--o--o| - // - if (_duration <= duration) - return this; - else - return new Take(_source, duration, _scheduler); - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_scheduler == null) + public Count(IObservable source, int count) { - var sink = new _(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; + _count = count; } - else + + public IObservable Combine(int count) { - var sink = new TakeImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); + // + // Minimum semantics: + // + // xs --o--o--o--o--o--o--| xs --o--o--o--o--o--o--| + // xs.Take(5) --o--o--o--o--o| xs.Take(3) --o--o--o| + // xs.Take(5).Take(3) --o--o--o| xs.Take(3).Take(5) --o--o--o| + // + if (_count <= count) + return this; + else + return new Count(_source, count); } - } - - class _ : Sink, IObserver - { - private readonly Take _parent; - private int _remaining; - public _(Take parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _parent = parent; - _remaining = _parent._count; + var sink = new _(_count, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - if (_remaining > 0) + private readonly Count _parent; + private int _remaining; + + public _(int count, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - --_remaining; - base._observer.OnNext(value); + _remaining = count; + } - if (_remaining == 0) + public void OnNext(TSource value) + { + if (_remaining > 0) { - base._observer.OnCompleted(); - base.Dispose(); + --_remaining; + base._observer.OnNext(value); + + if (_remaining == 0) + { + base._observer.OnCompleted(); + base.Dispose(); + } } } - } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } - class TakeImpl : Sink, IObserver + internal sealed class Time : Producer { - private readonly Take _parent; + private readonly IObservable _source; + private readonly TimeSpan _duration; + internal readonly IScheduler _scheduler; - public TakeImpl(Take parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Time(IObservable source, TimeSpan duration, IScheduler scheduler) { - _parent = parent; + _source = source; + _duration = duration; + _scheduler = scheduler; } - private object _gate; - - public IDisposable Run() + public IObservable Combine(TimeSpan duration) { - _gate = new object(); + // + // Minimum semantics: + // + // t 0--1--2--3--4--5--6--7-> t 0--1--2--3--4--5--6--7-> + // + // xs --o--o--o--o--o--o--| xs --o--o--o--o--o--o--| + // xs.Take(5s) --o--o--o--o--o| xs.Take(3s) --o--o--o| + // xs.Take(5s).Take(3s) --o--o--o| xs.Take(3s).Take(5s) --o--o--o| + // + if (_duration <= duration) + return this; + else + return new Time(_source, duration, _scheduler); + } - var t = _parent._scheduler.Schedule(_parent._duration, Tick); - var d = _parent._source.SubscribeSafe(this); - return StableCompositeDisposable.Create(t, d); + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(observer, cancel); + setSink(sink); + return sink.Run(this); } - private void Tick() + private sealed class _ : Sink, IObserver { - lock (_gate) + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnCompleted(); - base.Dispose(); } - } - public void OnNext(TSource value) - { - lock (_gate) + private object _gate; + + public IDisposable Run(Time parent) { - base._observer.OnNext(value); + _gate = new object(); + + var t = parent._scheduler.Schedule(parent._duration, Tick); + var d = parent._source.SubscribeSafe(this); + return StableCompositeDisposable.Create(t, d); } - } - public void OnError(Exception error) - { - lock (_gate) + private void Tick() { - base._observer.OnError(error); - base.Dispose(); + lock (_gate) + { + base._observer.OnCompleted(); + base.Dispose(); + } } - } - public void OnCompleted() - { - lock (_gate) + public void OnNext(TSource value) { - base._observer.OnCompleted(); - base.Dispose(); + lock (_gate) + { + base._observer.OnNext(value); + } + } + + public void OnError(Exception error) + { + lock (_gate) + { + base._observer.OnError(error); + base.Dispose(); + } + } + + public void OnCompleted() + { + lock (_gate) + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs index e68df38a1..b2a8e387d 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs @@ -344,11 +344,11 @@ private static IObservable SelectMany_(I public virtual IObservable Skip(IObservable source, int count) { - var skip = source as Skip; - if (skip != null && skip._scheduler == null) + var skip = source as Skip.Count; + if (skip != null) return skip.Combine(count); - return new Skip(source, count); + return new Skip.Count(source, count); } #endregion @@ -387,11 +387,11 @@ public virtual IObservable Take(IObservable source, i private static IObservable Take_(IObservable source, int count) { - var take = source as Take; - if (take != null && take._scheduler == null) + var take = source as Take.Count; + if (take != null) return take.Combine(count); - return new Take(source, count); + return new Take.Count(source, count); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index 3c380bd27..a7cf773b3 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -251,11 +251,11 @@ public virtual IObservable Skip(IObservable source, T private static IObservable Skip_(IObservable source, TimeSpan duration, IScheduler scheduler) { - var skip = source as Skip; + var skip = source as Skip.Time; if (skip != null && skip._scheduler == scheduler) return skip.Combine(duration); - return new Skip(source, duration, scheduler); + return new Skip.Time(source, duration, scheduler); } #endregion @@ -316,11 +316,11 @@ public virtual IObservable Take(IObservable source, T private static IObservable Take_(IObservable source, TimeSpan duration, IScheduler scheduler) { - var take = source as Take; + var take = source as Take.Time; if (take != null && take._scheduler == scheduler) return take.Combine(duration); - return new Take(source, duration, scheduler); + return new Take.Time(source, duration, scheduler); } #endregion From dbe5c04cbc182951dd8b32b92f5b60bcd32cebd1 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:33:20 -0700 Subject: [PATCH 24/95] Optimizing layout of WithLatestFrom. --- .../Linq/Observable/WithLatestFrom.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/WithLatestFrom.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/WithLatestFrom.cs index 8e6777158..d78e325f4 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/WithLatestFrom.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/WithLatestFrom.cs @@ -21,19 +21,19 @@ public WithLatestFrom(IObservable first, IObservable second, Fu protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_resultSelector, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_first, _second); } - class _ : Sink + private sealed class _ : Sink { - private readonly WithLatestFrom _parent; + private readonly Func _resultSelector; - public _(WithLatestFrom parent, IObserver observer, IDisposable cancel) + public _(Func resultSelector, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _resultSelector = resultSelector; } private object _gate; @@ -42,27 +42,27 @@ public _(WithLatestFrom parent, IObserver obs private object _latestGate; - public IDisposable Run() + public IDisposable Run(IObservable first, IObservable second) { _gate = new object(); _latestGate = new object(); var sndSubscription = new SingleAssignmentDisposable(); - var fstO = new F(this); - var sndO = new S(this, sndSubscription); + var fstO = new FirstObserver(this); + var sndO = new SecondObserver(this, sndSubscription); - var fstSubscription = _parent._first.SubscribeSafe(fstO); - sndSubscription.Disposable = _parent._second.SubscribeSafe(sndO); + var fstSubscription = first.SubscribeSafe(fstO); + sndSubscription.Disposable = second.SubscribeSafe(sndO); return StableCompositeDisposable.Create(fstSubscription, sndSubscription); } - class F : IObserver + private sealed class FirstObserver : IObserver { private readonly _ _parent; - public F(_ parent) + public FirstObserver(_ parent) { _parent = parent; } @@ -101,7 +101,7 @@ public void OnNext(TFirst value) try { - res = _parent._parent._resultSelector(value, latest); + res = _parent._resultSelector(value, latest); } catch (Exception ex) { @@ -122,12 +122,12 @@ public void OnNext(TFirst value) } } - class S : IObserver + private sealed class SecondObserver : IObserver { private readonly _ _parent; private readonly IDisposable _self; - public S(_ parent, IDisposable self) + public SecondObserver(_ parent, IDisposable self) { _parent = parent; _self = self; From 6ce27fcdc1d775c25c826e5d669b6dc9e15e9a6d Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:35:34 -0700 Subject: [PATCH 25/95] Sealing some more sinks. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/For.cs | 2 +- Rx.NET/Source/src/System.Reactive/Linq/Observable/If.cs | 7 ++----- .../src/System.Reactive/Linq/Observable/IgnoreElements.cs | 2 +- .../Source/src/System.Reactive/Linq/Observable/IsEmpty.cs | 2 +- .../Source/src/System.Reactive/Linq/Observable/Latest.cs | 2 +- .../src/System.Reactive/Linq/Observable/MostRecent.cs | 2 +- Rx.NET/Source/src/System.Reactive/Linq/Observable/Next.cs | 2 +- .../Source/src/System.Reactive/Linq/Observable/OfType.cs | 2 +- .../System.Reactive/Linq/Observable/OnErrorResumeNext.cs | 2 +- Rx.NET/Source/src/System.Reactive/Linq/Observable/While.cs | 2 +- 10 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/For.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/For.cs index 546a52eca..472efcb56 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/For.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/For.cs @@ -30,7 +30,7 @@ public IEnumerable> GetSources() yield return _resultSelector(item); } - class _ : ConcatSink + private sealed class _ : ConcatSink { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/If.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/If.cs index 3171bc9c3..f024906bd 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/If.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/If.cs @@ -19,10 +19,7 @@ public If(Func condition, IObservable thenSource, IObservable Eval() - { - return _condition() ? _thenSource : _elseSource; - } + public IObservable Eval() => _condition() ? _thenSource : _elseSource; protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { @@ -31,7 +28,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return sink.Run(); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private readonly If _parent; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/IgnoreElements.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/IgnoreElements.cs index 62f9af9a2..f56fc516e 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/IgnoreElements.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/IgnoreElements.cs @@ -20,7 +20,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/IsEmpty.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/IsEmpty.cs index f43b90abc..a5d36c6db 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/IsEmpty.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/IsEmpty.cs @@ -20,7 +20,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Latest.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Latest.cs index c0cccdf3e..e71c03cc3 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Latest.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Latest.cs @@ -18,7 +18,7 @@ protected override PushToPullSink Run(IDisposable subscription return new _(subscription); } - class _ : PushToPullSink + private sealed class _ : PushToPullSink { private readonly object _gate; private readonly SemaphoreSlim _semaphore; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/MostRecent.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/MostRecent.cs index 045dc9719..0aaf9c789 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/MostRecent.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/MostRecent.cs @@ -19,7 +19,7 @@ protected override PushToPullSink Run(IDisposable subscription return new _(_initialValue, subscription); } - class _ : PushToPullSink + private sealed class _ : PushToPullSink { public _(TSource initialValue, IDisposable subscription) : base(subscription) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Next.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Next.cs index 0343c2536..18efcda1b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Next.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Next.cs @@ -18,7 +18,7 @@ protected override PushToPullSink Run(IDisposable subscription return new _(subscription); } - class _ : PushToPullSink + private sealed class _ : PushToPullSink { private readonly object _gate; private readonly SemaphoreSlim _semaphore; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/OfType.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/OfType.cs index 837af0511..06f0960c6 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/OfType.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/OfType.cs @@ -20,7 +20,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/OnErrorResumeNext.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/OnErrorResumeNext.cs index 53e5626b2..052faf13b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/OnErrorResumeNext.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/OnErrorResumeNext.cs @@ -22,7 +22,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return sink.Run(_sources); } - class _ : TailRecursiveSink + private sealed class _ : TailRecursiveSink { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/While.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/While.cs index 1775f7294..6bab75aea 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/While.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/While.cs @@ -30,7 +30,7 @@ public IEnumerable> GetSources() yield return _source; } - class _ : ConcatSink + private sealed class _ : ConcatSink { public _(IObserver observer, IDisposable cancel) : base(observer, cancel) From 8936200212cc482430dda819c2bd158f95df7ec0 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:35:45 -0700 Subject: [PATCH 26/95] Optimizing layout of Finally. --- .../System.Reactive/Linq/Observable/Finally.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Finally.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Finally.cs index e3698b1d5..25b7a23c7 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Finally.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Finally.cs @@ -19,24 +19,24 @@ public Finally(IObservable source, Action finallyAction) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_finallyAction, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Finally _parent; + private readonly Action _finallyAction; - public _(Finally parent, IObserver observer, IDisposable cancel) + public _(Action finallyAction, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _finallyAction = finallyAction; } - public IDisposable Run() + public IDisposable Run(IObservable source) { - var subscription = _parent._source.SubscribeSafe(this); + var subscription = source.SubscribeSafe(this); return Disposable.Create(() => { @@ -46,7 +46,7 @@ public IDisposable Run() } finally { - _parent._finallyAction(); + _finallyAction(); } }); } From a015a242683a85b0bf4c574c7ead51ab68d182d5 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:37:54 -0700 Subject: [PATCH 27/95] Optimizing layout of TimeInterval. --- .../Linq/Observable/TimeInterval.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TimeInterval.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TimeInterval.cs index 0a1ccc390..fd260e68b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TimeInterval.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TimeInterval.cs @@ -19,30 +19,27 @@ public TimeInterval(IObservable source, IScheduler scheduler) protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } class _ : Sink>, IObserver { - private readonly TimeInterval _parent; - - public _(TimeInterval parent, IObserver> observer, IDisposable cancel) + public _(IObserver> observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } private IStopwatch _watch; private TimeSpan _last; - public IDisposable Run() + public IDisposable Run(TimeInterval parent) { - _watch = _parent._scheduler.StartStopwatch(); + _watch = parent._scheduler.StartStopwatch(); _last = TimeSpan.Zero; - return _parent._source.Subscribe(this); + return parent._source.Subscribe(this); } public void OnNext(TSource value) From ffbfb15a8ab35d6ecef63e9626a73ea4e80fa09b Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:38:03 -0700 Subject: [PATCH 28/95] Optimizing layout of Timestamp. --- .../src/System.Reactive/Linq/Observable/Timestamp.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timestamp.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timestamp.cs index 02e079ff7..45f6e311a 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timestamp.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timestamp.cs @@ -19,24 +19,24 @@ public Timestamp(IObservable source, IScheduler scheduler) protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_scheduler, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } class _ : Sink>, IObserver { - private readonly Timestamp _parent; + private readonly IScheduler _scheduler; - public _(Timestamp parent, IObserver> observer, IDisposable cancel) + public _(IScheduler scheduler, IObserver> observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _scheduler = scheduler; } public void OnNext(TSource value) { - base._observer.OnNext(new Timestamped(value, _parent._scheduler.Now)); + base._observer.OnNext(new Timestamped(value, _scheduler.Now)); } public void OnError(Exception error) From af3440126017912c1b07c76fa682e338e60d7538 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:38:27 -0700 Subject: [PATCH 29/95] Sealing a few more types. --- .../Source/src/System.Reactive/Linq/Observable/TimeInterval.cs | 2 +- Rx.NET/Source/src/System.Reactive/Linq/Observable/Timestamp.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TimeInterval.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TimeInterval.cs index fd260e68b..bdf488f2d 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TimeInterval.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TimeInterval.cs @@ -24,7 +24,7 @@ protected override IDisposable Run(IObserver>, IObserver + private sealed class _ : Sink>, IObserver { public _(IObserver> observer, IDisposable cancel) : base(observer, cancel) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timestamp.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timestamp.cs index 45f6e311a..090251b77 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timestamp.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timestamp.cs @@ -24,7 +24,7 @@ protected override IDisposable Run(IObserver> observer, IDi return _source.SubscribeSafe(sink); } - class _ : Sink>, IObserver + private sealed class _ : Sink>, IObserver { private readonly IScheduler _scheduler; From 40b9627bf2258285df0b03bf24e4138d43febaf2 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:41:26 -0700 Subject: [PATCH 30/95] Optimizing layout of ToObservable. --- .../Linq/Observable/ToObservable.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToObservable.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToObservable.cs index 7c197c9c7..21c04703f 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToObservable.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToObservable.cs @@ -21,27 +21,24 @@ public ToObservable(IEnumerable source, IScheduler scheduler) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink + private sealed class _ : Sink { - private readonly ToObservable _parent; - - public _(ToObservable parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - public IDisposable Run() + public IDisposable Run(ToObservable parent) { var e = default(IEnumerator); try { - e = _parent._source.GetEnumerator(); + e = parent._source.GetEnumerator(); } catch (Exception exception) { @@ -50,7 +47,7 @@ public IDisposable Run() return Disposable.Empty; } - var longRunning = _parent._scheduler.AsLongRunning(); + var longRunning = parent._scheduler.AsLongRunning(); if (longRunning != null) { // @@ -69,12 +66,12 @@ public IDisposable Run() // enumerator. // var flag = new BooleanDisposable(); - _parent._scheduler.Schedule(new State(flag, e), LoopRec); + parent._scheduler.Schedule(new State(flag, e), LoopRec); return flag; } } - class State + private sealed class State { public readonly ICancelable flag; public readonly IEnumerator enumerator; From 872838d9867ce7ec10c034126dd4c7479f68b598 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:49:49 -0700 Subject: [PATCH 31/95] Optimizing layouts of SequenceEqual. --- .../Linq/Observable/SequenceEqual.cs | 449 +++++++++--------- .../Linq/QueryLanguage.Aggregates.cs | 8 +- 2 files changed, 232 insertions(+), 225 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SequenceEqual.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SequenceEqual.cs index 6cbd3c02b..312df0fa7 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SequenceEqual.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SequenceEqual.cs @@ -7,224 +7,210 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class SequenceEqual : Producer + internal static class SequenceEqual { - private readonly IObservable _first; - private readonly IObservable _second; - private readonly IEnumerable _secondE; - private readonly IEqualityComparer _comparer; - - public SequenceEqual(IObservable first, IObservable second, IEqualityComparer comparer) - { - _first = first; - _second = second; - _comparer = comparer; - } - - public SequenceEqual(IObservable first, IEnumerable second, IEqualityComparer comparer) + internal sealed class Observable : Producer { - _first = first; - _secondE = second; - _comparer = comparer; - } + private readonly IObservable _first; + private readonly IObservable _second; + private readonly IEqualityComparer _comparer; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_second != null) + public Observable(IObservable first, IObservable second, IEqualityComparer comparer) { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); + _first = first; + _second = second; + _comparer = comparer; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new SequenceEqualImpl(this, observer, cancel); + var sink = new _(_comparer, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - } - - class _ : Sink - { - private readonly SequenceEqual _parent; - public _(SequenceEqual parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink { - _parent = parent; - } + private readonly IEqualityComparer _comparer; - private object _gate; - private bool _donel; - private bool _doner; - private Queue _ql; - private Queue _qr; - - public IDisposable Run() - { - _gate = new object(); - _donel = false; - _doner = false; - _ql = new Queue(); - _qr = new Queue(); - - return StableCompositeDisposable.Create - ( - _parent._first.SubscribeSafe(new F(this)), - _parent._second.SubscribeSafe(new S(this)) - ); - } + public _(IEqualityComparer comparer, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _comparer = comparer; + } - class F : IObserver - { - private readonly _ _parent; + private object _gate; + private bool _donel; + private bool _doner; + private Queue _ql; + private Queue _qr; - public F(_ parent) + public IDisposable Run(Observable parent) { - _parent = parent; + _gate = new object(); + _donel = false; + _doner = false; + _ql = new Queue(); + _qr = new Queue(); + + return StableCompositeDisposable.Create + ( + parent._first.SubscribeSafe(new FirstObserver(this)), + parent._second.SubscribeSafe(new SecondObserver(this)) + ); } - public void OnNext(TSource value) + private sealed class FirstObserver : IObserver { - lock (_parent._gate) + private readonly _ _parent; + + public FirstObserver(_ parent) { - if (_parent._qr.Count > 0) + _parent = parent; + } + + public void OnNext(TSource value) + { + lock (_parent._gate) { - var equal = false; - var v = _parent._qr.Dequeue(); - try - { - equal = _parent._parent._comparer.Equals(value, v); - } - catch (Exception exception) + if (_parent._qr.Count > 0) { - _parent._observer.OnError(exception); - _parent.Dispose(); - return; + var equal = false; + var v = _parent._qr.Dequeue(); + try + { + equal = _parent._comparer.Equals(value, v); + } + catch (Exception exception) + { + _parent._observer.OnError(exception); + _parent.Dispose(); + return; + } + if (!equal) + { + _parent._observer.OnNext(false); + _parent._observer.OnCompleted(); + _parent.Dispose(); + } } - if (!equal) + else if (_parent._doner) { _parent._observer.OnNext(false); _parent._observer.OnCompleted(); _parent.Dispose(); } + else + _parent._ql.Enqueue(value); } - else if (_parent._doner) - { - _parent._observer.OnNext(false); - _parent._observer.OnCompleted(); - _parent.Dispose(); - } - else - _parent._ql.Enqueue(value); } - } - public void OnError(Exception error) - { - lock (_parent._gate) + public void OnError(Exception error) { - _parent._observer.OnError(error); - _parent.Dispose(); + lock (_parent._gate) + { + _parent._observer.OnError(error); + _parent.Dispose(); + } } - } - public void OnCompleted() - { - lock (_parent._gate) + public void OnCompleted() { - _parent._donel = true; - if (_parent._ql.Count == 0) + lock (_parent._gate) { - if (_parent._qr.Count > 0) - { - _parent._observer.OnNext(false); - _parent._observer.OnCompleted(); - _parent.Dispose(); - } - else if (_parent._doner) + _parent._donel = true; + if (_parent._ql.Count == 0) { - _parent._observer.OnNext(true); - _parent._observer.OnCompleted(); - _parent.Dispose(); + if (_parent._qr.Count > 0) + { + _parent._observer.OnNext(false); + _parent._observer.OnCompleted(); + _parent.Dispose(); + } + else if (_parent._doner) + { + _parent._observer.OnNext(true); + _parent._observer.OnCompleted(); + _parent.Dispose(); + } } } } } - } - - class S : IObserver - { - private readonly _ _parent; - public S(_ parent) + private sealed class SecondObserver : IObserver { - _parent = parent; - } + private readonly _ _parent; - public void OnNext(TSource value) - { - lock (_parent._gate) + public SecondObserver(_ parent) + { + _parent = parent; + } + + public void OnNext(TSource value) { - if (_parent._ql.Count > 0) + lock (_parent._gate) { - var equal = false; - var v = _parent._ql.Dequeue(); - try - { - equal = _parent._parent._comparer.Equals(v, value); - } - catch (Exception exception) + if (_parent._ql.Count > 0) { - _parent._observer.OnError(exception); - _parent.Dispose(); - return; + var equal = false; + var v = _parent._ql.Dequeue(); + try + { + equal = _parent._comparer.Equals(v, value); + } + catch (Exception exception) + { + _parent._observer.OnError(exception); + _parent.Dispose(); + return; + } + if (!equal) + { + _parent._observer.OnNext(false); + _parent._observer.OnCompleted(); + _parent.Dispose(); + } } - if (!equal) + else if (_parent._donel) { _parent._observer.OnNext(false); _parent._observer.OnCompleted(); _parent.Dispose(); } + else + _parent._qr.Enqueue(value); } - else if (_parent._donel) - { - _parent._observer.OnNext(false); - _parent._observer.OnCompleted(); - _parent.Dispose(); - } - else - _parent._qr.Enqueue(value); } - } - public void OnError(Exception error) - { - lock (_parent._gate) + public void OnError(Exception error) { - _parent._observer.OnError(error); - _parent.Dispose(); + lock (_parent._gate) + { + _parent._observer.OnError(error); + _parent.Dispose(); + } } - } - public void OnCompleted() - { - lock (_parent._gate) + public void OnCompleted() { - _parent._doner = true; - if (_parent._qr.Count == 0) + lock (_parent._gate) { - if (_parent._ql.Count > 0) - { - _parent._observer.OnNext(false); - _parent._observer.OnCompleted(); - _parent.Dispose(); - } - else if (_parent._donel) + _parent._doner = true; + if (_parent._qr.Count == 0) { - _parent._observer.OnNext(true); - _parent._observer.OnCompleted(); - _parent.Dispose(); + if (_parent._ql.Count > 0) + { + _parent._observer.OnNext(false); + _parent._observer.OnCompleted(); + _parent.Dispose(); + } + else if (_parent._donel) + { + _parent._observer.OnNext(true); + _parent._observer.OnCompleted(); + _parent.Dispose(); + } } } } @@ -232,95 +218,116 @@ public void OnCompleted() } } - class SequenceEqualImpl : Sink, IObserver + internal sealed class Enumerable : Producer { - private readonly SequenceEqual _parent; + private readonly IObservable _first; + private readonly IEnumerable _second; + private readonly IEqualityComparer _comparer; - public SequenceEqualImpl(SequenceEqual parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Enumerable(IObservable first, IEnumerable second, IEqualityComparer comparer) { - _parent = parent; + _first = first; + _second = second; + _comparer = comparer; } - private IEnumerator _enumerator; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_comparer, observer, cancel); + setSink(sink); + return sink.Run(this); + } - public IDisposable Run() + private sealed class _ : Sink, IObserver { - // - // Notice the evaluation order of obtaining the enumerator and subscribing to the - // observable sequence is reversed compared to the operator's signature. This is - // required to make sure the enumerator is available as soon as the observer can - // be called. Otherwise, we end up having a race for the initialization and use - // of the _rightEnumerator field. - // - try - { - _enumerator = _parent._secondE.GetEnumerator(); - } - catch (Exception exception) + private readonly IEqualityComparer _comparer; + + public _(IEqualityComparer comparer, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnError(exception); - base.Dispose(); - return Disposable.Empty; + _comparer = comparer; } - return StableCompositeDisposable.Create( - _parent._first.SubscribeSafe(this), - _enumerator - ); - } - - public void OnNext(TSource value) - { - var equal = false; + private IEnumerator _enumerator; - try + public IDisposable Run(Enumerable parent) { - if (_enumerator.MoveNext()) + // + // Notice the evaluation order of obtaining the enumerator and subscribing to the + // observable sequence is reversed compared to the operator's signature. This is + // required to make sure the enumerator is available as soon as the observer can + // be called. Otherwise, we end up having a race for the initialization and use + // of the _rightEnumerator field. + // + try + { + _enumerator = parent._second.GetEnumerator(); + } + catch (Exception exception) { - var current = _enumerator.Current; - equal = _parent._comparer.Equals(value, current); + base._observer.OnError(exception); + base.Dispose(); + return Disposable.Empty; } + + return StableCompositeDisposable.Create( + parent._first.SubscribeSafe(this), + _enumerator + ); } - catch (Exception exception) + + public void OnNext(TSource value) { - base._observer.OnError(exception); - base.Dispose(); - return; + var equal = false; + + try + { + if (_enumerator.MoveNext()) + { + var current = _enumerator.Current; + equal = _comparer.Equals(value, current); + } + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + if (!equal) + { + base._observer.OnNext(false); + base._observer.OnCompleted(); + base.Dispose(); + } } - if (!equal) + public void OnError(Exception error) { - base._observer.OnNext(false); - base._observer.OnCompleted(); + base._observer.OnError(error); base.Dispose(); } - } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public void OnCompleted() + { + var hasNext = false; - public void OnCompleted() - { - var hasNext = false; + try + { + hasNext = _enumerator.MoveNext(); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } - try - { - hasNext = _enumerator.MoveNext(); - } - catch (Exception exception) - { - base._observer.OnError(exception); + base._observer.OnNext(!hasNext); + base._observer.OnCompleted(); base.Dispose(); - return; } - - base._observer.OnNext(!hasNext); - base._observer.OnCompleted(); - base.Dispose(); } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs index f24f8afe1..fb761db4f 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs @@ -567,22 +567,22 @@ public virtual IObservable> MinBy(IObservable SequenceEqual(IObservable first, IObservable second) { - return new SequenceEqual(first, second, EqualityComparer.Default); + return new SequenceEqual.Observable(first, second, EqualityComparer.Default); } public virtual IObservable SequenceEqual(IObservable first, IObservable second, IEqualityComparer comparer) { - return new SequenceEqual(first, second, comparer); + return new SequenceEqual.Observable(first, second, comparer); } public virtual IObservable SequenceEqual(IObservable first, IEnumerable second) { - return new SequenceEqual(first, second, EqualityComparer.Default); + return new SequenceEqual.Enumerable(first, second, EqualityComparer.Default); } public virtual IObservable SequenceEqual(IObservable first, IEnumerable second, IEqualityComparer comparer) { - return new SequenceEqual(first, second, comparer); + return new SequenceEqual.Enumerable(first, second, comparer); } #endregion From 0a237b18f9b96862bd302bcb4aea875d400aced7 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:54:52 -0700 Subject: [PATCH 32/95] Optimizing layouts of SkipLast. --- .../Linq/Observable/SkipLast.cs | 184 +++++++++--------- .../Linq/QueryLanguage.Single.cs | 2 +- .../Linq/QueryLanguage.Time.cs | 2 +- 3 files changed, 97 insertions(+), 91 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipLast.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipLast.cs index 06cfa4889..2a8aa79b0 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipLast.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipLast.cs @@ -7,117 +7,123 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class SkipLast : Producer + internal static class SkipLast { - private readonly IObservable _source; - private readonly int _count; - private readonly TimeSpan _duration; - private readonly IScheduler _scheduler; - - public SkipLast(IObservable source, int count) - { - _source = source; - _count = count; - } - - public SkipLast(IObservable source, TimeSpan duration, IScheduler scheduler) - { - _source = source; - _duration = duration; - _scheduler = scheduler; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_scheduler == null) - { - var sink = new _(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); - } - else - { - var sink = new SkipLastImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - } - - class _ : Sink, IObserver + internal sealed class Count : Producer { - private readonly SkipLast _parent; - private Queue _queue; - - public _(SkipLast parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - _queue = new Queue(); - } + private readonly IObservable _source; + private readonly int _count; - public void OnNext(TSource value) + public Count(IObservable source, int count) { - _queue.Enqueue(value); - if (_queue.Count > _parent._count) - base._observer.OnNext(_queue.Dequeue()); + _source = source; + _count = count; } - public void OnError(Exception error) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - base._observer.OnError(error); - base.Dispose(); + var sink = new _(_count, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnCompleted() + private sealed class _ : Sink, IObserver { - base._observer.OnCompleted(); - base.Dispose(); + private int _count; + private Queue _queue; + + public _(int count, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _count = count; + _queue = new Queue(); + } + + public void OnNext(TSource value) + { + _queue.Enqueue(value); + if (_queue.Count > _count) + base._observer.OnNext(_queue.Dequeue()); + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } - class SkipLastImpl : Sink, IObserver + internal sealed class Time : Producer { - private readonly SkipLast _parent; - private Queue> _queue; - - public SkipLastImpl(SkipLast parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - _queue = new Queue>(); - } - - private IStopwatch _watch; - - public IDisposable Run() - { - _watch = _parent._scheduler.StartStopwatch(); + private readonly IObservable _source; + private readonly TimeSpan _duration; + private readonly IScheduler _scheduler; - return _parent._source.SubscribeSafe(this); - } - - public void OnNext(TSource value) + public Time(IObservable source, TimeSpan duration, IScheduler scheduler) { - var now = _watch.Elapsed; - _queue.Enqueue(new System.Reactive.TimeInterval(value, now)); - while (_queue.Count > 0 && now - _queue.Peek().Interval >= _parent._duration) - base._observer.OnNext(_queue.Dequeue().Value); + _source = source; + _duration = duration; + _scheduler = scheduler; } - public void OnError(Exception error) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - base._observer.OnError(error); - base.Dispose(); + var sink = new _(_duration, observer, cancel); + setSink(sink); + return sink.Run(this); } - public void OnCompleted() + private sealed class _ : Sink, IObserver { - var now = _watch.Elapsed; - while (_queue.Count > 0 && now - _queue.Peek().Interval >= _parent._duration) - base._observer.OnNext(_queue.Dequeue().Value); - - base._observer.OnCompleted(); - base.Dispose(); + private readonly TimeSpan _duration; + private Queue> _queue; + + public _(TimeSpan duration, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _duration = duration; + _queue = new Queue>(); + } + + private IStopwatch _watch; + + public IDisposable Run(Time parent) + { + _watch = parent._scheduler.StartStopwatch(); + + return parent._source.SubscribeSafe(this); + } + + public void OnNext(TSource value) + { + var now = _watch.Elapsed; + _queue.Enqueue(new System.Reactive.TimeInterval(value, now)); + while (_queue.Count > 0 && now - _queue.Peek().Interval >= _duration) + base._observer.OnNext(_queue.Dequeue().Value); + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + var now = _watch.Elapsed; + while (_queue.Count > 0 && now - _queue.Peek().Interval >= _duration) + base._observer.OnNext(_queue.Dequeue().Value); + + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs index c62762a83..d47a3d94e 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs @@ -211,7 +211,7 @@ public virtual IObservable Scan(IObservable source, F public virtual IObservable SkipLast(IObservable source, int count) { - return new SkipLast(source, count); + return new SkipLast.Count(source, count); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index a7cf773b3..bec99d8ca 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -274,7 +274,7 @@ public virtual IObservable SkipLast(IObservable sourc private static IObservable SkipLast_(IObservable source, TimeSpan duration, IScheduler scheduler) { - return new SkipLast(source, duration, scheduler); + return new SkipLast.Time(source, duration, scheduler); } #endregion From fccd480a962eb4c4a21ee517b7a0f32bd0ed00de Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:59:02 -0700 Subject: [PATCH 33/95] Optimizing layout of TakeLastBuffer. --- .../Linq/Observable/TakeLastBuffer.cs | 212 +++++++++--------- .../Linq/QueryLanguage.Single.cs | 2 +- .../Linq/QueryLanguage.Time.cs | 2 +- 3 files changed, 111 insertions(+), 105 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLastBuffer.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLastBuffer.cs index 315b70201..5a9790418 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLastBuffer.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLastBuffer.cs @@ -7,131 +7,137 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class TakeLastBuffer : Producer> + internal static class TakeLastBuffer { - private readonly IObservable _source; - private readonly int _count; - private readonly TimeSpan _duration; - private readonly IScheduler _scheduler; - - public TakeLastBuffer(IObservable source, int count) + internal sealed class Count : Producer> { - _source = source; - _count = count; - } - - public TakeLastBuffer(IObservable source, TimeSpan duration, IScheduler scheduler) - { - _source = source; - _duration = duration; - _scheduler = scheduler; - } + private readonly IObservable _source; + private readonly int _count; - protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) - { - if (_scheduler == null) + public Count(IObservable source, int count) { - var sink = new _(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; + _count = count; } - else - { - var sink = new Impl(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - } - class _ : Sink>, IObserver - { - private readonly TakeLastBuffer _parent; - private Queue _queue; - - public _(TakeLastBuffer parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - _parent = parent; - _queue = new Queue(); - } - - public void OnNext(TSource value) - { - _queue.Enqueue(value); - if (_queue.Count > _parent._count) - _queue.Dequeue(); - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); + var sink = new _(_count, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnCompleted() + private sealed class _ : Sink>, IObserver { - var res = new List(_queue.Count); - while (_queue.Count > 0) - res.Add(_queue.Dequeue()); - - base._observer.OnNext(res); - base._observer.OnCompleted(); - base.Dispose(); + private readonly int _count; + private Queue _queue; + + public _(int count, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + _count = count; + _queue = new Queue(); + } + + public void OnNext(TSource value) + { + _queue.Enqueue(value); + if (_queue.Count > _count) + _queue.Dequeue(); + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + var res = new List(_queue.Count); + while (_queue.Count > 0) + res.Add(_queue.Dequeue()); + + base._observer.OnNext(res); + base._observer.OnCompleted(); + base.Dispose(); + } } } - class Impl : Sink>, IObserver + internal sealed class Time : Producer> { - private readonly TakeLastBuffer _parent; - private Queue> _queue; - - public Impl(TakeLastBuffer parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - _queue = new Queue>(); - } - - private IStopwatch _watch; - - public IDisposable Run() - { - _watch = _parent._scheduler.StartStopwatch(); - - return _parent._source.SubscribeSafe(this); - } + private readonly IObservable _source; + private readonly TimeSpan _duration; + private readonly IScheduler _scheduler; - public void OnNext(TSource value) + public Time(IObservable source, TimeSpan duration, IScheduler scheduler) { - var now = _watch.Elapsed; - _queue.Enqueue(new System.Reactive.TimeInterval(value, now)); - Trim(now); + _source = source; + _duration = duration; + _scheduler = scheduler; } - public void OnError(Exception error) + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - base._observer.OnError(error); - base.Dispose(); - } - - public void OnCompleted() - { - var now = _watch.Elapsed; - Trim(now); - - var res = new List(_queue.Count); - while (_queue.Count > 0) - res.Add(_queue.Dequeue().Value); - - base._observer.OnNext(res); - base._observer.OnCompleted(); - base.Dispose(); + var sink = new _(_duration, observer, cancel); + setSink(sink); + return sink.Run(this); } - private void Trim(TimeSpan now) + private sealed class _ : Sink>, IObserver { - while (_queue.Count > 0 && now - _queue.Peek().Interval >= _parent._duration) - _queue.Dequeue(); + private readonly TimeSpan _duration; + private Queue> _queue; + + public _(TimeSpan duration, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + _duration = duration; + _queue = new Queue>(); + } + + private IStopwatch _watch; + + public IDisposable Run(Time parent) + { + _watch = parent._scheduler.StartStopwatch(); + + return parent._source.SubscribeSafe(this); + } + + public void OnNext(TSource value) + { + var now = _watch.Elapsed; + _queue.Enqueue(new System.Reactive.TimeInterval(value, now)); + Trim(now); + } + + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } + + public void OnCompleted() + { + var now = _watch.Elapsed; + Trim(now); + + var res = new List(_queue.Count); + while (_queue.Count > 0) + res.Add(_queue.Dequeue().Value); + + base._observer.OnNext(res); + base._observer.OnCompleted(); + base.Dispose(); + } + + private void Trim(TimeSpan now) + { + while (_queue.Count > 0 && now - _queue.Peek().Interval >= _duration) + _queue.Dequeue(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs index d47a3d94e..435bc0158 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs @@ -277,7 +277,7 @@ private static IObservable TakeLast_(IObservable sour public virtual IObservable> TakeLastBuffer(IObservable source, int count) { - return new TakeLastBuffer(source, count); + return new TakeLastBuffer.Count(source, count); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index bec99d8ca..be3a63c94 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -359,7 +359,7 @@ public virtual IObservable> TakeLastBuffer(IObservable> TakeLastBuffer_(IObservable source, TimeSpan duration, IScheduler scheduler) { - return new TakeLastBuffer(source, duration, scheduler); + return new TakeLastBuffer.Time(source, duration, scheduler); } #endregion From 63a92a2724e894ce0ee14ac029cc6c549db5a82d Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 17:59:11 -0700 Subject: [PATCH 34/95] Removing unused field. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/Take.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Take.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Take.cs index 7700f9a29..4dead392c 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Take.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Take.cs @@ -44,7 +44,6 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - private readonly Count _parent; private int _remaining; public _(int count, IObserver observer, IDisposable cancel) From d54c29e1e903476f25096aac0676287dd99bbab7 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:03:45 -0700 Subject: [PATCH 35/95] Optimizing layouts of TakeLast. --- .../Linq/Observable/TakeLast.cs | 315 +++++++++--------- .../Linq/QueryLanguage.Single.cs | 2 +- .../Linq/QueryLanguage.Time.cs | 2 +- 3 files changed, 163 insertions(+), 156 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLast.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLast.cs index 9717ce5c1..e5ad288b5 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLast.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLast.cs @@ -8,221 +8,228 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class TakeLast : Producer + internal static class TakeLast { - private readonly IObservable _source; - private readonly int _count; - private readonly TimeSpan _duration; - private readonly IScheduler _scheduler; - private readonly IScheduler _loopScheduler; - - public TakeLast(IObservable source, int count, IScheduler loopScheduler) - { - _source = source; - _count = count; - _loopScheduler = loopScheduler; - } - - public TakeLast(IObservable source, TimeSpan duration, IScheduler scheduler, IScheduler loopScheduler) + internal sealed class Count : Producer { - _source = source; - _duration = duration; - _scheduler = scheduler; - _loopScheduler = loopScheduler; - } + private readonly IObservable _source; + private readonly int _count; + private readonly IScheduler _loopScheduler; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_scheduler == null) + public Count(IObservable source, int count, IScheduler loopScheduler) { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _count = count; + _loopScheduler = loopScheduler; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new TakeLastImpl(this, observer, cancel); + var sink = new _(this, observer, cancel); setSink(sink); return sink.Run(); } - } - - class _ : Sink, IObserver - { - private readonly TakeLast _parent; - private Queue _queue; - - public _(TakeLast parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - _queue = new Queue(); - } - - private SingleAssignmentDisposable _subscription; - private SingleAssignmentDisposable _loop; - public IDisposable Run() + private sealed class _ : Sink, IObserver { - _subscription = new SingleAssignmentDisposable(); - _loop = new SingleAssignmentDisposable(); + private readonly Count _parent; + private Queue _queue; - _subscription.Disposable = _parent._source.SubscribeSafe(this); - - return StableCompositeDisposable.Create(_subscription, _loop); - } + public _(Count parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _parent = parent; + _queue = new Queue(); + } - public void OnNext(TSource value) - { - _queue.Enqueue(value); - if (_queue.Count > _parent._count) - _queue.Dequeue(); - } + private SingleAssignmentDisposable _subscription; + private SingleAssignmentDisposable _loop; - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public IDisposable Run() + { + _subscription = new SingleAssignmentDisposable(); + _loop = new SingleAssignmentDisposable(); - public void OnCompleted() - { - _subscription.Dispose(); + _subscription.Disposable = _parent._source.SubscribeSafe(this); - var longRunning = _parent._loopScheduler.AsLongRunning(); - if (longRunning != null) - _loop.Disposable = longRunning.ScheduleLongRunning(Loop); - else - _loop.Disposable = _parent._loopScheduler.Schedule(LoopRec); - } + return StableCompositeDisposable.Create(_subscription, _loop); + } - private void LoopRec(Action recurse) - { - if (_queue.Count > 0) + public void OnNext(TSource value) { - base._observer.OnNext(_queue.Dequeue()); - recurse(); + _queue.Enqueue(value); + if (_queue.Count > _parent._count) + _queue.Dequeue(); } - else + + public void OnError(Exception error) { - base._observer.OnCompleted(); + base._observer.OnError(error); base.Dispose(); } - } - private void Loop(ICancelable cancel) - { - var n = _queue.Count; + public void OnCompleted() + { + _subscription.Dispose(); - while (!cancel.IsDisposed) + var longRunning = _parent._loopScheduler.AsLongRunning(); + if (longRunning != null) + _loop.Disposable = longRunning.ScheduleLongRunning(Loop); + else + _loop.Disposable = _parent._loopScheduler.Schedule(LoopRec); + } + + private void LoopRec(Action recurse) { - if (n == 0) + if (_queue.Count > 0) { - base._observer.OnCompleted(); - break; + base._observer.OnNext(_queue.Dequeue()); + recurse(); } else - base._observer.OnNext(_queue.Dequeue()); - - n--; + { + base._observer.OnCompleted(); + base.Dispose(); + } } - base.Dispose(); + private void Loop(ICancelable cancel) + { + var n = _queue.Count; + + while (!cancel.IsDisposed) + { + if (n == 0) + { + base._observer.OnCompleted(); + break; + } + else + base._observer.OnNext(_queue.Dequeue()); + + n--; + } + + base.Dispose(); + } } } - class TakeLastImpl : Sink, IObserver + internal sealed class Time : Producer { - private readonly TakeLast _parent; - private Queue> _queue; + private readonly IObservable _source; + private readonly TimeSpan _duration; + private readonly IScheduler _scheduler; + private readonly IScheduler _loopScheduler; - public TakeLastImpl(TakeLast parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Time(IObservable source, TimeSpan duration, IScheduler scheduler, IScheduler loopScheduler) { - _parent = parent; - _queue = new Queue>(); + _source = source; + _duration = duration; + _scheduler = scheduler; + _loopScheduler = loopScheduler; } - private SingleAssignmentDisposable _subscription; - private SingleAssignmentDisposable _loop; - private IStopwatch _watch; - - public IDisposable Run() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _subscription = new SingleAssignmentDisposable(); - _loop = new SingleAssignmentDisposable(); - - _watch = _parent._scheduler.StartStopwatch(); - _subscription.Disposable = _parent._source.SubscribeSafe(this); - - return StableCompositeDisposable.Create(_subscription, _loop); + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var now = _watch.Elapsed; - _queue.Enqueue(new System.Reactive.TimeInterval(value, now)); - Trim(now); - } + private readonly Time _parent; + private Queue> _queue; - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public _(Time parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _parent = parent; + _queue = new Queue>(); + } - public void OnCompleted() - { - _subscription.Dispose(); + private SingleAssignmentDisposable _subscription; + private SingleAssignmentDisposable _loop; + private IStopwatch _watch; - var now = _watch.Elapsed; - Trim(now); + public IDisposable Run() + { + _subscription = new SingleAssignmentDisposable(); + _loop = new SingleAssignmentDisposable(); - var longRunning = _parent._loopScheduler.AsLongRunning(); - if (longRunning != null) - _loop.Disposable = longRunning.ScheduleLongRunning(Loop); - else - _loop.Disposable = _parent._loopScheduler.Schedule(LoopRec); - } + _watch = _parent._scheduler.StartStopwatch(); + _subscription.Disposable = _parent._source.SubscribeSafe(this); - private void LoopRec(Action recurse) - { - if (_queue.Count > 0) + return StableCompositeDisposable.Create(_subscription, _loop); + } + + public void OnNext(TSource value) { - base._observer.OnNext(_queue.Dequeue().Value); - recurse(); + var now = _watch.Elapsed; + _queue.Enqueue(new System.Reactive.TimeInterval(value, now)); + Trim(now); } - else + + public void OnError(Exception error) { - base._observer.OnCompleted(); + base._observer.OnError(error); base.Dispose(); } - } - private void Loop(ICancelable cancel) - { - var n = _queue.Count; + public void OnCompleted() + { + _subscription.Dispose(); + + var now = _watch.Elapsed; + Trim(now); + + var longRunning = _parent._loopScheduler.AsLongRunning(); + if (longRunning != null) + _loop.Disposable = longRunning.ScheduleLongRunning(Loop); + else + _loop.Disposable = _parent._loopScheduler.Schedule(LoopRec); + } - while (!cancel.IsDisposed) + private void LoopRec(Action recurse) { - if (n == 0) + if (_queue.Count > 0) { - base._observer.OnCompleted(); - break; + base._observer.OnNext(_queue.Dequeue().Value); + recurse(); } else - base._observer.OnNext(_queue.Dequeue().Value); - - n--; + { + base._observer.OnCompleted(); + base.Dispose(); + } } - base.Dispose(); - } + private void Loop(ICancelable cancel) + { + var n = _queue.Count; - private void Trim(TimeSpan now) - { - while (_queue.Count > 0 && now - _queue.Peek().Interval >= _parent._duration) - _queue.Dequeue(); + while (!cancel.IsDisposed) + { + if (n == 0) + { + base._observer.OnCompleted(); + break; + } + else + base._observer.OnNext(_queue.Dequeue().Value); + + n--; + } + + base.Dispose(); + } + + private void Trim(TimeSpan now) + { + while (_queue.Count > 0 && now - _queue.Peek().Interval >= _parent._duration) + _queue.Dequeue(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs index 435bc0158..155c1ea54 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs @@ -272,7 +272,7 @@ public virtual IObservable TakeLast(IObservable sourc private static IObservable TakeLast_(IObservable source, int count, IScheduler scheduler) { - return new TakeLast(source, count, scheduler); + return new TakeLast.Count(source, count, scheduler); } public virtual IObservable> TakeLastBuffer(IObservable source, int count) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index be3a63c94..1019fa76a 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -344,7 +344,7 @@ public virtual IObservable TakeLast(IObservable sourc private static IObservable TakeLast_(IObservable source, TimeSpan duration, IScheduler timerScheduler, IScheduler loopScheduler) { - return new TakeLast(source, duration, timerScheduler, loopScheduler); + return new TakeLast.Time(source, duration, timerScheduler, loopScheduler); } public virtual IObservable> TakeLastBuffer(IObservable source, TimeSpan duration) From d969ef4c8202c06bfc01c6ab1281f420fbfcd1d1 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:08:32 -0700 Subject: [PATCH 36/95] Optimizing layouts of SkipWhile --- .../Linq/Observable/SkipWhile.cs | 178 +++++++++--------- 1 file changed, 92 insertions(+), 86 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipWhile.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipWhile.cs index 59c204092..f0c00de45 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipWhile.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipWhile.cs @@ -4,133 +4,139 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class SkipWhile : Producer + internal static class SkipWhile { - private readonly IObservable _source; - private readonly Func _predicate; - private readonly Func _predicateI; - - public SkipWhile(IObservable source, Func predicate) - { - _source = source; - _predicate = predicate; - } - - public SkipWhile(IObservable source, Func predicate) + internal sealed class Predicate : Producer { - _source = source; - _predicateI = predicate; - } + private readonly IObservable _source; + private readonly Func _predicate; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_predicate != null) + public Predicate(IObservable source, Func predicate) { - var sink = new _(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; + _predicate = predicate; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new SkipWhileImpl(this, observer, cancel); + var sink = new _(_predicate, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - class _ : Sink, IObserver - { - private readonly SkipWhile _parent; - private bool _running; - - public _(SkipWhile parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver { - _parent = parent; - _running = false; - } + private readonly Func _predicate; + private bool _running; - public void OnNext(TSource value) - { - if (!_running) + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _predicate = predicate; + _running = false; + } + + public void OnNext(TSource value) { - try + if (!_running) { - _running = !_parent._predicate(value); + try + { + _running = !_predicate(value); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } } - catch (Exception exception) + + if (_running) { - base._observer.OnError(exception); - base.Dispose(); - return; + base._observer.OnNext(value); } } - if (_running) + public void OnError(Exception error) { - base._observer.OnNext(value); + base._observer.OnError(error); + base.Dispose(); } - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } - class SkipWhileImpl : Sink, IObserver + internal sealed class PredicateIndexed : Producer { - private readonly SkipWhile _parent; - private bool _running; - private int _index; + private readonly IObservable _source; + private readonly Func _predicate; - public SkipWhileImpl(SkipWhile parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public PredicateIndexed(IObservable source, Func predicate) { - _parent = parent; - _running = false; - _index = 0; + _source = source; + _predicate = predicate; } - public void OnNext(TSource value) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - if (!_running) + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly Func _predicate; + private bool _running; + private int _index; + + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - try + _predicate = predicate; + _running = false; + _index = 0; + } + + public void OnNext(TSource value) + { + if (!_running) { - _running = !_parent._predicateI(value, checked(_index++)); + try + { + _running = !_predicate(value, checked(_index++)); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } } - catch (Exception exception) + + if (_running) { - base._observer.OnError(exception); - base.Dispose(); - return; + base._observer.OnNext(value); } } - if (_running) + public void OnError(Exception error) { - base._observer.OnNext(value); + base._observer.OnError(error); + base.Dispose(); } - } - - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } From 54bbbb90b42c4cbc7392c96cb8fce19ffa7f5e2d Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:13:22 -0700 Subject: [PATCH 37/95] Optimizing layouts of TakeWhile --- .../Linq/Observable/TakeWhile.cs | 206 +++++++++--------- ...QueryLanguage.StandardSequenceOperators.cs | 8 +- 2 files changed, 110 insertions(+), 104 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeWhile.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeWhile.cs index 7f91fc1ce..4b10ab28a 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeWhile.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeWhile.cs @@ -4,143 +4,149 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class TakeWhile : Producer + internal static class TakeWhile { - private readonly IObservable _source; - private readonly Func _predicate; - private readonly Func _predicateI; - - public TakeWhile(IObservable source, Func predicate) + internal sealed class Predicate : Producer { - _source = source; - _predicate = predicate; - } + private readonly IObservable _source; + private readonly Func _predicate; - public TakeWhile(IObservable source, Func predicate) - { - _source = source; - _predicateI = predicate; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_predicate != null) + public Predicate(IObservable source, Func predicate) { - var sink = new _(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); + _source = source; + _predicate = predicate; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new TakeWhileImpl(this, observer, cancel); + var sink = new _(_predicate, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - } - class _ : Sink, IObserver - { - private readonly TakeWhile _parent; - private bool _running; - - public _(TakeWhile parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver { - _parent = parent; - _running = true; - } + private readonly Func _predicate; + private bool _running; - public void OnNext(TSource value) - { - if (_running) + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - try - { - _running = _parent._predicate(value); - } - catch (Exception exception) - { - base._observer.OnError(exception); - base.Dispose(); - return; - } + _predicate = predicate; + _running = true; + } + public void OnNext(TSource value) + { if (_running) { - base._observer.OnNext(value); - } - else - { - base._observer.OnCompleted(); - base.Dispose(); + try + { + _running = _predicate(value); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + if (_running) + { + base._observer.OnNext(value); + } + else + { + base._observer.OnCompleted(); + base.Dispose(); + } } } - } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } - class TakeWhileImpl : Sink, IObserver + internal sealed class PredicateIndexed : Producer { - private readonly TakeWhile _parent; - private bool _running; - private int _index; + private readonly IObservable _source; + private readonly Func _predicate; - public TakeWhileImpl(TakeWhile parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public PredicateIndexed(IObservable source, Func predicate) { - _parent = parent; - _running = true; - _index = 0; + _source = source; + _predicate = predicate; } - public void OnNext(TSource value) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - if (_running) + var sink = new _(_predicate, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly Func _predicate; + private bool _running; + private int _index; + + public _(Func predicate, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - try - { - _running = _parent._predicateI(value, checked(_index++)); - } - catch (Exception exception) - { - base._observer.OnError(exception); - base.Dispose(); - return; - } + _predicate = predicate; + _running = true; + _index = 0; + } + public void OnNext(TSource value) + { if (_running) { - base._observer.OnNext(value); - } - else - { - base._observer.OnCompleted(); - base.Dispose(); + try + { + _running = _predicate(value, checked(_index++)); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + if (_running) + { + base._observer.OnNext(value); + } + else + { + base._observer.OnCompleted(); + base.Dispose(); + } } } - } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public void OnError(Exception error) + { + base._observer.OnError(error); + base.Dispose(); + } - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs index b2a8e387d..a27d6cddb 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs @@ -357,12 +357,12 @@ public virtual IObservable Skip(IObservable source, i public virtual IObservable SkipWhile(IObservable source, Func predicate) { - return new SkipWhile(source, predicate); + return new SkipWhile.Predicate(source, predicate); } public virtual IObservable SkipWhile(IObservable source, Func predicate) { - return new SkipWhile(source, predicate); + return new SkipWhile.PredicateIndexed(source, predicate); } #endregion @@ -400,12 +400,12 @@ private static IObservable Take_(IObservable source, public virtual IObservable TakeWhile(IObservable source, Func predicate) { - return new TakeWhile(source, predicate); + return new TakeWhile.Predicate(source, predicate); } public virtual IObservable TakeWhile(IObservable source, Func predicate) { - return new TakeWhile(source, predicate); + return new TakeWhile.PredicateIndexed(source, predicate); } #endregion From 0ea7f8abb6fe0356f37d43a860f3fac6982cd002 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:15:57 -0700 Subject: [PATCH 38/95] Adding comment to Aggregate. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs index 68dcdefd7..951af3de7 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs @@ -164,6 +164,8 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Aggregate _parent; private TAccumulate _accumulation; From 7cac0c236a4e7bfc4a792bcbf96128319a5cf0f8 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:17:31 -0700 Subject: [PATCH 39/95] Optimizing layout of Amb. --- .../System.Reactive/Linq/Observable/Amb.cs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Amb.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Amb.cs index 6eddfc88c..6c5d45099 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Amb.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Amb.cs @@ -19,24 +19,21 @@ public Amb(IObservable left, IObservable right) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _( observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink + private sealed class _ : Sink { - private readonly Amb _parent; - - public _(Amb parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } private AmbState _choice; - public IDisposable Run() + public IDisposable Run(Amb parent) { var ls = new SingleAssignmentDisposable(); var rs = new SingleAssignmentDisposable(); @@ -54,13 +51,13 @@ public IDisposable Run() _choice = AmbState.Neither; - ls.Disposable = _parent._left.SubscribeSafe(lo); - rs.Disposable = _parent._right.SubscribeSafe(ro); + ls.Disposable = parent._left.SubscribeSafe(lo); + rs.Disposable = parent._right.SubscribeSafe(ro); return d; } - class DecisionObserver : IObserver + private sealed class DecisionObserver : IObserver { private readonly _ _parent; private readonly AmbState _me; @@ -92,7 +89,9 @@ public void OnNext(TSource value) } if (_parent._choice == _me) + { _parent._observer.OnNext(value); + } } } @@ -137,7 +136,7 @@ public void OnCompleted() } } - class AmbObserver : IObserver + private sealed class AmbObserver : IObserver { public IObserver _target; @@ -161,11 +160,11 @@ public void OnCompleted() } } - enum AmbState + private enum AmbState { Left, Right, - Neither + Neither, } } } From d65505dc4eadb30a7a490bc50a6c79b266c10568 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:23:54 -0700 Subject: [PATCH 40/95] Optimizing layout of Using. --- .../System.Reactive/Linq/Observable/Using.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Using.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Using.cs index eca80d5f1..519e8c416 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Using.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Using.cs @@ -20,31 +20,28 @@ public Using(Func resourceFactory, Func observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Using _parent; - - public _(Using parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - public IDisposable Run() + public IDisposable Run(Using parent) { var source = default(IObservable); var disposable = Disposable.Empty; try { - var resource = _parent._resourceFactory(); + var resource = parent._resourceFactory(); if (resource != null) disposable = resource; - source = _parent._observableFactory(resource); + source = parent._observableFactory(resource); } catch (Exception exception) { From 42a258c34366488fb910f8af9b1e2eb7c8a173b8 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:24:50 -0700 Subject: [PATCH 41/95] Optimizing layout of Synchronize. --- .../src/System.Reactive/Linq/Observable/Synchronize.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs index 80304d42d..23e97af7b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs @@ -27,16 +27,14 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.Subscribe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Synchronize _parent; private object _gate; public _(Synchronize parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - _gate = _parent._gate ?? new object(); + _gate = parent._gate ?? new object(); } public void OnNext(TSource value) From 6e947bf6d0855b0f4033665778b2fd2c251b656f Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:25:26 -0700 Subject: [PATCH 42/95] Simplifying code in Synchronize. --- .../src/System.Reactive/Linq/Observable/Synchronize.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs index 23e97af7b..5cfa50138 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs @@ -22,7 +22,7 @@ public Synchronize(IObservable source) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_gate, observer, cancel); setSink(sink); return _source.Subscribe(sink); } @@ -31,10 +31,10 @@ private sealed class _ : Sink, IObserver { private object _gate; - public _(Synchronize parent, IObserver observer, IDisposable cancel) + public _(object gate, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _gate = parent._gate ?? new object(); + _gate = gate ?? new object(); } public void OnNext(TSource value) From 466c01bef832466cd9474607340aab1f5e7d72e4 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:41:58 -0700 Subject: [PATCH 43/95] Optimizing layouts of Timer variants. --- .../System.Reactive/Linq/Observable/Timer.cs | 415 ++++++++++-------- .../Linq/QueryLanguage.Time.cs | 8 +- 2 files changed, 235 insertions(+), 188 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timer.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timer.cs index 290c4f4fe..224a85f28 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timer.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timer.cs @@ -8,253 +8,300 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Timer : Producer + internal static class Timer { - private readonly DateTimeOffset? _dueTimeA; - private readonly TimeSpan? _dueTimeR; - private readonly TimeSpan? _period; - private readonly IScheduler _scheduler; - - public Timer(DateTimeOffset dueTime, TimeSpan? period, IScheduler scheduler) - { - _dueTimeA = dueTime; - _period = period; - _scheduler = scheduler; - } - - public Timer(TimeSpan dueTime, TimeSpan? period, IScheduler scheduler) + internal abstract class Single : Producer { - _dueTimeR = dueTime; - _period = period; - _scheduler = scheduler; - } + private readonly IScheduler _scheduler; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_period.HasValue) + public Single(IScheduler scheduler) { - var sink = new TimerImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); + _scheduler = scheduler; } - else + + internal sealed class Relative : Single { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - } + private readonly TimeSpan _dueTime; - class _ : Sink - { - private readonly Timer _parent; + public Relative(TimeSpan dueTime, IScheduler scheduler) + : base(scheduler) + { + _dueTime = dueTime; + } - public _(Timer parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(observer, cancel); + setSink(sink); + return sink.Run(this, _dueTime); + } } - public IDisposable Run() + internal sealed class Absolute : Single { - if (_parent._dueTimeA.HasValue) + private readonly DateTimeOffset _dueTime; + + public Absolute(DateTimeOffset dueTime, IScheduler scheduler) + : base(scheduler) { - return _parent._scheduler.Schedule(_parent._dueTimeA.Value, Invoke); + _dueTime = dueTime; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - return _parent._scheduler.Schedule(_parent._dueTimeR.Value, Invoke); + var sink = new _(observer, cancel); + setSink(sink); + return sink.Run(this, _dueTime); } } - private void Invoke() + private sealed class _ : Sink { - base._observer.OnNext(0); - base._observer.OnCompleted(); - base.Dispose(); + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public IDisposable Run(Single parent, DateTimeOffset dueTime) + { + return parent._scheduler.Schedule(dueTime, Invoke); + } + + public IDisposable Run(Single parent, TimeSpan dueTime) + { + return parent._scheduler.Schedule(dueTime, Invoke); + } + + private void Invoke() + { + base._observer.OnNext(0); + base._observer.OnCompleted(); + base.Dispose(); + } } } - class TimerImpl : Sink + internal abstract class Periodic : Producer { - private readonly Timer _parent; private readonly TimeSpan _period; + private readonly IScheduler _scheduler; - public TimerImpl(Timer parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Periodic(TimeSpan period, IScheduler scheduler) { - _parent = parent; - _period = _parent._period.Value; + _period = period; + _scheduler = scheduler; } - public IDisposable Run() + internal sealed class Relative : Periodic { - if (_parent._dueTimeA.HasValue) + private readonly TimeSpan _dueTime; + + public Relative(TimeSpan dueTime, TimeSpan period, IScheduler scheduler) + : base(period, scheduler) { - var dueTime = _parent._dueTimeA.Value; - return _parent._scheduler.Schedule(default(object), dueTime, InvokeStart); + _dueTime = dueTime; } - else - { - var dueTime = _parent._dueTimeR.Value; - // - // Optimize for the case of Observable.Interval. - // - if (dueTime == _period) - { - return _parent._scheduler.SchedulePeriodic(0L, _period, (Func)Tick); - } - - return _parent._scheduler.Schedule(default(object), dueTime, InvokeStart); + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_period, observer, cancel); + setSink(sink); + return sink.Run(this, _dueTime); } } - // - // BREAKING CHANGE v2 > v1.x - No more correction for time drift based on absolute time. This - // didn't work for large period values anyway; the fractional - // error exceeded corrections. Also complicated dealing with system - // clock change conditions and caused numerous bugs. - // - // - For more precise scheduling, use a custom scheduler that measures TimeSpan values in a - // better way, e.g. spinning to make up for the last part of the period. Whether or not the - // values of the TimeSpan period match NT time or wall clock time is up to the scheduler. - // - // - For more accurate scheduling wrt the system clock, use Generate with DateTimeOffset time - // selectors. When the system clock changes, intervals will not be the same as diffs between - // consecutive absolute time values. The precision will be low (1s range by default). - // - private long Tick(long count) + internal sealed class Absolute : Periodic { - base._observer.OnNext(count); - return unchecked(count + 1); - } - - private int _pendingTickCount; - private IDisposable _periodic; + private readonly DateTimeOffset _dueTime; - private IDisposable InvokeStart(IScheduler self, object state) - { - // - // Notice the first call to OnNext will introduce skew if it takes significantly long when - // using the following naive implementation: - // - // Code: base._observer.OnNext(0L); - // return self.SchedulePeriodicEmulated(1L, _period, (Func)Tick); - // - // What we're saying here is that Observable.Timer(dueTime, period) is pretty much the same - // as writing Observable.Timer(dueTime).Concat(Observable.Interval(period)). - // - // Expected: dueTime - // | - // 0--period--1--period--2--period--3--period--4--... - // | - // +-OnNext(0L)-| - // - // Actual: dueTime - // | - // 0------------#--period--1--period--2--period--3--period--4--... - // | - // +-OnNext(0L)-| - // - // Different solutions for this behavior have different problems: - // - // 1. Scheduling the periodic job first and using an AsyncLock to serialize the OnNext calls - // has the drawback that InvokeStart may never return. This happens when every callback - // doesn't meet the period's deadline, hence the periodic job keeps queueing stuff up. In - // this case, InvokeStart stays the owner of the AsyncLock and the call to Wait will never - // return, thus not allowing any interleaving of work on this scheduler's logical thread. - // - // 2. Scheduling the periodic job first and using a (blocking) synchronization primitive to - // signal completion of the OnNext(0L) call to the Tick call requires quite a bit of state - // and careful handling of the case when OnNext(0L) throws. What's worse is the blocking - // behavior inside Tick. - // - // In order to avoid blocking behavior, we need a scheme much like SchedulePeriodic emulation - // where work to dispatch OnNext(n + 1) is delegated to a catch up loop in case OnNext(n) was - // still running. Because SchedulePeriodic emulation exhibits such behavior in all cases, we - // only need to deal with the overlap of OnNext(0L) with future periodic OnNext(n) dispatch - // jobs. In the worst case where every callback takes longer than the deadline implied by the - // period, the periodic job will just queue up work that's dispatched by the tail-recursive - // catch up loop. In the best case, all work will be dispatched on the periodic scheduler. - // + public Absolute(DateTimeOffset dueTime, TimeSpan period, IScheduler scheduler) + : base(period, scheduler) + { + _dueTime = dueTime; + } - // - // We start with one tick pending because we're about to start doing OnNext(0L). - // - _pendingTickCount = 1; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_period, observer, cancel); + setSink(sink); + return sink.Run(this, _dueTime); + } + } - var d = new SingleAssignmentDisposable(); - _periodic = d; - d.Disposable = self.SchedulePeriodic(1L, _period, (Func)Tock); + private sealed class _ : Sink + { + private readonly TimeSpan _period; - try + public _(TimeSpan period, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnNext(0L); + _period = period; } - catch (Exception e) + + public IDisposable Run(Periodic parent, DateTimeOffset dueTime) { - d.Dispose(); - e.Throw(); + return parent._scheduler.Schedule(default(object), dueTime, InvokeStart); } - // - // If the periodic scheduling job already ran before we finished dispatching the OnNext(0L) - // call, we'll find pendingTickCount to be > 1. In this case, we need to catch up by dispatching - // subsequent calls to OnNext as fast as possible, but without running a loop in order to ensure - // fair play with the scheduler. So, we run a tail-recursive loop in CatchUp instead. - // - if (Interlocked.Decrement(ref _pendingTickCount) > 0) + public IDisposable Run(Periodic parent, TimeSpan dueTime) { - var c = new SingleAssignmentDisposable(); - c.Disposable = self.Schedule(1L, CatchUp); + // + // Optimize for the case of Observable.Interval. + // + if (dueTime == _period) + { + return parent._scheduler.SchedulePeriodic(0L, _period, (Func)Tick); + } - return StableCompositeDisposable.Create(d, c); + return parent._scheduler.Schedule(default(object), dueTime, InvokeStart); } - return d; - } - - private long Tock(long count) - { // - // Notice the handler for (emulated) periodic scheduling is non-reentrant. + // BREAKING CHANGE v2 > v1.x - No more correction for time drift based on absolute time. This + // didn't work for large period values anyway; the fractional + // error exceeded corrections. Also complicated dealing with system + // clock change conditions and caused numerous bugs. // - // When there's no overlap with the OnNext(0L) call, the following code will cycle through - // pendingTickCount 0 -> 1 -> 0 for the remainder of the timer's execution. + // - For more precise scheduling, use a custom scheduler that measures TimeSpan values in a + // better way, e.g. spinning to make up for the last part of the period. Whether or not the + // values of the TimeSpan period match NT time or wall clock time is up to the scheduler. // - // If there's overlap with the OnNext(0L) call, pendingTickCount will increase to record - // the number of catch up OnNext calls required, which will be dispatched by the recursive - // scheduling loop in CatchUp (which quits when it reaches 0 pending ticks). + // - For more accurate scheduling wrt the system clock, use Generate with DateTimeOffset time + // selectors. When the system clock changes, intervals will not be the same as diffs between + // consecutive absolute time values. The precision will be low (1s range by default). // - if (Interlocked.Increment(ref _pendingTickCount) == 1) + private long Tick(long count) { base._observer.OnNext(count); - Interlocked.Decrement(ref _pendingTickCount); + return unchecked(count + 1); } - return unchecked(count + 1); - } + private int _pendingTickCount; + private IDisposable _periodic; - private void CatchUp(long count, Action recurse) - { - try + private IDisposable InvokeStart(IScheduler self, object state) { - base._observer.OnNext(count); + // + // Notice the first call to OnNext will introduce skew if it takes significantly long when + // using the following naive implementation: + // + // Code: base._observer.OnNext(0L); + // return self.SchedulePeriodicEmulated(1L, _period, (Func)Tick); + // + // What we're saying here is that Observable.Timer(dueTime, period) is pretty much the same + // as writing Observable.Timer(dueTime).Concat(Observable.Interval(period)). + // + // Expected: dueTime + // | + // 0--period--1--period--2--period--3--period--4--... + // | + // +-OnNext(0L)-| + // + // Actual: dueTime + // | + // 0------------#--period--1--period--2--period--3--period--4--... + // | + // +-OnNext(0L)-| + // + // Different solutions for this behavior have different problems: + // + // 1. Scheduling the periodic job first and using an AsyncLock to serialize the OnNext calls + // has the drawback that InvokeStart may never return. This happens when every callback + // doesn't meet the period's deadline, hence the periodic job keeps queueing stuff up. In + // this case, InvokeStart stays the owner of the AsyncLock and the call to Wait will never + // return, thus not allowing any interleaving of work on this scheduler's logical thread. + // + // 2. Scheduling the periodic job first and using a (blocking) synchronization primitive to + // signal completion of the OnNext(0L) call to the Tick call requires quite a bit of state + // and careful handling of the case when OnNext(0L) throws. What's worse is the blocking + // behavior inside Tick. + // + // In order to avoid blocking behavior, we need a scheme much like SchedulePeriodic emulation + // where work to dispatch OnNext(n + 1) is delegated to a catch up loop in case OnNext(n) was + // still running. Because SchedulePeriodic emulation exhibits such behavior in all cases, we + // only need to deal with the overlap of OnNext(0L) with future periodic OnNext(n) dispatch + // jobs. In the worst case where every callback takes longer than the deadline implied by the + // period, the periodic job will just queue up work that's dispatched by the tail-recursive + // catch up loop. In the best case, all work will be dispatched on the periodic scheduler. + // + + // + // We start with one tick pending because we're about to start doing OnNext(0L). + // + _pendingTickCount = 1; + + var d = new SingleAssignmentDisposable(); + _periodic = d; + d.Disposable = self.SchedulePeriodic(1L, _period, (Func)Tock); + + try + { + base._observer.OnNext(0L); + } + catch (Exception e) + { + d.Dispose(); + e.Throw(); + } + + // + // If the periodic scheduling job already ran before we finished dispatching the OnNext(0L) + // call, we'll find pendingTickCount to be > 1. In this case, we need to catch up by dispatching + // subsequent calls to OnNext as fast as possible, but without running a loop in order to ensure + // fair play with the scheduler. So, we run a tail-recursive loop in CatchUp instead. + // + if (Interlocked.Decrement(ref _pendingTickCount) > 0) + { + var c = new SingleAssignmentDisposable(); + c.Disposable = self.Schedule(1L, CatchUp); + + return StableCompositeDisposable.Create(d, c); + } + + return d; } - catch (Exception e) + + private long Tock(long count) { - _periodic.Dispose(); - e.Throw(); + // + // Notice the handler for (emulated) periodic scheduling is non-reentrant. + // + // When there's no overlap with the OnNext(0L) call, the following code will cycle through + // pendingTickCount 0 -> 1 -> 0 for the remainder of the timer's execution. + // + // If there's overlap with the OnNext(0L) call, pendingTickCount will increase to record + // the number of catch up OnNext calls required, which will be dispatched by the recursive + // scheduling loop in CatchUp (which quits when it reaches 0 pending ticks). + // + if (Interlocked.Increment(ref _pendingTickCount) == 1) + { + base._observer.OnNext(count); + Interlocked.Decrement(ref _pendingTickCount); + } + + return unchecked(count + 1); } - // - // We can simply bail out if we decreased the tick count to 0. In that case, the Tock - // method will take over when it sees the 0 -> 1 transition. - // - if (Interlocked.Decrement(ref _pendingTickCount) > 0) + private void CatchUp(long count, Action recurse) { - recurse(unchecked(count + 1)); + try + { + base._observer.OnNext(count); + } + catch (Exception e) + { + _periodic.Dispose(); + e.Throw(); + } + + // + // We can simply bail out if we decreased the tick count to 0. In that case, the Tock + // method will take over when it sees the 0 -> 1 transition. + // + if (Interlocked.Decrement(ref _pendingTickCount) > 0) + { + recurse(unchecked(count + 1)); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index 1019fa76a..a5a45cd5b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -565,22 +565,22 @@ public virtual IObservable Timer(DateTimeOffset dueTime, TimeSpan period, private static IObservable Timer_(TimeSpan dueTime, IScheduler scheduler) { - return new Timer(dueTime, null, scheduler); + return new Timer.Single.Relative(dueTime, scheduler); } private static IObservable Timer_(TimeSpan dueTime, TimeSpan period, IScheduler scheduler) { - return new Timer(dueTime, period, scheduler); + return new Timer.Periodic.Relative(dueTime, period, scheduler); } private static IObservable Timer_(DateTimeOffset dueTime, IScheduler scheduler) { - return new Timer(dueTime, null, scheduler); + return new Timer.Single.Absolute(dueTime, scheduler); } private static IObservable Timer_(DateTimeOffset dueTime, TimeSpan period, IScheduler scheduler) { - return new Timer(dueTime, period, scheduler); + return new Timer.Periodic.Absolute(dueTime, period, scheduler); } #endregion From 2ccfff864cbb2387b6894c243289a84c12a4da44 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 18:58:30 -0700 Subject: [PATCH 44/95] Optimizing layouts of Timeout. --- .../Linq/Observable/Timeout.cs | 350 +++++++++--------- .../Linq/QueryLanguage.Time.cs | 4 +- 2 files changed, 183 insertions(+), 171 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timeout.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timeout.cs index 044aa58fc..17ccef7a1 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timeout.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timeout.cs @@ -7,250 +7,260 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Timeout : Producer + internal static class Timeout { - private readonly IObservable _source; - private readonly TimeSpan? _dueTimeR; - private readonly DateTimeOffset? _dueTimeA; - private readonly IObservable _other; - private readonly IScheduler _scheduler; - - public Timeout(IObservable source, TimeSpan dueTime, IObservable other, IScheduler scheduler) + internal sealed class Relative : Producer { - _source = source; - _dueTimeR = dueTime; - _other = other; - _scheduler = scheduler; - } - - public Timeout(IObservable source, DateTimeOffset dueTime, IObservable other, IScheduler scheduler) - { - _source = source; - _dueTimeA = dueTime; - _other = other; - _scheduler = scheduler; - } + private readonly IObservable _source; + private readonly TimeSpan _dueTime; + private readonly IObservable _other; + private readonly IScheduler _scheduler; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_dueTimeA.HasValue) + public Relative(IObservable source, TimeSpan dueTime, IObservable other, IScheduler scheduler) { - var sink = new TimeA(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _dueTime = dueTime; + _other = other; + _scheduler = scheduler; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new TimeR(this, observer, cancel); + var sink = new _(this, observer, cancel); setSink(sink); return sink.Run(); } - } - - class TimeA : Sink, IObserver - { - private readonly Timeout _parent; - public TimeA(Timeout parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver { - _parent = parent; - } + // CONSIDER: This sink has a parent reference that can be considered for removal. - private SerialDisposable _subscription; - private object _gate; - private bool _switched; + private readonly Relative _parent; - public IDisposable Run() - { - _subscription = new SerialDisposable(); - var original = new SingleAssignmentDisposable(); + public _(Relative parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _parent = parent; + } - _subscription.Disposable = original; + private SerialDisposable _subscription; + private SerialDisposable _timer; - _gate = new object(); - _switched = false; + private object _gate; + private ulong _id; + private bool _switched; - var timer = _parent._scheduler.Schedule(_parent._dueTimeA.Value, Timeout); + public IDisposable Run() + { + _subscription = new SerialDisposable(); + _timer = new SerialDisposable(); + var original = new SingleAssignmentDisposable(); - original.Disposable = _parent._source.SubscribeSafe(this); + _subscription.Disposable = original; - return StableCompositeDisposable.Create(_subscription, timer); - } + _gate = new object(); + _id = 0UL; + _switched = false; - private void Timeout() - { - var timerWins = false; + CreateTimer(); - lock (_gate) - { - timerWins = !_switched; - _switched = true; - } + original.Disposable = _parent._source.SubscribeSafe(this); - if (timerWins) - _subscription.Disposable = _parent._other.SubscribeSafe(this.GetForwarder()); - } + return StableCompositeDisposable.Create(_subscription, _timer); + } - public void OnNext(TSource value) - { - lock (_gate) + private void CreateTimer() { - if (!_switched) - base._observer.OnNext(value); + _timer.Disposable = _parent._scheduler.Schedule(_id, _parent._dueTime, Timeout); } - } - - public void OnError(Exception error) - { - var onErrorWins = false; - lock (_gate) + private IDisposable Timeout(IScheduler _, ulong myid) { - onErrorWins = !_switched; - _switched = true; + var timerWins = false; + + lock (_gate) + { + _switched = (_id == myid); + timerWins = _switched; + } + + if (timerWins) + _subscription.Disposable = _parent._other.SubscribeSafe(this.GetForwarder()); + + return Disposable.Empty; } - if (onErrorWins) + public void OnNext(TSource value) { - base._observer.OnError(error); - base.Dispose(); - } - } + var onNextWins = false; - public void OnCompleted() - { - var onCompletedWins = false; + lock (_gate) + { + onNextWins = !_switched; + if (onNextWins) + { + _id = unchecked(_id + 1); + } + } - lock (_gate) + if (onNextWins) + { + base._observer.OnNext(value); + CreateTimer(); + } + } + + public void OnError(Exception error) { - onCompletedWins = !_switched; - _switched = true; + var onErrorWins = false; + + lock (_gate) + { + onErrorWins = !_switched; + if (onErrorWins) + { + _id = unchecked(_id + 1); + } + } + + if (onErrorWins) + { + base._observer.OnError(error); + base.Dispose(); + } } - if (onCompletedWins) + public void OnCompleted() { - base._observer.OnCompleted(); - base.Dispose(); + var onCompletedWins = false; + + lock (_gate) + { + onCompletedWins = !_switched; + if (onCompletedWins) + { + _id = unchecked(_id + 1); + } + } + + if (onCompletedWins) + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } - class TimeR : Sink, IObserver + internal sealed class Absolute : Producer { - private readonly Timeout _parent; + private readonly IObservable _source; + private readonly DateTimeOffset _dueTime; + private readonly IObservable _other; + private readonly IScheduler _scheduler; - public TimeR(Timeout parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Absolute(IObservable source, DateTimeOffset dueTime, IObservable other, IScheduler scheduler) { - _parent = parent; + _source = source; + _dueTime = dueTime; + _other = other; + _scheduler = scheduler; } - private SerialDisposable _subscription; - private SerialDisposable _timer; - - private object _gate; - private ulong _id; - private bool _switched; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(_other, observer, cancel); + setSink(sink); + return sink.Run(this); + } - public IDisposable Run() + private sealed class _ : Sink, IObserver { - _subscription = new SerialDisposable(); - _timer = new SerialDisposable(); - var original = new SingleAssignmentDisposable(); + private readonly IObservable _other; - _subscription.Disposable = original; + public _(IObservable other, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _other = other; + } - _gate = new object(); - _id = 0UL; - _switched = false; + private SerialDisposable _subscription; + private object _gate; + private bool _switched; - CreateTimer(); + public IDisposable Run(Absolute parent) + { + _subscription = new SerialDisposable(); + var original = new SingleAssignmentDisposable(); - original.Disposable = _parent._source.SubscribeSafe(this); + _subscription.Disposable = original; - return StableCompositeDisposable.Create(_subscription, _timer); - } + _gate = new object(); + _switched = false; - private void CreateTimer() - { - _timer.Disposable = _parent._scheduler.Schedule(_id, _parent._dueTimeR.Value, Timeout); - } + var timer = parent._scheduler.Schedule(parent._dueTime, Timeout); - private IDisposable Timeout(IScheduler _, ulong myid) - { - var timerWins = false; + original.Disposable = parent._source.SubscribeSafe(this); - lock (_gate) - { - _switched = (_id == myid); - timerWins = _switched; + return StableCompositeDisposable.Create(_subscription, timer); } - if (timerWins) - _subscription.Disposable = _parent._other.SubscribeSafe(this.GetForwarder()); + private void Timeout() + { + var timerWins = false; - return Disposable.Empty; - } + lock (_gate) + { + timerWins = !_switched; + _switched = true; + } - public void OnNext(TSource value) - { - var onNextWins = false; + if (timerWins) + _subscription.Disposable = _other.SubscribeSafe(this.GetForwarder()); + } - lock (_gate) + public void OnNext(TSource value) { - onNextWins = !_switched; - if (onNextWins) + lock (_gate) { - _id = unchecked(_id + 1); + if (!_switched) + base._observer.OnNext(value); } } - if (onNextWins) + public void OnError(Exception error) { - base._observer.OnNext(value); - CreateTimer(); - } - } + var onErrorWins = false; - public void OnError(Exception error) - { - var onErrorWins = false; + lock (_gate) + { + onErrorWins = !_switched; + _switched = true; + } - lock (_gate) - { - onErrorWins = !_switched; if (onErrorWins) { - _id = unchecked(_id + 1); + base._observer.OnError(error); + base.Dispose(); } } - if (onErrorWins) + public void OnCompleted() { - base._observer.OnError(error); - base.Dispose(); - } - } + var onCompletedWins = false; - public void OnCompleted() - { - var onCompletedWins = false; + lock (_gate) + { + onCompletedWins = !_switched; + _switched = true; + } - lock (_gate) - { - onCompletedWins = !_switched; if (onCompletedWins) { - _id = unchecked(_id + 1); + base._observer.OnCompleted(); + base.Dispose(); } } - - if (onCompletedWins) - { - base._observer.OnCompleted(); - base.Dispose(); - } } } } @@ -277,8 +287,10 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return sink.Run(); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Timeout _parent; public _(Timeout parent, IObserver observer, IDisposable cancel) @@ -358,16 +370,16 @@ private void SetTimer(IObservable timeout) var d = new SingleAssignmentDisposable(); _timer.Disposable = d; - d.Disposable = timeout.SubscribeSafe(new TimeoutImpl(this, myid, d)); + d.Disposable = timeout.SubscribeSafe(new TimeoutObserver(this, myid, d)); } - class TimeoutImpl : IObserver + private sealed class TimeoutObserver : IObserver { private readonly _ _parent; private readonly ulong _id; private readonly IDisposable _self; - public TimeoutImpl(_ parent, ulong id, IDisposable self) + public TimeoutObserver(_ parent, ulong id, IDisposable self) { _parent = parent; _id = id; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index a5a45cd5b..6e057b718 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -456,7 +456,7 @@ public virtual IObservable Timeout(IObservable source private static IObservable Timeout_(IObservable source, TimeSpan dueTime, IObservable other, IScheduler scheduler) { - return new Timeout(source, dueTime, other, scheduler); + return new Timeout.Relative(source, dueTime, other, scheduler); } #endregion @@ -485,7 +485,7 @@ public virtual IObservable Timeout(IObservable source private static IObservable Timeout_(IObservable source, DateTimeOffset dueTime, IObservable other, IScheduler scheduler) { - return new Timeout(source, dueTime, other, scheduler); + return new Timeout.Absolute(source, dueTime, other, scheduler); } #endregion From 05e85e55befa47cf13cfef3c889fcb7c10d7a415 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:04:29 -0700 Subject: [PATCH 45/95] Optimizing layouts of Scan. --- .../System.Reactive/Linq/Observable/Scan.cs | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Scan.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Scan.cs index 426f39832..f25a03806 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Scan.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Scan.cs @@ -24,31 +24,23 @@ protected override IDisposable Run(IObserver observer, IDisposable return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Scan _parent; + private readonly Func _accumulator; private TAccumulate _accumulation; - private bool _hasAccumulation; public _(Scan parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - _accumulation = default(TAccumulate); - _hasAccumulation = false; + _accumulator = parent._accumulator; + _accumulation = parent._seed; } public void OnNext(TSource value) { try { - if (_hasAccumulation) - _accumulation = _parent._accumulator(_accumulation, value); - else - { - _accumulation = _parent._accumulator(_parent._seed, value); - _hasAccumulation = true; - } + _accumulation = _accumulator(_accumulation, value); } catch (Exception exception) { @@ -87,21 +79,21 @@ public Scan(IObservable source, Func accumul protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_accumulator, observer, cancel); setSink(sink); return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Scan _parent; + private readonly Func _accumulator; private TSource _accumulation; private bool _hasAccumulation; - public _(Scan parent, IObserver observer, IDisposable cancel) + public _(Func accumulator, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _accumulator = accumulator; _accumulation = default(TSource); _hasAccumulation = false; } @@ -111,7 +103,7 @@ public void OnNext(TSource value) try { if (_hasAccumulation) - _accumulation = _parent._accumulator(_accumulation, value); + _accumulation = _accumulator(_accumulation, value); else { _accumulation = value; From 48d661a92ed136569e480b937f3a8ad04c2c8650 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:08:32 -0700 Subject: [PATCH 46/95] Optimizing layouts of Sample. --- .../System.Reactive/Linq/Observable/Sample.cs | 46 ++++++++----------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Sample.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Sample.cs index 83b75f11e..ebf87772e 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Sample.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Sample.cs @@ -20,38 +20,33 @@ public Sample(IObservable source, IObservable sampler) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Sample _parent; + private readonly object _gate = new object(); - public _(Sample parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - private object _gate; - private IDisposable _sourceSubscription; private bool _hasValue; private TSource _value; private bool _atEnd; - public IDisposable Run() + public IDisposable Run(Sample parent) { - _gate = new object(); - var sourceSubscription = new SingleAssignmentDisposable(); _sourceSubscription = sourceSubscription; - sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + sourceSubscription.Disposable = parent._source.SubscribeSafe(this); - var samplerSubscription = _parent._sampler.SubscribeSafe(new SampleImpl(this)); + var samplerSubscription = parent._sampler.SubscribeSafe(new SampleObserver(this)); return StableCompositeDisposable.Create(_sourceSubscription, samplerSubscription); } @@ -83,11 +78,11 @@ public void OnCompleted() } } - class SampleImpl : IObserver + private sealed class SampleObserver : IObserver { private readonly _ _parent; - public SampleImpl(_ parent) + public SampleObserver(_ parent) { _parent = parent; } @@ -156,40 +151,35 @@ public Sample(IObservable source, TimeSpan interval, IScheduler schedul protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Sample _parent; + private object _gate = new object(); - public _(Sample parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - private object _gate; - private IDisposable _sourceSubscription; private bool _hasValue; private TSource _value; private bool _atEnd; - public IDisposable Run() + public IDisposable Run(Sample parent) { - _gate = new object(); - var sourceSubscription = new SingleAssignmentDisposable(); _sourceSubscription = sourceSubscription; - sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + sourceSubscription.Disposable = parent._source.SubscribeSafe(this); return StableCompositeDisposable.Create( sourceSubscription, - _parent._scheduler.SchedulePeriodic(_parent._interval, Tick) + parent._scheduler.SchedulePeriodic(parent._interval, Tick) ); } From 47947744184a907443a241458de7b95a026d782e Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:10:39 -0700 Subject: [PATCH 47/95] Optimizing layout of Case. --- .../src/System.Reactive/Linq/Observable/Case.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Case.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Case.cs index 60405eda3..aa92377ad 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Case.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Case.cs @@ -31,27 +31,24 @@ public IObservable Eval() protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } private sealed class _ : Sink, IObserver { - private readonly Case _parent; - - public _(Case parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - public IDisposable Run() + public IDisposable Run(Case parent) { var result = default(IObservable); try { - result = _parent.Eval(); + result = parent.Eval(); } catch (Exception exception) { From f7be3a0ed0a405a3e4fd311823963818ebeff428 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:12:09 -0700 Subject: [PATCH 48/95] Adding a comment to Collect. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/Collect.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Collect.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Collect.cs index 64011836b..5244c00d4 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Collect.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Collect.cs @@ -27,6 +27,8 @@ protected override PushToPullSink Run(IDisposable subscription private sealed class _ : PushToPullSink { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Collect _parent; public _(Collect parent, IDisposable subscription) From 971515a4209cf2b9d2c87af7a5c3f5031cae148a Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:17:22 -0700 Subject: [PATCH 49/95] Adding a comment to Contains. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs index e22568352..a5158ba19 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs @@ -28,6 +28,8 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, private sealed class _ : Sink, IObserver { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Contains _parent; public _(Contains parent, IObserver observer, IDisposable cancel) From 769038e7998f2a18929a3c295b8559fa7f77cf29 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:21:40 -0700 Subject: [PATCH 50/95] Optimizing layout of DelaySubscription. --- .../Linq/Observable/DelaySubscription.cs | 43 ++++++++++++------- .../Linq/QueryLanguage.Time.cs | 4 +- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DelaySubscription.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DelaySubscription.cs index 6878b8a94..af00c20ff 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DelaySubscription.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DelaySubscription.cs @@ -6,39 +6,50 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class DelaySubscription : Producer + internal abstract class DelaySubscription : Producer { private readonly IObservable _source; - private readonly DateTimeOffset? _dueTimeA; - private readonly TimeSpan? _dueTimeR; private readonly IScheduler _scheduler; - public DelaySubscription(IObservable source, DateTimeOffset dueTime, IScheduler scheduler) + public DelaySubscription(IObservable source, IScheduler scheduler) { _source = source; - _dueTimeA = dueTime; _scheduler = scheduler; } - public DelaySubscription(IObservable source, TimeSpan dueTime, IScheduler scheduler) + internal sealed class Relative : DelaySubscription { - _source = source; - _dueTimeR = dueTime; - _scheduler = scheduler; + private readonly TimeSpan _dueTime; + + public Relative(IObservable source, TimeSpan dueTime, IScheduler scheduler) + : base(source, scheduler) + { + _dueTime = dueTime; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(observer, cancel); + setSink(sink); + return _scheduler.Schedule(sink, _dueTime, Subscribe); + } } - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + internal sealed class Absolute : DelaySubscription { - var sink = new _(observer, cancel); - setSink(sink); + private readonly DateTimeOffset _dueTime; - if (_dueTimeA.HasValue) + public Absolute(IObservable source, DateTimeOffset dueTime, IScheduler scheduler) + : base(source, scheduler) { - return _scheduler.Schedule(sink, _dueTimeA.Value, Subscribe); + _dueTime = dueTime; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - return _scheduler.Schedule(sink, _dueTimeR.Value, Subscribe); + var sink = new _(observer, cancel); + setSink(sink); + return _scheduler.Schedule(sink, _dueTime, Subscribe); } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index 6e057b718..350795d75 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -140,7 +140,7 @@ public virtual IObservable DelaySubscription(IObservable DelaySubscription_(IObservable source, TimeSpan dueTime, IScheduler scheduler) { - return new DelaySubscription(source, dueTime, scheduler); + return new DelaySubscription.Relative(source, dueTime, scheduler); } public virtual IObservable DelaySubscription(IObservable source, DateTimeOffset dueTime) @@ -155,7 +155,7 @@ public virtual IObservable DelaySubscription(IObservable DelaySubscription_(IObservable source, DateTimeOffset dueTime, IScheduler scheduler) { - return new DelaySubscription(source, dueTime, scheduler); + return new DelaySubscription.Absolute(source, dueTime, scheduler); } #endregion From ecba9023aac9b399e06e9c5785bb53c84b75f67b Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:25:30 -0700 Subject: [PATCH 51/95] Adding a few comments. --- .../System.Reactive/Linq/Observable/DistinctUntilChanged.cs | 4 +++- Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DistinctUntilChanged.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DistinctUntilChanged.cs index 85780c518..da0e78c99 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DistinctUntilChanged.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DistinctUntilChanged.cs @@ -26,8 +26,10 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly DistinctUntilChanged _parent; private TKey _currentKey; private bool _hasCurrentKey; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs index 6c443645b..d73c510bd 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Do.cs @@ -168,6 +168,8 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Actions _parent; public _(Actions parent, IObserver observer, IDisposable cancel) From a3f6f63294a52bfe2dbd84e77238269e0680ecb0 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:34:43 -0700 Subject: [PATCH 52/95] Some improvements to FromEvent[Pattern]. --- .../Linq/Observable/FromEvent.cs | 6 ++--- .../Linq/Observable/FromEventPattern.cs | 26 ++++++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/FromEvent.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/FromEvent.cs index 4499b5245..d6074e4cc 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/FromEvent.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/FromEvent.cs @@ -190,7 +190,7 @@ protected override TDelegate GetHandler(Action onNext) } } - abstract class EventProducer : Producer + internal abstract class EventProducer : Producer { private readonly IScheduler _scheduler; private readonly object _gate; @@ -229,7 +229,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel return connection; } - class Session + private sealed class Session { private readonly EventProducer _parent; private readonly Subject _subject; @@ -346,7 +346,7 @@ private IDisposable AddHandler(IScheduler self, TDelegate onNext) } } - abstract class ClassicEventProducer : EventProducer + internal abstract class ClassicEventProducer : EventProducer { private readonly Action _addHandler; private readonly Action _removeHandler; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/FromEventPattern.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/FromEventPattern.cs index 696f44b90..bc243ac6e 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/FromEventPattern.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/FromEventPattern.cs @@ -15,7 +15,7 @@ namespace System.Reactive.Linq.ObservableImpl { internal sealed class FromEventPattern { - public class Impl : ClassicEventProducer> + public sealed class Impl : ClassicEventProducer> { private readonly Func, TDelegate> _conversion; @@ -48,7 +48,7 @@ protected override TDelegate GetHandler(Action> onNext) } } - public class Impl : ClassicEventProducer> + public sealed class Impl : ClassicEventProducer> { public Impl(Action addHandler, Action removeHandler, IScheduler scheduler) : base(addHandler, removeHandler, scheduler) @@ -62,7 +62,7 @@ protected override TDelegate GetHandler(Action } } - public class Handler : EventProducer + public sealed class Handler : EventProducer { private readonly object _target; private readonly Type _delegateType; @@ -103,14 +103,12 @@ protected override IDisposable AddHandler(Delegate handler) #if HAS_WINRT if (_isWinRT) { - var token = _addMethod.Invoke(_target, new object[] { handler }); - removeHandler = () => _removeMethod.Invoke(_target, new object[] { token }); + removeHandler = AddHandlerCoreWinRT(handler); } else #endif { - _addMethod.Invoke(_target, new object[] { handler }); - removeHandler = () => _removeMethod.Invoke(_target, new object[] { handler }); + removeHandler = AddHandlerCore(handler); } } catch (TargetInvocationException tie) @@ -130,6 +128,20 @@ protected override IDisposable AddHandler(Delegate handler) } }); } + + private Action AddHandlerCore(Delegate handler) + { + _addMethod.Invoke(_target, new object[] { handler }); + return () => _removeMethod.Invoke(_target, new object[] { handler }); + } + +#if HAS_WINRT + private Action AddHandlerCoreWinRT(Delegate handler) + { + var token = _addMethod.Invoke(_target, new object[] { handler }); + return () => _removeMethod.Invoke(_target, new object[] { token }); + } +#endif } } } From 34ef5d04458d01102da8f1d4dafd9ace6c4a6ea8 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:37:18 -0700 Subject: [PATCH 53/95] Some stylistic fixes to Generate. --- .../Linq/Observable/Generate.cs | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Generate.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Generate.cs index 4d740a5d7..450c95e37 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Generate.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Generate.cs @@ -68,7 +68,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc } } - class SelectorA : Sink + private sealed class SelectorA : Sink { private readonly Generate _parent; @@ -96,14 +96,23 @@ private IDisposable InvokeRec(IScheduler self, TState state) var time = default(DateTimeOffset); if (_hasResult) + { base._observer.OnNext(_result); + } + try { if (_first) + { _first = false; + } else + { state = _parent._iterate(state); + } + _hasResult = _parent._condition(state); + if (_hasResult) { _result = _parent._resultSelector(state); @@ -128,7 +137,7 @@ private IDisposable InvokeRec(IScheduler self, TState state) } } - class Delta : Sink + private sealed class Delta : Sink { private readonly Generate _parent; @@ -156,14 +165,23 @@ private IDisposable InvokeRec(IScheduler self, TState state) var time = default(TimeSpan); if (_hasResult) + { base._observer.OnNext(_result); + } + try { if (_first) + { _first = false; + } else + { state = _parent._iterate(state); + } + _hasResult = _parent._condition(state); + if (_hasResult) { _result = _parent._resultSelector(state); @@ -188,7 +206,7 @@ private IDisposable InvokeRec(IScheduler self, TState state) } } - class _ : Sink + private sealed class _ : Sink { private readonly Generate _parent; @@ -226,12 +244,20 @@ private void Loop(ICancelable cancel) try { if (_first) + { _first = false; + } else + { _state = _parent._iterate(_state); + } + hasResult = _parent._condition(_state); + if (hasResult) + { result = _parent._resultSelector(_state); + } } catch (Exception exception) { @@ -241,13 +267,19 @@ private void Loop(ICancelable cancel) } if (hasResult) + { base._observer.OnNext(result); + } else + { break; + } } if (!cancel.IsDisposed) + { base._observer.OnCompleted(); + } base.Dispose(); } @@ -259,12 +291,20 @@ private void LoopRec(Action recurse) try { if (_first) + { _first = false; + } else + { _state = _parent._iterate(_state); + } + hasResult = _parent._condition(_state); + if (hasResult) + { result = _parent._resultSelector(_state); + } } catch (Exception exception) { From 94b8a42b07f67e2ddf6b6f574984f48b575ed6d9 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:46:11 -0700 Subject: [PATCH 54/95] Optimizing layouts of Generate variants. --- .../Linq/Observable/Generate.cs | 464 +++++++++--------- .../Linq/QueryLanguage.Creation.cs | 4 +- .../Linq/QueryLanguage.Time.cs | 4 +- 3 files changed, 249 insertions(+), 223 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Generate.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Generate.cs index 450c95e37..cab69ce32 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Generate.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Generate.cs @@ -7,240 +7,313 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Generate : Producer + internal static class Generate { - private readonly TState _initialState; - private readonly Func _condition; - private readonly Func _iterate; - private readonly Func _resultSelector; - private readonly Func _timeSelectorA; - private readonly Func _timeSelectorR; - private readonly IScheduler _scheduler; - - public Generate(TState initialState, Func condition, Func iterate, Func resultSelector, IScheduler scheduler) + internal sealed class NoTime : Producer { - _initialState = initialState; - _condition = condition; - _iterate = iterate; - _resultSelector = resultSelector; - _scheduler = scheduler; - } - - public Generate(TState initialState, Func condition, Func iterate, Func resultSelector, Func timeSelector, IScheduler scheduler) - { - _initialState = initialState; - _condition = condition; - _iterate = iterate; - _resultSelector = resultSelector; - _timeSelectorA = timeSelector; - _scheduler = scheduler; - } - - public Generate(TState initialState, Func condition, Func iterate, Func resultSelector, Func timeSelector, IScheduler scheduler) - { - _initialState = initialState; - _condition = condition; - _iterate = iterate; - _resultSelector = resultSelector; - _timeSelectorR = timeSelector; - _scheduler = scheduler; - } + private readonly TState _initialState; + private readonly Func _condition; + private readonly Func _iterate; + private readonly Func _resultSelector; + private readonly IScheduler _scheduler; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_timeSelectorA != null) + public NoTime(TState initialState, Func condition, Func iterate, Func resultSelector, IScheduler scheduler) { - var sink = new SelectorA(this, observer, cancel); - setSink(sink); - return sink.Run(); + _initialState = initialState; + _condition = condition; + _iterate = iterate; + _resultSelector = resultSelector; + _scheduler = scheduler; } - else if (_timeSelectorR != null) - { - var sink = new Delta(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { var sink = new _(this, observer, cancel); setSink(sink); return sink.Run(); } - } - - private sealed class SelectorA : Sink - { - private readonly Generate _parent; - public SelectorA(Generate parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink { - _parent = parent; - } - - private bool _first; - private bool _hasResult; - private TResult _result; - - public IDisposable Run() - { - _first = true; - _hasResult = false; - _result = default(TResult); - - return _parent._scheduler.Schedule(_parent._initialState, InvokeRec); - } + // CONSIDER: This sink has a parent reference that can be considered for removal. - private IDisposable InvokeRec(IScheduler self, TState state) - { - var time = default(DateTimeOffset); + private readonly NoTime _parent; - if (_hasResult) + public _(NoTime parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnNext(_result); + _parent = parent; } - try + private TState _state; + private bool _first; + + public IDisposable Run() { - if (_first) + _state = _parent._initialState; + _first = true; + + var longRunning = _parent._scheduler.AsLongRunning(); + if (longRunning != null) { - _first = false; + return longRunning.ScheduleLongRunning(Loop); } else { - state = _parent._iterate(state); + return _parent._scheduler.Schedule(LoopRec); } + } - _hasResult = _parent._condition(state); + private void Loop(ICancelable cancel) + { + while (!cancel.IsDisposed) + { + var hasResult = false; + var result = default(TResult); + try + { + if (_first) + { + _first = false; + } + else + { + _state = _parent._iterate(_state); + } + + hasResult = _parent._condition(_state); + + if (hasResult) + { + result = _parent._resultSelector(_state); + } + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } - if (_hasResult) + if (hasResult) + { + base._observer.OnNext(result); + } + else + { + break; + } + } + + if (!cancel.IsDisposed) { - _result = _parent._resultSelector(state); - time = _parent._timeSelectorA(state); + base._observer.OnCompleted(); } - } - catch (Exception exception) - { - base._observer.OnError(exception); + base.Dispose(); - return Disposable.Empty; } - if (!_hasResult) + private void LoopRec(Action recurse) { - base._observer.OnCompleted(); - base.Dispose(); - return Disposable.Empty; - } + var hasResult = false; + var result = default(TResult); + try + { + if (_first) + { + _first = false; + } + else + { + _state = _parent._iterate(_state); + } + + hasResult = _parent._condition(_state); + + if (hasResult) + { + result = _parent._resultSelector(_state); + } + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } - return self.Schedule(state, time, InvokeRec); + if (hasResult) + { + base._observer.OnNext(result); + recurse(); + } + else + { + base._observer.OnCompleted(); + base.Dispose(); + } + } } } - private sealed class Delta : Sink + internal sealed class Absolute : Producer { - private readonly Generate _parent; - - public Delta(Generate parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private readonly TState _initialState; + private readonly Func _condition; + private readonly Func _iterate; + private readonly Func _resultSelector; + private readonly Func _timeSelector; + private readonly IScheduler _scheduler; + + public Absolute(TState initialState, Func condition, Func iterate, Func resultSelector, Func timeSelector, IScheduler scheduler) { - _parent = parent; + _initialState = initialState; + _condition = condition; + _iterate = iterate; + _resultSelector = resultSelector; + _timeSelector = timeSelector; + _scheduler = scheduler; } - private bool _first; - private bool _hasResult; - private TResult _result; - - public IDisposable Run() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _first = true; - _hasResult = false; - _result = default(TResult); - - return _parent._scheduler.Schedule(_parent._initialState, InvokeRec); + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); } - private IDisposable InvokeRec(IScheduler self, TState state) + private sealed class _ : Sink { - var time = default(TimeSpan); + // CONSIDER: This sink has a parent reference that can be considered for removal. + + private readonly Absolute _parent; - if (_hasResult) + public _(Absolute parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnNext(_result); + _parent = parent; } - try + private bool _first; + private bool _hasResult; + private TResult _result; + + public IDisposable Run() { - if (_first) + _first = true; + _hasResult = false; + _result = default(TResult); + + return _parent._scheduler.Schedule(_parent._initialState, InvokeRec); + } + + private IDisposable InvokeRec(IScheduler self, TState state) + { + var time = default(DateTimeOffset); + + if (_hasResult) { - _first = false; + base._observer.OnNext(_result); } - else + + try { - state = _parent._iterate(state); - } + if (_first) + { + _first = false; + } + else + { + state = _parent._iterate(state); + } - _hasResult = _parent._condition(state); + _hasResult = _parent._condition(state); - if (_hasResult) + if (_hasResult) + { + _result = _parent._resultSelector(state); + time = _parent._timeSelector(state); + } + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return Disposable.Empty; + } + + if (!_hasResult) { - _result = _parent._resultSelector(state); - time = _parent._timeSelectorR(state); + base._observer.OnCompleted(); + base.Dispose(); + return Disposable.Empty; } - } - catch (Exception exception) - { - base._observer.OnError(exception); - base.Dispose(); - return Disposable.Empty; - } - if (!_hasResult) - { - base._observer.OnCompleted(); - base.Dispose(); - return Disposable.Empty; + return self.Schedule(state, time, InvokeRec); } - - return self.Schedule(state, time, InvokeRec); } } - private sealed class _ : Sink + internal sealed class Relative : Producer { - private readonly Generate _parent; - - public _(Generate parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private readonly TState _initialState; + private readonly Func _condition; + private readonly Func _iterate; + private readonly Func _resultSelector; + private readonly Func _timeSelector; + private readonly IScheduler _scheduler; + + public Relative(TState initialState, Func condition, Func iterate, Func resultSelector, Func timeSelector, IScheduler scheduler) { - _parent = parent; + _initialState = initialState; + _condition = condition; + _iterate = iterate; + _resultSelector = resultSelector; + _timeSelector = timeSelector; + _scheduler = scheduler; } - private TState _state; - private bool _first; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); + } - public IDisposable Run() + private sealed class _ : Sink { - _state = _parent._initialState; - _first = true; + // CONSIDER: This sink has a parent reference that can be considered for removal. + + private readonly Relative _parent; - var longRunning = _parent._scheduler.AsLongRunning(); - if (longRunning != null) + public _(Relative parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - return longRunning.ScheduleLongRunning(Loop); + _parent = parent; } - else + + private bool _first; + private bool _hasResult; + private TResult _result; + + public IDisposable Run() { - return _parent._scheduler.Schedule(LoopRec); + _first = true; + _hasResult = false; + _result = default(TResult); + + return _parent._scheduler.Schedule(_parent._initialState, InvokeRec); } - } - private void Loop(ICancelable cancel) - { - while (!cancel.IsDisposed) + private IDisposable InvokeRec(IScheduler self, TState state) { - var hasResult = false; - var result = default(TResult); + var time = default(TimeSpan); + + if (_hasResult) + { + base._observer.OnNext(_result); + } + try { if (_first) @@ -249,79 +322,32 @@ private void Loop(ICancelable cancel) } else { - _state = _parent._iterate(_state); + state = _parent._iterate(state); } - hasResult = _parent._condition(_state); + _hasResult = _parent._condition(state); - if (hasResult) + if (_hasResult) { - result = _parent._resultSelector(_state); + _result = _parent._resultSelector(state); + time = _parent._timeSelector(state); } } catch (Exception exception) { base._observer.OnError(exception); base.Dispose(); - return; + return Disposable.Empty; } - if (hasResult) - { - base._observer.OnNext(result); - } - else + if (!_hasResult) { - break; - } - } - - if (!cancel.IsDisposed) - { - base._observer.OnCompleted(); - } - - base.Dispose(); - } - - private void LoopRec(Action recurse) - { - var hasResult = false; - var result = default(TResult); - try - { - if (_first) - { - _first = false; - } - else - { - _state = _parent._iterate(_state); - } - - hasResult = _parent._condition(_state); - - if (hasResult) - { - result = _parent._resultSelector(_state); + base._observer.OnCompleted(); + base.Dispose(); + return Disposable.Empty; } - } - catch (Exception exception) - { - base._observer.OnError(exception); - base.Dispose(); - return; - } - if (hasResult) - { - base._observer.OnNext(result); - recurse(); - } - else - { - base._observer.OnCompleted(); - base.Dispose(); + return self.Schedule(state, time, InvokeRec); } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Creation.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Creation.cs index ac21d67f5..e1b0abf41 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Creation.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Creation.cs @@ -148,12 +148,12 @@ public virtual IObservable Empty(IScheduler scheduler) public virtual IObservable Generate(TState initialState, Func condition, Func iterate, Func resultSelector) { - return new Generate(initialState, condition, iterate, resultSelector, SchedulerDefaults.Iteration); + return new Generate.NoTime(initialState, condition, iterate, resultSelector, SchedulerDefaults.Iteration); } public virtual IObservable Generate(TState initialState, Func condition, Func iterate, Func resultSelector, IScheduler scheduler) { - return new Generate(initialState, condition, iterate, resultSelector, scheduler); + return new Generate.NoTime(initialState, condition, iterate, resultSelector, scheduler); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index 350795d75..9e81adb26 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -174,7 +174,7 @@ public virtual IObservable Generate(TState initialStat private static IObservable Generate_(TState initialState, Func condition, Func iterate, Func resultSelector, Func timeSelector, IScheduler scheduler) { - return new Generate(initialState, condition, iterate, resultSelector, timeSelector, scheduler); + return new Generate.Relative(initialState, condition, iterate, resultSelector, timeSelector, scheduler); } public virtual IObservable Generate(TState initialState, Func condition, Func iterate, Func resultSelector, Func timeSelector) @@ -189,7 +189,7 @@ public virtual IObservable Generate(TState initialStat private static IObservable Generate_(TState initialState, Func condition, Func iterate, Func resultSelector, Func timeSelector, IScheduler scheduler) { - return new Generate(initialState, condition, iterate, resultSelector, timeSelector, scheduler); + return new Generate.Absolute(initialState, condition, iterate, resultSelector, timeSelector, scheduler); } #endregion From 384e5f8c324804b912a86cd03b99306ee0cbc289 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:47:09 -0700 Subject: [PATCH 55/95] Misc. cosmetic changes. --- .../Linq/Observable/GetEnumerator.cs | 10 ++-------- .../Linq/Observable/PushToPullAdapter.cs | 14 ++++---------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/GetEnumerator.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/GetEnumerator.cs index b29fab8a0..d25dfa9aa 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/GetEnumerator.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/GetEnumerator.cs @@ -75,15 +75,9 @@ public bool MoveNext() return false; } - public TSource Current - { - get { return _current; } - } + public TSource Current => _current; - object Collections.IEnumerator.Current - { - get { return _current; } - } + object Collections.IEnumerator.Current => _current; public void Dispose() { diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/PushToPullAdapter.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/PushToPullAdapter.cs index 5faa9a720..c35f2f729 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/PushToPullAdapter.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/PushToPullAdapter.cs @@ -8,7 +8,7 @@ namespace System.Reactive.Linq.ObservableImpl { - abstract class PushToPullAdapter : IEnumerable + internal abstract class PushToPullAdapter : IEnumerable { private readonly IObservable _source; @@ -17,10 +17,7 @@ public PushToPullAdapter(IObservable source) _source = source; } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() { @@ -33,7 +30,7 @@ public IEnumerator GetEnumerator() protected abstract PushToPullSink Run(IDisposable subscription); } - abstract class PushToPullSink : IObserver, IEnumerator, IDisposable + internal abstract class PushToPullSink : IObserver, IEnumerator, IDisposable { private readonly IDisposable _subscription; @@ -76,10 +73,7 @@ public TResult Current private set; } - object IEnumerator.Current - { - get { return Current; } - } + object IEnumerator.Current => Current; public void Reset() { From f9443554e5dad83843ef58376e8906a7314645e2 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:50:44 -0700 Subject: [PATCH 56/95] Sealing sinks for Join. --- .../System.Reactive/Linq/Observable/Join.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Join.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Join.cs index fb8064e44..3723cdd9e 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Join.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Join.cs @@ -31,8 +31,10 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return sink.Run(); } - class _ : Sink + private sealed class _ : Sink { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Join _parent; public _(Join parent, IObserver observer, IDisposable cancel) @@ -47,7 +49,7 @@ public _(Join parent, IOb private bool _leftDone; private int _leftID; private SortedDictionary _leftMap; - + private bool _rightDone; private int _rightID; private SortedDictionary _rightMap; @@ -56,7 +58,7 @@ public IDisposable Run() { _gate = new object(); _group = new CompositeDisposable(); - + var leftSubscription = new SingleAssignmentDisposable(); _group.Add(leftSubscription); _leftDone = false; @@ -75,7 +77,7 @@ public IDisposable Run() return _group; } - class LeftObserver : IObserver + private sealed class LeftObserver : IObserver { private readonly _ _parent; private readonly IDisposable _self; @@ -126,7 +128,7 @@ public void OnNext(TLeft value) return; } - md.Disposable = duration.SubscribeSafe(new Delta(this, id, md)); + md.Disposable = duration.SubscribeSafe(new DurationObserver(this, id, md)); lock (_parent._gate) { @@ -152,13 +154,13 @@ public void OnNext(TLeft value) } } - class Delta : IObserver + private sealed class DurationObserver : IObserver { private readonly LeftObserver _parent; private readonly int _id; private readonly IDisposable _self; - public Delta(LeftObserver parent, int id, IDisposable self) + public DurationObserver(LeftObserver parent, int id, IDisposable self) { _parent = parent; _id = id; @@ -208,7 +210,7 @@ public void OnCompleted() } } - class RightObserver : IObserver + private sealed class RightObserver : IObserver { private readonly _ _parent; private readonly IDisposable _self; @@ -259,7 +261,7 @@ public void OnNext(TRight value) return; } - md.Disposable = duration.SubscribeSafe(new Delta(this, id, md)); + md.Disposable = duration.SubscribeSafe(new DurationObserver(this, id, md)); lock (_parent._gate) { @@ -285,13 +287,13 @@ public void OnNext(TRight value) } } - class Delta : IObserver + private sealed class DurationObserver : IObserver { private readonly RightObserver _parent; private readonly int _id; private readonly IDisposable _self; - public Delta(RightObserver parent, int id, IDisposable self) + public DurationObserver(RightObserver parent, int id, IDisposable self) { _parent = parent; _id = id; From 83d6ced578b44e5ff46c8109af41880dcdf56065 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Mon, 17 Apr 2017 19:53:29 -0700 Subject: [PATCH 57/95] Sealing some more sinks. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/MaxBy.cs | 2 +- Rx.NET/Source/src/System.Reactive/Linq/Observable/MinBy.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/MaxBy.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/MaxBy.cs index d63788078..dbf5d37eb 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/MaxBy.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/MaxBy.cs @@ -26,7 +26,7 @@ protected override IDisposable Run(IObserver> observer, IDisposab return _source.SubscribeSafe(sink); } - class _ : Sink>, IObserver + private sealed class _ : Sink>, IObserver { private readonly MaxBy _parent; private bool _hasValue; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/MinBy.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/MinBy.cs index fd9ee815e..a9e1da432 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/MinBy.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/MinBy.cs @@ -26,7 +26,7 @@ protected override IDisposable Run(IObserver> observer, IDisposab return _source.SubscribeSafe(sink); } - class _ : Sink>, IObserver + private sealed class _ : Sink>, IObserver { private readonly MinBy _parent; private bool _hasValue; From 1698aa7d9bfc98b9d0367b95f44b2567a778fb8e Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 10:33:23 -0700 Subject: [PATCH 58/95] Optimizing layouts of Merge variants. --- .../System.Reactive/Linq/Observable/Merge.cs | 513 +++++++++--------- .../Linq/QueryLanguage.Multiple.cs | 6 +- 2 files changed, 262 insertions(+), 257 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Merge.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Merge.cs index 2329a2ccd..7df0ca784 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Merge.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Merge.cs @@ -9,285 +9,276 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Merge : Producer + internal static class Merge { - private readonly IObservable> _sources; - private readonly IObservable> _sourcesT; - private readonly int _maxConcurrent; - - public Merge(IObservable> sources) - { - _sources = sources; - } - - public Merge(IObservable> sources, int maxConcurrent) + internal sealed class ObservablesMaxConcurrency : Producer { - _sources = sources; - _maxConcurrent = maxConcurrent; - } + private readonly IObservable> _sources; + private readonly int _maxConcurrent; - public Merge(IObservable> sources) - { - _sourcesT = sources; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_maxConcurrent > 0) - { - var sink = new MergeConcurrent(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - else if (_sourcesT != null) + public ObservablesMaxConcurrency(IObservable> sources, int maxConcurrent) { - var sink = new MergeImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); + _sources = sources; + _maxConcurrent = maxConcurrent; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(_maxConcurrent, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - } - - class _ : Sink, IObserver> - { - private readonly Merge _parent; - public _(Merge parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink, IObserver> { - _parent = parent; - } + private readonly int _maxConcurrent; - private object _gate; - private bool _isStopped; - private CompositeDisposable _group; - private SingleAssignmentDisposable _sourceSubscription; + public _(int maxConcurrent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _maxConcurrent = maxConcurrent; + } - public IDisposable Run() - { - _gate = new object(); - _isStopped = false; - _group = new CompositeDisposable(); + private object _gate; + private Queue> _q; + private bool _isStopped; + private SingleAssignmentDisposable _sourceSubscription; + private CompositeDisposable _group; + private int _activeCount = 0; - _sourceSubscription = new SingleAssignmentDisposable(); - _group.Add(_sourceSubscription); - _sourceSubscription.Disposable = _parent._sources.SubscribeSafe(this); + public IDisposable Run(ObservablesMaxConcurrency parent) + { + _gate = new object(); + _q = new Queue>(); + _isStopped = false; + _activeCount = 0; - return _group; - } + _group = new CompositeDisposable(); + _sourceSubscription = new SingleAssignmentDisposable(); + _sourceSubscription.Disposable = parent._sources.SubscribeSafe(this); + _group.Add(_sourceSubscription); - public void OnNext(IObservable value) - { - var innerSubscription = new SingleAssignmentDisposable(); - _group.Add(innerSubscription); - innerSubscription.Disposable = value.SubscribeSafe(new Iter(this, innerSubscription)); - } + return _group; + } - public void OnError(Exception error) - { - lock (_gate) + public void OnNext(IObservable value) { - base._observer.OnError(error); - base.Dispose(); + lock (_gate) + { + if (_activeCount < _maxConcurrent) + { + _activeCount++; + Subscribe(value); + } + else + _q.Enqueue(value); + } } - } - public void OnCompleted() - { - _isStopped = true; - if (_group.Count == 1) + public void OnError(Exception error) { - // - // Notice there can be a race between OnCompleted of the source and any - // of the inner sequences, where both see _group.Count == 1, and one is - // waiting for the lock. There won't be a double OnCompleted observation - // though, because the call to Dispose silences the observer by swapping - // in a NopObserver. - // lock (_gate) { - base._observer.OnCompleted(); + base._observer.OnError(error); base.Dispose(); } } - else - { - _sourceSubscription.Dispose(); - } - } - class Iter : IObserver - { - private readonly _ _parent; - private readonly IDisposable _self; - - public Iter(_ parent, IDisposable self) + public void OnCompleted() { - _parent = parent; - _self = self; + lock (_gate) + { + _isStopped = true; + if (_activeCount == 0) + { + base._observer.OnCompleted(); + base.Dispose(); + } + else + { + _sourceSubscription.Dispose(); + } + } } - public void OnNext(TSource value) + private void Subscribe(IObservable innerSource) { - lock (_parent._gate) - _parent._observer.OnNext(value); + var subscription = new SingleAssignmentDisposable(); + _group.Add(subscription); + subscription.Disposable = innerSource.SubscribeSafe(new InnerObserver(this, subscription)); } - public void OnError(Exception error) + private sealed class InnerObserver : IObserver { - lock (_parent._gate) + private readonly _ _parent; + private readonly IDisposable _self; + + public InnerObserver(_ parent, IDisposable self) { - _parent._observer.OnError(error); - _parent.Dispose(); + _parent = parent; + _self = self; } - } - public void OnCompleted() - { - _parent._group.Remove(_self); - if (_parent._isStopped && _parent._group.Count == 1) + public void OnNext(TSource value) + { + lock (_parent._gate) + _parent._observer.OnNext(value); + } + + public void OnError(Exception error) { - // - // Notice there can be a race between OnCompleted of the source and any - // of the inner sequences, where both see _group.Count == 1, and one is - // waiting for the lock. There won't be a double OnCompleted observation - // though, because the call to Dispose silences the observer by swapping - // in a NopObserver. - // lock (_parent._gate) { - _parent._observer.OnCompleted(); + _parent._observer.OnError(error); _parent.Dispose(); } } + + public void OnCompleted() + { + _parent._group.Remove(_self); + lock (_parent._gate) + { + if (_parent._q.Count > 0) + { + var s = _parent._q.Dequeue(); + _parent.Subscribe(s); + } + else + { + _parent._activeCount--; + if (_parent._isStopped && _parent._activeCount == 0) + { + _parent._observer.OnCompleted(); + _parent.Dispose(); + } + } + } + } } } } - class MergeConcurrent : Sink, IObserver> + internal sealed class Observables : Producer { - private readonly Merge _parent; + private readonly IObservable> _sources; - public MergeConcurrent(Merge parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Observables(IObservable> sources) { - _parent = parent; + _sources = sources; } - private object _gate; - private Queue> _q; - private bool _isStopped; - private SingleAssignmentDisposable _sourceSubscription; - private CompositeDisposable _group; - private int _activeCount = 0; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(observer, cancel); + setSink(sink); + return sink.Run(this); + } - public IDisposable Run() + private sealed class _ : Sink, IObserver> { - _gate = new object(); - _q = new Queue>(); - _isStopped = false; - _activeCount = 0; + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } - _group = new CompositeDisposable(); - _sourceSubscription = new SingleAssignmentDisposable(); - _sourceSubscription.Disposable = _parent._sources.SubscribeSafe(this); - _group.Add(_sourceSubscription); + private object _gate; + private bool _isStopped; + private CompositeDisposable _group; + private SingleAssignmentDisposable _sourceSubscription; - return _group; - } + public IDisposable Run(Observables parent) + { + _gate = new object(); + _isStopped = false; + _group = new CompositeDisposable(); - public void OnNext(IObservable value) - { - lock (_gate) + _sourceSubscription = new SingleAssignmentDisposable(); + _group.Add(_sourceSubscription); + _sourceSubscription.Disposable = parent._sources.SubscribeSafe(this); + + return _group; + } + + public void OnNext(IObservable value) { - if (_activeCount < _parent._maxConcurrent) - { - _activeCount++; - Subscribe(value); - } - else - _q.Enqueue(value); + var innerSubscription = new SingleAssignmentDisposable(); + _group.Add(innerSubscription); + innerSubscription.Disposable = value.SubscribeSafe(new InnerObserver(this, innerSubscription)); } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { - base._observer.OnError(error); - base.Dispose(); + lock (_gate) + { + base._observer.OnError(error); + base.Dispose(); + } } - } - public void OnCompleted() - { - lock (_gate) + public void OnCompleted() { _isStopped = true; - if (_activeCount == 0) + if (_group.Count == 1) { - base._observer.OnCompleted(); - base.Dispose(); + // + // Notice there can be a race between OnCompleted of the source and any + // of the inner sequences, where both see _group.Count == 1, and one is + // waiting for the lock. There won't be a double OnCompleted observation + // though, because the call to Dispose silences the observer by swapping + // in a NopObserver. + // + lock (_gate) + { + base._observer.OnCompleted(); + base.Dispose(); + } } else { _sourceSubscription.Dispose(); } } - } - - private void Subscribe(IObservable innerSource) - { - var subscription = new SingleAssignmentDisposable(); - _group.Add(subscription); - subscription.Disposable = innerSource.SubscribeSafe(new Iter(this, subscription)); - } - class Iter : IObserver - { - private readonly MergeConcurrent _parent; - private readonly IDisposable _self; - - public Iter(MergeConcurrent parent, IDisposable self) + private sealed class InnerObserver : IObserver { - _parent = parent; - _self = self; - } + private readonly _ _parent; + private readonly IDisposable _self; - public void OnNext(TSource value) - { - lock (_parent._gate) - _parent._observer.OnNext(value); - } + public InnerObserver(_ parent, IDisposable self) + { + _parent = parent; + _self = self; + } - public void OnError(Exception error) - { - lock (_parent._gate) + public void OnNext(TSource value) { - _parent._observer.OnError(error); - _parent.Dispose(); + lock (_parent._gate) + _parent._observer.OnNext(value); } - } - public void OnCompleted() - { - _parent._group.Remove(_self); - lock (_parent._gate) + public void OnError(Exception error) { - if (_parent._q.Count > 0) + lock (_parent._gate) { - var s = _parent._q.Dequeue(); - _parent.Subscribe(s); + _parent._observer.OnError(error); + _parent.Dispose(); } - else + } + + public void OnCompleted() + { + _parent._group.Remove(_self); + if (_parent._isStopped && _parent._group.Count == 1) { - _parent._activeCount--; - if (_parent._isStopped && _parent._activeCount == 0) + // + // Notice there can be a race between OnCompleted of the source and any + // of the inner sequences, where both see _group.Count == 1, and one is + // waiting for the lock. There won't be a double OnCompleted observation + // though, because the call to Dispose silences the observer by swapping + // in a NopObserver. + // + lock (_parent._gate) { _parent._observer.OnCompleted(); _parent.Dispose(); @@ -298,90 +289,104 @@ public void OnCompleted() } } - class MergeImpl : Sink, IObserver> + internal sealed class Tasks : Producer { - private readonly Merge _parent; + private readonly IObservable> _sources; - public MergeImpl(Merge parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Tasks(IObservable> sources) { - _parent = parent; + _sources = sources; } - private object _gate; - private volatile int _count; - - public IDisposable Run() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _gate = new object(); - _count = 1; - - return _parent._sourcesT.SubscribeSafe(this); + var sink = new _(observer, cancel); + setSink(sink); + return sink.Run(this); } - public void OnNext(Task value) + private sealed class _ : Sink, IObserver> { - Interlocked.Increment(ref _count); - if (value.IsCompleted) + public _(IObserver observer, IDisposable cancel) + : base(observer, cancel) { - OnCompletedTask(value); } - else + + private object _gate; + private volatile int _count; + + public IDisposable Run(Tasks parent) { - value.ContinueWith(OnCompletedTask); + _gate = new object(); + _count = 1; + + return parent._sources.SubscribeSafe(this); } - } - private void OnCompletedTask(Task task) - { - switch (task.Status) + public void OnNext(Task value) { - case TaskStatus.RanToCompletion: - { - lock (_gate) - base._observer.OnNext(task.Result); + Interlocked.Increment(ref _count); + if (value.IsCompleted) + { + OnCompletedTask(value); + } + else + { + value.ContinueWith(OnCompletedTask); + } + } - OnCompleted(); - } - break; - case TaskStatus.Faulted: - { - lock (_gate) + private void OnCompletedTask(Task task) + { + switch (task.Status) + { + case TaskStatus.RanToCompletion: { - base._observer.OnError(task.Exception.InnerException); - base.Dispose(); + lock (_gate) + base._observer.OnNext(task.Result); + + OnCompleted(); } - } - break; - case TaskStatus.Canceled: - { - lock (_gate) + break; + case TaskStatus.Faulted: { - base._observer.OnError(new TaskCanceledException(task)); - base.Dispose(); + lock (_gate) + { + base._observer.OnError(task.Exception.InnerException); + base.Dispose(); + } } - } - break; + break; + case TaskStatus.Canceled: + { + lock (_gate) + { + base._observer.OnError(new TaskCanceledException(task)); + base.Dispose(); + } + } + break; + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { - base._observer.OnError(error); - base.Dispose(); + lock (_gate) + { + base._observer.OnError(error); + base.Dispose(); + } } - } - public void OnCompleted() - { - if (Interlocked.Decrement(ref _count) == 0) + public void OnCompleted() { - lock (_gate) + if (Interlocked.Decrement(ref _count) == 0) { - base._observer.OnCompleted(); - base.Dispose(); + lock (_gate) + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs index 532329476..b47f741bf 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs @@ -248,7 +248,7 @@ public virtual IObservable Merge(IObservable Merge(IObservable> sources) { - return new Merge(sources); + return new Merge.Tasks(sources); } public virtual IObservable Merge(IObservable> sources, int maxConcurrent) @@ -298,12 +298,12 @@ public virtual IObservable Merge(IEnumerable Merge_(IObservable> sources) { - return new Merge(sources); + return new Merge.Observables(sources); } private static IObservable Merge_(IObservable> sources, int maxConcurrent) { - return new Merge(sources, maxConcurrent); + return new Merge.ObservablesMaxConcurrency(sources, maxConcurrent); } #endregion From fc8e754af8091ec447ac7ac05cebf9de36ba7ab4 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 10:48:51 -0700 Subject: [PATCH 59/95] Further optimizations to ObserveOn, --- .../Concurrency/Synchronization.ObserveOn.cs | 142 +++++++++--------- .../Concurrency/Synchronization.cs | 4 +- .../Linq/Observable/ObserveOn.cs | 90 +++++------ 3 files changed, 123 insertions(+), 113 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Concurrency/Synchronization.ObserveOn.cs b/Rx.NET/Source/src/System.Reactive/Concurrency/Synchronization.ObserveOn.cs index f7676ba93..3d91fb4fa 100644 --- a/Rx.NET/Source/src/System.Reactive/Concurrency/Synchronization.ObserveOn.cs +++ b/Rx.NET/Source/src/System.Reactive/Concurrency/Synchronization.ObserveOn.cs @@ -7,34 +7,21 @@ namespace System.Reactive.Concurrency { - internal sealed class ObserveOn : Producer + internal static class ObserveOn { - private readonly IObservable _source; - private readonly IScheduler _scheduler; - private readonly SynchronizationContext _context; - - public ObserveOn(IObservable source, IScheduler scheduler) - { - _source = source; - _scheduler = scheduler; - } - - public ObserveOn(IObservable source, SynchronizationContext context) + internal sealed class Scheduler : Producer { - _source = source; - _context = context; - } + private readonly IObservable _source; + private readonly IScheduler _scheduler; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2", Justification = "Visibility restricted to friend assemblies. Those should be correct by inspection.")] - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_context != null) + public Scheduler(IObservable source, IScheduler scheduler) { - var sink = new ObserveOnSink(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _scheduler = scheduler; } - else + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2", Justification = "Visibility restricted to friend assemblies. Those should be correct by inspection.")] + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { var sink = new ObserveOnObserver(_scheduler, observer, cancel); setSink(sink); @@ -42,66 +29,83 @@ protected override IDisposable Run(IObserver observer, IDisposable canc } } - private sealed class ObserveOnSink : Sink, IObserver + internal sealed class Context : Producer { - private readonly ObserveOn _parent; + private readonly IObservable _source; + private readonly SynchronizationContext _context; - public ObserveOnSink(ObserveOn parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Context(IObservable source, SynchronizationContext context) { - _parent = parent; + _source = source; + _context = context; } - public IDisposable Run() + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2", Justification = "Visibility restricted to friend assemblies. Those should be correct by inspection.")] + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - // - // The interactions with OperationStarted/OperationCompleted below allow - // for test frameworks to wait until a whole sequence is observed, running - // asserts on a per-message level. Also, for ASP.NET pages, the use of the - // built-in synchronization context would allow processing to finished in - // its entirety before moving on with the page lifecycle. - // - _parent._context.OperationStarted(); - - var d = _parent._source.SubscribeSafe(this); - var c = Disposable.Create(() => - { - _parent._context.OperationCompleted(); - }); - - return StableCompositeDisposable.Create(d, c); + var sink = new _(_context, observer, cancel); + setSink(sink); + return sink.Run(_source); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - _parent._context.Post(OnNextPosted, value); - } + private readonly SynchronizationContext _context; - public void OnError(Exception error) - { - _parent._context.Post(OnErrorPosted, error); - } + public _(SynchronizationContext context, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _context = context; + } - public void OnCompleted() - { - _parent._context.Post(OnCompletedPosted, state: null); - } + public IDisposable Run(IObservable source) + { + // + // The interactions with OperationStarted/OperationCompleted below allow + // for test frameworks to wait until a whole sequence is observed, running + // asserts on a per-message level. Also, for ASP.NET pages, the use of the + // built-in synchronization context would allow processing to finished in + // its entirety before moving on with the page lifecycle. + // + _context.OperationStarted(); + + var d = source.SubscribeSafe(this); + var c = Disposable.Create(_context.OperationCompleted); + + return StableCompositeDisposable.Create(d, c); + } + + public void OnNext(TSource value) + { + _context.Post(OnNextPosted, value); + } - private void OnNextPosted(object value) - { - _observer.OnNext((TSource)value); - } + public void OnError(Exception error) + { + _context.Post(OnErrorPosted, error); + } - private void OnErrorPosted(object error) - { - _observer.OnError((Exception)error); - Dispose(); - } + public void OnCompleted() + { + _context.Post(OnCompletedPosted, state: null); + } - private void OnCompletedPosted(object ignored) - { - _observer.OnCompleted(); - Dispose(); + private void OnNextPosted(object value) + { + _observer.OnNext((TSource)value); + } + + private void OnErrorPosted(object error) + { + _observer.OnError((Exception)error); + Dispose(); + } + + private void OnCompletedPosted(object ignored) + { + _observer.OnCompleted(); + Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Concurrency/Synchronization.cs b/Rx.NET/Source/src/System.Reactive/Concurrency/Synchronization.cs index c4e1cff8a..b868238d2 100644 --- a/Rx.NET/Source/src/System.Reactive/Concurrency/Synchronization.cs +++ b/Rx.NET/Source/src/System.Reactive/Concurrency/Synchronization.cs @@ -102,7 +102,7 @@ public static IObservable ObserveOn(IObservable sourc if (scheduler == null) throw new ArgumentNullException(nameof(scheduler)); - return new ObserveOn(source, scheduler); + return new ObserveOn.Scheduler(source, scheduler); } /// @@ -120,7 +120,7 @@ public static IObservable ObserveOn(IObservable sourc if (context == null) throw new ArgumentNullException(nameof(context)); - return new ObserveOn(source, context); + return new ObserveOn.Context(source, context); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs index f0192b04b..72f5514d7 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs @@ -7,33 +7,20 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class ObserveOn : Producer + internal static class ObserveOn { - private readonly IObservable _source; - private readonly IScheduler _scheduler; - private readonly SynchronizationContext _context; - - public ObserveOn(IObservable source, IScheduler scheduler) + internal sealed class Scheduler : Producer { - _source = source; - _scheduler = scheduler; - } - - public ObserveOn(IObservable source, SynchronizationContext context) - { - _source = source; - _context = context; - } + private readonly IObservable _source; + private readonly IScheduler _scheduler; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_context != null) + public Scheduler(IObservable source, IScheduler scheduler) { - var sink = new Context(_context, observer, cancel); - setSink(sink); - return _source.Subscribe(sink); + _source = source; + _scheduler = scheduler; } - else + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { var sink = new ObserveOnObserver(_scheduler, observer, cancel); setSink(sink); @@ -41,40 +28,59 @@ protected override IDisposable Run(IObserver observer, IDisposable canc } } - private sealed class Context : Sink, IObserver + internal sealed class Context : Producer { + private readonly IObservable _source; private readonly SynchronizationContext _context; - public Context(SynchronizationContext context, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Context(IObservable source, SynchronizationContext context) { + _source = source; _context = context; } - public void OnNext(TSource value) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _context.PostWithStartComplete(() => - { - base._observer.OnNext(value); - }); + var sink = new _(_context, observer, cancel); + setSink(sink); + return _source.Subscribe(sink); } - public void OnError(Exception error) + private sealed class _ : Sink, IObserver { - _context.PostWithStartComplete(() => + private readonly SynchronizationContext _context; + + public _(SynchronizationContext context, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnError(error); - base.Dispose(); - }); - } + _context = context; + } - public void OnCompleted() - { - _context.PostWithStartComplete(() => + public void OnNext(TSource value) + { + _context.PostWithStartComplete(() => + { + base._observer.OnNext(value); + }); + } + + public void OnError(Exception error) + { + _context.PostWithStartComplete(() => + { + base._observer.OnError(error); + base.Dispose(); + }); + } + + public void OnCompleted() { - base._observer.OnCompleted(); - base.Dispose(); - }); + _context.PostWithStartComplete(() => + { + base._observer.OnCompleted(); + base.Dispose(); + }); + } } } } From 8a3e2fe39a26c5032f35c1ac397b60a6ad833dee Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 10:52:07 -0700 Subject: [PATCH 60/95] Sealing some more sinks. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs | 2 +- Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs index c5b1a3f6d..a5ea2800b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs @@ -22,7 +22,7 @@ protected override IDisposable Run(IObserver observer, IDisposable ca return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private List _list; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs index 48142a377..712d6a524 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs @@ -22,7 +22,7 @@ protected override IDisposable Run(IObserver> observer, IDisposab return _source.SubscribeSafe(sink); } - class _ : Sink>, IObserver + private sealed class _ : Sink>, IObserver { private List _list; From 7d962def4468ee08a2532876667cb435c27c531a Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 10:54:55 -0700 Subject: [PATCH 61/95] Optimizing RefCount layout. --- .../Linq/Observable/RefCount.cs | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/RefCount.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/RefCount.cs index e6fd9e883..4a53e7ae9 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/RefCount.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/RefCount.cs @@ -25,30 +25,27 @@ public RefCount(IConnectableObservable source) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly RefCount _parent; - - public _(RefCount parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - public IDisposable Run() + public IDisposable Run(RefCount parent) { - var subscription = _parent._source.SubscribeSafe(this); + var subscription = parent._source.SubscribeSafe(this); - lock (_parent._gate) + lock (parent._gate) { - if (++_parent._count == 1) + if (++parent._count == 1) { - _parent._connectableSubscription = _parent._source.Connect(); + parent._connectableSubscription = parent._source.Connect(); } } @@ -56,11 +53,11 @@ public IDisposable Run() { subscription.Dispose(); - lock (_parent._gate) + lock (parent._gate) { - if (--_parent._count == 0) + if (--parent._count == 0) { - _parent._connectableSubscription.Dispose(); + parent._connectableSubscription.Dispose(); } } }); From c8cf043bcec8f304cc509168c7d4011c0772e3c9 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 11:08:39 -0700 Subject: [PATCH 62/95] Optimizing layouts of Repeat. --- .../System.Reactive/Linq/Observable/Repeat.cs | 178 ++++++++++-------- .../Linq/QueryLanguage.Creation.cs | 8 +- 2 files changed, 104 insertions(+), 82 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Repeat.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Repeat.cs index 180fc5711..0c5c47961 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Repeat.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Repeat.cs @@ -7,119 +7,141 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Repeat : Producer + internal static class Repeat { - private readonly TResult _value; - private readonly int? _repeatCount; - private readonly IScheduler _scheduler; - - public Repeat(TResult value, int? repeatCount, IScheduler scheduler) + internal sealed class Forever : Producer { - _value = value; - _repeatCount = repeatCount; - _scheduler = scheduler; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); - } + private readonly TResult _value; + private readonly IScheduler _scheduler; - class _ : Sink - { - private readonly Repeat _parent; + public Forever(TResult value, IScheduler scheduler) + { + _value = value; + _scheduler = scheduler; + } - public _(Repeat parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _parent = parent; + var sink = new _(_value, observer, cancel); + setSink(sink); + return sink.Run(this); } - public IDisposable Run() + private sealed class _ : Sink { - var longRunning = _parent._scheduler.AsLongRunning(); - if (longRunning != null) + private readonly TResult _value; + + public _(TResult value, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - return Run(longRunning); + _value = value; } - else + + public IDisposable Run(Forever parent) { - return Run(_parent._scheduler); + var longRunning = parent._scheduler.AsLongRunning(); + if (longRunning != null) + { + return longRunning.ScheduleLongRunning(LoopInf); + } + else + { + return parent._scheduler.Schedule(LoopRecInf); + } } - } - private IDisposable Run(IScheduler scheduler) - { - if (_parent._repeatCount == null) + private void LoopRecInf(Action recurse) { - return scheduler.Schedule(LoopRecInf); + base._observer.OnNext(_value); + recurse(); } - else + + private void LoopInf(ICancelable cancel) { - return scheduler.Schedule(_parent._repeatCount.Value, LoopRec); + var value = _value; + while (!cancel.IsDisposed) + base._observer.OnNext(value); + + base.Dispose(); } } + } + + internal sealed class Count : Producer + { + private readonly TResult _value; + private readonly IScheduler _scheduler; + private readonly int _repeatCount; - private void LoopRecInf(Action recurse) + public Count(TResult value, int repeatCount, IScheduler scheduler) { - base._observer.OnNext(_parent._value); - recurse(); + _value = value; + _scheduler = scheduler; + _repeatCount = repeatCount; } - private void LoopRec(int n, Action recurse) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - if (n > 0) - { - base._observer.OnNext(_parent._value); - n--; - } - - if (n == 0) - { - base._observer.OnCompleted(); - base.Dispose(); - return; - } - - recurse(n); + var sink = new _(_value, observer, cancel); + setSink(sink); + return sink.Run(this); } - private IDisposable Run(ISchedulerLongRunning scheduler) + private sealed class _ : Sink { - if (_parent._repeatCount == null) + private readonly TResult _value; + + public _(TResult value, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - return scheduler.ScheduleLongRunning(LoopInf); + _value = value; } - else + + public IDisposable Run(Count parent) { - return scheduler.ScheduleLongRunning(_parent._repeatCount.Value, Loop); + var longRunning = parent._scheduler.AsLongRunning(); + if (longRunning != null) + { + return longRunning.ScheduleLongRunning(parent._repeatCount, Loop); + } + else + { + return parent._scheduler.Schedule(parent._repeatCount, LoopRec); + } } - } - private void LoopInf(ICancelable cancel) - { - var value = _parent._value; - while (!cancel.IsDisposed) - base._observer.OnNext(value); - - base.Dispose(); - } - - private void Loop(int n, ICancelable cancel) - { - var value = _parent._value; - while (n > 0 && !cancel.IsDisposed) + private void LoopRec(int n, Action recurse) { - base._observer.OnNext(value); - n--; + if (n > 0) + { + base._observer.OnNext(_value); + n--; + } + + if (n == 0) + { + base._observer.OnCompleted(); + base.Dispose(); + return; + } + + recurse(n); } - if (!cancel.IsDisposed) - base._observer.OnCompleted(); + private void Loop(int n, ICancelable cancel) + { + var value = _value; + while (n > 0 && !cancel.IsDisposed) + { + base._observer.OnNext(value); + n--; + } + + if (!cancel.IsDisposed) + base._observer.OnCompleted(); - base.Dispose(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Creation.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Creation.cs index e1b0abf41..8984100e7 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Creation.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Creation.cs @@ -190,22 +190,22 @@ private static IObservable Range_(int start, int count, IScheduler schedule public virtual IObservable Repeat(TResult value) { - return new Repeat(value, null, SchedulerDefaults.Iteration); + return new Repeat.Forever(value, SchedulerDefaults.Iteration); } public virtual IObservable Repeat(TResult value, IScheduler scheduler) { - return new Repeat(value, null, scheduler); + return new Repeat.Forever(value, scheduler); } public virtual IObservable Repeat(TResult value, int repeatCount) { - return new Repeat(value, repeatCount, SchedulerDefaults.Iteration); + return new Repeat.Count(value, repeatCount, SchedulerDefaults.Iteration); } public virtual IObservable Repeat(TResult value, int repeatCount, IScheduler scheduler) { - return new Repeat(value, repeatCount, scheduler); + return new Repeat.Count(value, repeatCount, scheduler); } #endregion From e92f0e787bc824b017aa69d1fa52e6b7a59205c5 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 11:10:28 -0700 Subject: [PATCH 63/95] Stylistic change to Scan. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/Scan.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Scan.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Scan.cs index f25a03806..b9d244893 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Scan.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Scan.cs @@ -103,7 +103,9 @@ public void OnNext(TSource value) try { if (_hasAccumulation) + { _accumulation = _accumulator(_accumulation, value); + } else { _accumulation = value; From add3eb5d354ca1b781525aac2d200a31587fb90e Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:08:33 -0700 Subject: [PATCH 64/95] Initial refactoring of SelectMany. --- .../Linq/Observable/SelectMany.cs | 2437 +++++++++-------- 1 file changed, 1251 insertions(+), 1186 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SelectMany.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SelectMany.cs index 14ffe0156..904a21f7d 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SelectMany.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SelectMany.cs @@ -9,233 +9,92 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class SelectMany : Producer + internal static class SelectMany { - private readonly IObservable _source; - private readonly Func> _collectionSelector; - private readonly Func> _collectionSelectorI; - private readonly Func> _collectionSelectorE; - private readonly Func> _collectionSelectorEI; - private readonly Func _resultSelector; - private readonly Func _resultSelectorI; - private readonly Func> _collectionSelectorT; - private readonly Func> _collectionSelectorTI; - private readonly Func _resultSelectorTI; - - public SelectMany(IObservable source, Func> collectionSelector, Func resultSelector) + internal sealed class ObservableSelector : Producer { - _source = source; - _collectionSelector = collectionSelector; - _resultSelector = resultSelector; - } - - public SelectMany(IObservable source, Func> collectionSelector, Func resultSelector) - { - _source = source; - _collectionSelectorI = collectionSelector; - _resultSelectorI = resultSelector; - } - - public SelectMany(IObservable source, Func> collectionSelector, Func resultSelector) - { - _source = source; - _collectionSelectorE = collectionSelector; - _resultSelector = resultSelector; - } - - public SelectMany(IObservable source, Func> collectionSelector, Func resultSelector) - { - _source = source; - _collectionSelectorEI = collectionSelector; - _resultSelectorI = resultSelector; - } - - public SelectMany(IObservable source, Func> collectionSelector, Func resultSelector) - { - _source = source; - _collectionSelectorT = collectionSelector; - _resultSelector = resultSelector; - } - - public SelectMany(IObservable source, Func> collectionSelector, Func resultSelector) - { - _source = source; - _collectionSelectorTI = collectionSelector; - _resultSelectorTI = resultSelector; - } + private readonly IObservable _source; + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_collectionSelector != null) - { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - else if (_collectionSelectorI != null) - { - var sink = new IndexSelectorImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - else if (_collectionSelectorT != null) + public ObservableSelector(IObservable source, Func> collectionSelector, Func resultSelector) { - var sink = new SelectManyImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _collectionSelector = collectionSelector; + _resultSelector = resultSelector; } - else if (_collectionSelectorTI != null) + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new Sigma(this, observer, cancel); + var sink = new _(this, observer, cancel); setSink(sink); return sink.Run(); } - else if (_collectionSelectorE != null) - { - var sink = new NoSelectorImpl(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); - } - else - { - var sink = new Omega(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); - } - } - - class _ : Sink, IObserver - { - private readonly SelectMany _parent; - - public _(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - } - - private object _gate; - private bool _isStopped; - private CompositeDisposable _group; - private SingleAssignmentDisposable _sourceSubscription; - - public IDisposable Run() - { - _gate = new object(); - _isStopped = false; - _group = new CompositeDisposable(); - - _sourceSubscription = new SingleAssignmentDisposable(); - _group.Add(_sourceSubscription); - _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); - - return _group; - } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var collection = default(IObservable); + private readonly ObservableSelector _parent; - try - { - collection = _parent._collectionSelector(value); - } - catch (Exception ex) + public _(ObservableSelector parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - lock (_gate) - { - base._observer.OnError(ex); - base.Dispose(); - } - return; + _parent = parent; } - var innerSubscription = new SingleAssignmentDisposable(); - _group.Add(innerSubscription); - innerSubscription.Disposable = collection.SubscribeSafe(new Iter(this, value, innerSubscription)); - } - - public void OnError(Exception error) - { - lock (_gate) - { - base._observer.OnError(error); - base.Dispose(); - } - } + private object _gate; + private bool _isStopped; + private CompositeDisposable _group; + private SingleAssignmentDisposable _sourceSubscription; - public void OnCompleted() - { - _isStopped = true; - if (_group.Count == 1) - { - // - // Notice there can be a race between OnCompleted of the source and any - // of the inner sequences, where both see _group.Count == 1, and one is - // waiting for the lock. There won't be a double OnCompleted observation - // though, because the call to Dispose silences the observer by swapping - // in a NopObserver. - // - lock (_gate) - { - base._observer.OnCompleted(); - base.Dispose(); - } - } - else + public IDisposable Run() { - _sourceSubscription.Dispose(); - } - } + _gate = new object(); + _isStopped = false; + _group = new CompositeDisposable(); - class Iter : IObserver - { - private readonly _ _parent; - private readonly TSource _value; - private readonly IDisposable _self; + _sourceSubscription = new SingleAssignmentDisposable(); + _group.Add(_sourceSubscription); + _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); - public Iter(_ parent, TSource value, IDisposable self) - { - _parent = parent; - _value = value; - _self = self; + return _group; } - public void OnNext(TCollection value) + public void OnNext(TSource value) { - var res = default(TResult); + var collection = default(IObservable); try { - res = _parent._parent._resultSelector(_value, value); + collection = _parent._collectionSelector(value); } catch (Exception ex) { - lock (_parent._gate) + lock (_gate) { - _parent._observer.OnError(ex); - _parent.Dispose(); + base._observer.OnError(ex); + base.Dispose(); } return; } - lock (_parent._gate) - _parent._observer.OnNext(res); + var innerSubscription = new SingleAssignmentDisposable(); + _group.Add(innerSubscription); + innerSubscription.Disposable = collection.SubscribeSafe(new InnerObserver(this, value, innerSubscription)); } public void OnError(Exception error) { - lock (_parent._gate) + lock (_gate) { - _parent._observer.OnError(error); - _parent.Dispose(); + base._observer.OnError(error); + base.Dispose(); } } public void OnCompleted() { - _parent._group.Remove(_self); - if (_parent._isStopped && _parent._group.Count == 1) + _isStopped = true; + if (_group.Count == 1) { // // Notice there can be a race between OnCompleted of the source and any @@ -244,154 +103,171 @@ public void OnCompleted() // though, because the call to Dispose silences the observer by swapping // in a NopObserver. // - lock (_parent._gate) + lock (_gate) { - _parent._observer.OnCompleted(); - _parent.Dispose(); + base._observer.OnCompleted(); + base.Dispose(); } } + else + { + _sourceSubscription.Dispose(); + } } - } - } - - class IndexSelectorImpl : Sink, IObserver - { - private readonly SelectMany _parent; - public IndexSelectorImpl(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - } + private sealed class InnerObserver : IObserver + { + private readonly _ _parent; + private readonly TSource _value; + private readonly IDisposable _self; - private object _gate; - private bool _isStopped; - private CompositeDisposable _group; - private SingleAssignmentDisposable _sourceSubscription; - private int _index; + public InnerObserver(_ parent, TSource value, IDisposable self) + { + _parent = parent; + _value = value; + _self = self; + } - public IDisposable Run() - { - _gate = new object(); - _isStopped = false; - _group = new CompositeDisposable(); + public void OnNext(TCollection value) + { + var res = default(TResult); - _sourceSubscription = new SingleAssignmentDisposable(); - _group.Add(_sourceSubscription); - _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + try + { + res = _parent._parent._resultSelector(_value, value); + } + catch (Exception ex) + { + lock (_parent._gate) + { + _parent._observer.OnError(ex); + _parent.Dispose(); + } + return; + } - return _group; - } + lock (_parent._gate) + _parent._observer.OnNext(res); + } - public void OnNext(TSource value) - { - var index = checked(_index++); - var collection = default(IObservable); + public void OnError(Exception error) + { + lock (_parent._gate) + { + _parent._observer.OnError(error); + _parent.Dispose(); + } + } - try - { - collection = _parent._collectionSelectorI(value, index); - } - catch (Exception ex) - { - lock (_gate) + public void OnCompleted() { - base._observer.OnError(ex); - base.Dispose(); + _parent._group.Remove(_self); + if (_parent._isStopped && _parent._group.Count == 1) + { + // + // Notice there can be a race between OnCompleted of the source and any + // of the inner sequences, where both see _group.Count == 1, and one is + // waiting for the lock. There won't be a double OnCompleted observation + // though, because the call to Dispose silences the observer by swapping + // in a NopObserver. + // + lock (_parent._gate) + { + _parent._observer.OnCompleted(); + _parent.Dispose(); + } + } } - return; } - - var innerSubscription = new SingleAssignmentDisposable(); - _group.Add(innerSubscription); - innerSubscription.Disposable = collection.SubscribeSafe(new Iter(this, value, index, innerSubscription)); } + } + + internal sealed class ObservableSelectorIndexed : Producer + { + private readonly IObservable _source; + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; - public void OnError(Exception error) + public ObservableSelectorIndexed(IObservable source, Func> collectionSelector, Func resultSelector) { - lock (_gate) - { - base._observer.OnError(error); - base.Dispose(); - } + _source = source; + _collectionSelector = collectionSelector; + _resultSelector = resultSelector; } - public void OnCompleted() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _isStopped = true; - if (_group.Count == 1) - { - // - // Notice there can be a race between OnCompleted of the source and any - // of the inner sequences, where both see _group.Count == 1, and one is - // waiting for the lock. There won't be a double OnCompleted observation - // though, because the call to Dispose silences the observer by swapping - // in a NopObserver. - // - lock (_gate) - { - base._observer.OnCompleted(); - base.Dispose(); - } - } - else - { - _sourceSubscription.Dispose(); - } + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); } - class Iter : IObserver + private sealed class _ : Sink, IObserver { - private readonly IndexSelectorImpl _parent; - private readonly TSource _value; - private readonly int _valueIndex; - private readonly IDisposable _self; + private readonly ObservableSelectorIndexed _parent; - public Iter(IndexSelectorImpl parent, TSource value, int index, IDisposable self) + public _(ObservableSelectorIndexed parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { _parent = parent; - _value = value; - _valueIndex = index; - _self = self; } + private object _gate; + private bool _isStopped; + private CompositeDisposable _group; + private SingleAssignmentDisposable _sourceSubscription; private int _index; - public void OnNext(TCollection value) + public IDisposable Run() { - var res = default(TResult); + _gate = new object(); + _isStopped = false; + _group = new CompositeDisposable(); + + _sourceSubscription = new SingleAssignmentDisposable(); + _group.Add(_sourceSubscription); + _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + + return _group; + } + + public void OnNext(TSource value) + { + var index = checked(_index++); + var collection = default(IObservable); try { - res = _parent._parent._resultSelectorI(_value, _valueIndex, value, checked(_index++)); + collection = _parent._collectionSelector(value, index); } catch (Exception ex) { - lock (_parent._gate) + lock (_gate) { - _parent._observer.OnError(ex); - _parent.Dispose(); + base._observer.OnError(ex); + base.Dispose(); } return; } - lock (_parent._gate) - _parent._observer.OnNext(res); + var innerSubscription = new SingleAssignmentDisposable(); + _group.Add(innerSubscription); + innerSubscription.Disposable = collection.SubscribeSafe(new InnerObserver(this, value, index, innerSubscription)); } public void OnError(Exception error) { - lock (_parent._gate) + lock (_gate) { - _parent._observer.OnError(error); - _parent.Dispose(); + base._observer.OnError(error); + base.Dispose(); } } public void OnCompleted() { - _parent._group.Remove(_self); - if (_parent._isStopped && _parent._group.Count == 1) + _isStopped = true; + if (_group.Count == 1) { // // Notice there can be a race between OnCompleted of the source and any @@ -400,617 +276,506 @@ public void OnCompleted() // though, because the call to Dispose silences the observer by swapping // in a NopObserver. // - lock (_parent._gate) + lock (_gate) { - _parent._observer.OnCompleted(); - _parent.Dispose(); + base._observer.OnCompleted(); + base.Dispose(); } } + else + { + _sourceSubscription.Dispose(); + } } - } - } - - class NoSelectorImpl : Sink, IObserver - { - private readonly SelectMany _parent; - - public NoSelectorImpl(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - } - public void OnNext(TSource value) - { - var xs = default(IEnumerable); - try - { - xs = _parent._collectionSelectorE(value); - } - catch (Exception exception) + private sealed class InnerObserver : IObserver { - base._observer.OnError(exception); - base.Dispose(); - return; - } + private readonly _ _parent; + private readonly TSource _value; + private readonly int _valueIndex; + private readonly IDisposable _self; - var e = default(IEnumerator); - try - { - e = xs.GetEnumerator(); - } - catch (Exception exception) - { - base._observer.OnError(exception); - base.Dispose(); - return; - } + public InnerObserver(_ parent, TSource value, int index, IDisposable self) + { + _parent = parent; + _value = value; + _valueIndex = index; + _self = self; + } - try - { - var hasNext = true; - while (hasNext) + private int _index; + + public void OnNext(TCollection value) { - hasNext = false; - var current = default(TResult); + var res = default(TResult); try { - hasNext = e.MoveNext(); - if (hasNext) - current = _parent._resultSelector(value, e.Current); + res = _parent._parent._resultSelector(_value, _valueIndex, value, checked(_index++)); } - catch (Exception exception) + catch (Exception ex) { - base._observer.OnError(exception); - base.Dispose(); + lock (_parent._gate) + { + _parent._observer.OnError(ex); + _parent.Dispose(); + } return; } - if (hasNext) - base._observer.OnNext(current); + lock (_parent._gate) + _parent._observer.OnNext(res); } - } - finally - { - if (e != null) - e.Dispose(); - } - } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + public void OnError(Exception error) + { + lock (_parent._gate) + { + _parent._observer.OnError(error); + _parent.Dispose(); + } + } - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + _parent._group.Remove(_self); + if (_parent._isStopped && _parent._group.Count == 1) + { + // + // Notice there can be a race between OnCompleted of the source and any + // of the inner sequences, where both see _group.Count == 1, and one is + // waiting for the lock. There won't be a double OnCompleted observation + // though, because the call to Dispose silences the observer by swapping + // in a NopObserver. + // + lock (_parent._gate) + { + _parent._observer.OnCompleted(); + _parent.Dispose(); + } + } + } + } } } - class Omega : Sink, IObserver + internal sealed class EnumerableSelector : Producer { - private readonly SelectMany _parent; + private readonly IObservable _source; + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; - public Omega(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public EnumerableSelector(IObservable source, Func> collectionSelector, Func resultSelector) { - _parent = parent; + _source = source; + _collectionSelector = collectionSelector; + _resultSelector = resultSelector; } - private int _index; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var index = checked(_index++); + private readonly EnumerableSelector _parent; - var xs = default(IEnumerable); - try - { - xs = _parent._collectionSelectorEI(value, index); - } - catch (Exception exception) + public _(EnumerableSelector parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnError(exception); - base.Dispose(); - return; + _parent = parent; } - var e = default(IEnumerator); - try - { - e = xs.GetEnumerator(); - } - catch (Exception exception) + public void OnNext(TSource value) { - base._observer.OnError(exception); - base.Dispose(); - return; - } + var xs = default(IEnumerable); + try + { + xs = _parent._collectionSelector(value); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } - try - { - var eIndex = 0; - var hasNext = true; - while (hasNext) + var e = default(IEnumerator); + try + { + e = xs.GetEnumerator(); + } + catch (Exception exception) { - hasNext = false; - var current = default(TResult); + base._observer.OnError(exception); + base.Dispose(); + return; + } - try + try + { + var hasNext = true; + while (hasNext) { - hasNext = e.MoveNext(); + hasNext = false; + var current = default(TResult); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + current = _parent._resultSelector(value, e.Current); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + if (hasNext) - current = _parent._resultSelectorI(value, index, e.Current, checked(eIndex++)); + base._observer.OnNext(current); } - catch (Exception exception) - { - base._observer.OnError(exception); - base.Dispose(); - return; - } - - if (hasNext) - base._observer.OnNext(current); + } + finally + { + if (e != null) + e.Dispose(); } } - finally + + public void OnError(Exception error) { - if (e != null) - e.Dispose(); + base._observer.OnError(error); + base.Dispose(); } - } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } - - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + base._observer.OnCompleted(); + base.Dispose(); + } } } - class SelectManyImpl : Sink, IObserver + internal sealed class EnumerableSelectorIndexed : Producer { - private readonly SelectMany _parent; + private readonly IObservable _source; + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; - public SelectManyImpl(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public EnumerableSelectorIndexed(IObservable source, Func> collectionSelector, Func resultSelector) { - _parent = parent; + _source = source; + _collectionSelector = collectionSelector; + _resultSelector = resultSelector; } - private object _gate; - private CancellationDisposable _cancel; - private volatile int _count; - - public IDisposable Run() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _gate = new object(); - _cancel = new CancellationDisposable(); - _count = 1; - - return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + var sink = new _(this, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var task = default(Task); - try + private readonly EnumerableSelectorIndexed _parent; + + public _(EnumerableSelectorIndexed parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - Interlocked.Increment(ref _count); - task = _parent._collectionSelectorT(value, _cancel.Token); + _parent = parent; } - catch (Exception ex) + + private int _index; + + public void OnNext(TSource value) { - lock (_gate) + var index = checked(_index++); + + var xs = default(IEnumerable); + try + { + xs = _parent._collectionSelector(value, index); + } + catch (Exception exception) { - base._observer.OnError(ex); + base._observer.OnError(exception); base.Dispose(); + return; } - return; - } - - if (task.IsCompleted) - { - OnCompletedTask(value, task); - } - else - { - AttachContinuation(value, task); - } - } - - private void AttachContinuation(TSource value, Task task) - { - // - // Separate method to avoid closure in synchronous completion case. - // - task.ContinueWith(t => OnCompletedTask(value, t)); - } + var e = default(IEnumerator); + try + { + e = xs.GetEnumerator(); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } - private void OnCompletedTask(TSource value, Task task) - { - switch (task.Status) - { - case TaskStatus.RanToCompletion: + try + { + var eIndex = 0; + var hasNext = true; + while (hasNext) { - var res = default(TResult); + hasNext = false; + var current = default(TResult); + try { - res = _parent._resultSelector(value, task.Result); + hasNext = e.MoveNext(); + if (hasNext) + current = _parent._resultSelector(value, index, e.Current, checked(eIndex++)); } - catch (Exception ex) + catch (Exception exception) { - lock (_gate) - { - base._observer.OnError(ex); - base.Dispose(); - } - + base._observer.OnError(exception); + base.Dispose(); return; } - lock (_gate) - base._observer.OnNext(res); - - OnCompleted(); - } - break; - case TaskStatus.Faulted: - { - lock (_gate) - { - base._observer.OnError(task.Exception.InnerException); - base.Dispose(); - } - } - break; - case TaskStatus.Canceled: - { - if (!_cancel.IsDisposed) - { - lock (_gate) - { - base._observer.OnError(new TaskCanceledException(task)); - base.Dispose(); - } - } + if (hasNext) + base._observer.OnNext(current); } - break; + } + finally + { + if (e != null) + e.Dispose(); + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { base._observer.OnError(error); base.Dispose(); } - } - public void OnCompleted() - { - if (Interlocked.Decrement(ref _count) == 0) + public void OnCompleted() { - lock (_gate) - { - base._observer.OnCompleted(); - base.Dispose(); - } + base._observer.OnCompleted(); + base.Dispose(); } } } - class Sigma : Sink, IObserver + internal sealed class TaskSelector : Producer { - private readonly SelectMany _parent; + private readonly IObservable _source; + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; - public Sigma(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public TaskSelector(IObservable source, Func> collectionSelector, Func resultSelector) { - _parent = parent; + _source = source; + _collectionSelector = collectionSelector; + _resultSelector = resultSelector; } - private object _gate; - private CancellationDisposable _cancel; - private volatile int _count; - private int _index; - - public IDisposable Run() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _gate = new object(); - _cancel = new CancellationDisposable(); - _count = 1; - - return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var index = checked(_index++); + private readonly TaskSelector _parent; - var task = default(Task); - try + public _(TaskSelector parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - Interlocked.Increment(ref _count); - task = _parent._collectionSelectorTI(value, index, _cancel.Token); + _parent = parent; } - catch (Exception ex) + + private object _gate; + private CancellationDisposable _cancel; + private volatile int _count; + + public IDisposable Run() { - lock (_gate) - { - base._observer.OnError(ex); - base.Dispose(); - } + _gate = new object(); + _cancel = new CancellationDisposable(); + _count = 1; - return; + return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); } - if (task.IsCompleted) + public void OnNext(TSource value) { - OnCompletedTask(value, index, task); + var task = default(Task); + try + { + Interlocked.Increment(ref _count); + task = _parent._collectionSelector(value, _cancel.Token); + } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } + + return; + } + + if (task.IsCompleted) + { + OnCompletedTask(value, task); + } + else + { + AttachContinuation(value, task); + } } - else + + private void AttachContinuation(TSource value, Task task) { - AttachContinuation(value, index, task); + // + // Separate method to avoid closure in synchronous completion case. + // + task.ContinueWith(t => OnCompletedTask(value, t)); } - } - - private void AttachContinuation(TSource value, int index, Task task) - { - // - // Separate method to avoid closure in synchronous completion case. - // - task.ContinueWith(t => OnCompletedTask(value, index, t)); - } - private void OnCompletedTask(TSource value, int index, Task task) - { - switch (task.Status) + private void OnCompletedTask(TSource value, Task task) { - case TaskStatus.RanToCompletion: - { - var res = default(TResult); - try - { - res = _parent._resultSelectorTI(value, index, task.Result); - } - catch (Exception ex) + switch (task.Status) + { + case TaskStatus.RanToCompletion: { - lock (_gate) + var res = default(TResult); + try { - base._observer.OnError(ex); - base.Dispose(); + res = _parent._resultSelector(value, task.Result); } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } - return; - } + return; + } - lock (_gate) - base._observer.OnNext(res); + lock (_gate) + base._observer.OnNext(res); - OnCompleted(); - } - break; - case TaskStatus.Faulted: - { - lock (_gate) - { - base._observer.OnError(task.Exception.InnerException); - base.Dispose(); + OnCompleted(); } - } - break; - case TaskStatus.Canceled: - { - if (!_cancel.IsDisposed) + break; + case TaskStatus.Faulted: { lock (_gate) { - base._observer.OnError(new TaskCanceledException(task)); + base._observer.OnError(task.Exception.InnerException); base.Dispose(); } } - } - break; + break; + case TaskStatus.Canceled: + { + if (!_cancel.IsDisposed) + { + lock (_gate) + { + base._observer.OnError(new TaskCanceledException(task)); + base.Dispose(); + } + } + } + break; + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { - base._observer.OnError(error); - base.Dispose(); + lock (_gate) + { + base._observer.OnError(error); + base.Dispose(); + } } - } - public void OnCompleted() - { - if (Interlocked.Decrement(ref _count) == 0) + public void OnCompleted() { - lock (_gate) + if (Interlocked.Decrement(ref _count) == 0) { - base._observer.OnCompleted(); - base.Dispose(); + lock (_gate) + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } } - } - - internal sealed class SelectMany : Producer - { - private readonly IObservable _source; - private readonly Func> _selector; - private readonly Func> _selectorI; - private readonly Func> _selectorOnError; - private readonly Func> _selectorOnCompleted; - private readonly Func> _selectorE; - private readonly Func> _selectorEI; - private readonly Func> _selectorT; - private readonly Func> _selectorTI; - - public SelectMany(IObservable source, Func> selector) - { - _source = source; - _selector = selector; - } - - public SelectMany(IObservable source, Func> selector) - { - _source = source; - _selectorI = selector; - } - - public SelectMany(IObservable source, Func> selector, Func> selectorOnError, Func> selectorOnCompleted) - { - _source = source; - _selector = selector; - _selectorOnError = selectorOnError; - _selectorOnCompleted = selectorOnCompleted; - } - - public SelectMany(IObservable source, Func> selector, Func> selectorOnError, Func> selectorOnCompleted) - { - _source = source; - _selectorI = selector; - _selectorOnError = selectorOnError; - _selectorOnCompleted = selectorOnCompleted; - } - public SelectMany(IObservable source, Func> selector) + internal sealed class TaskSelectorIndexed : Producer { - _source = source; - _selectorE = selector; - } - - public SelectMany(IObservable source, Func> selector) - { - _source = source; - _selectorEI = selector; - } - - public SelectMany(IObservable source, Func> selector) - { - _source = source; - _selectorT = selector; - } - - public SelectMany(IObservable source, Func> selector) - { - _source = source; - _selectorTI = selector; - } + private readonly IObservable _source; + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_selector != null) - { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - else if (_selectorI != null) + public TaskSelectorIndexed(IObservable source, Func> collectionSelector, Func resultSelector) { - var sink = new IndexSelectorImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - else if (_selectorT != null) - { - var sink = new SelectManyImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _collectionSelector = collectionSelector; + _resultSelector = resultSelector; } - else if (_selectorTI != null) + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new Sigma(this, observer, cancel); + var sink = new _(this, observer, cancel); setSink(sink); return sink.Run(); } - else if (_selectorE != null) - { - var sink = new NoSelectorImpl(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); - } - else - { - var sink = new Omega(this, observer, cancel); - setSink(sink); - return _source.SubscribeSafe(sink); - } - } - - class _ : Sink, IObserver - { - private readonly SelectMany _parent; - - public _(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - } - - private object _gate; - private bool _isStopped; - private CompositeDisposable _group; - private SingleAssignmentDisposable _sourceSubscription; - - public IDisposable Run() - { - _gate = new object(); - _isStopped = false; - _group = new CompositeDisposable(); - - _sourceSubscription = new SingleAssignmentDisposable(); - _group.Add(_sourceSubscription); - _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); - - return _group; - } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var inner = default(IObservable); + private readonly TaskSelectorIndexed _parent; - try + public _(TaskSelectorIndexed parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - inner = _parent._selector(value); + _parent = parent; } - catch (Exception ex) + + private object _gate; + private CancellationDisposable _cancel; + private volatile int _count; + private int _index; + + public IDisposable Run() { - lock (_gate) - { - base._observer.OnError(ex); - base.Dispose(); - } - return; - } + _gate = new object(); + _cancel = new CancellationDisposable(); + _count = 1; - SubscribeInner(inner); - } + return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + } - public void OnError(Exception error) - { - if (_parent._selectorOnError != null) + public void OnNext(TSource value) { - var inner = default(IObservable); + var index = checked(_index++); + var task = default(Task); try { - inner = _parent._selectorOnError(error); + Interlocked.Increment(ref _count); + task = _parent._collectionSelector(value, index, _cancel.Token); } catch (Exception ex) { @@ -1019,187 +784,169 @@ public void OnError(Exception error) base._observer.OnError(ex); base.Dispose(); } + return; } - SubscribeInner(inner); - - Final(); - } - else - { - lock (_gate) + if (task.IsCompleted) { - base._observer.OnError(error); - base.Dispose(); - } - } - } - - public void OnCompleted() - { - if (_parent._selectorOnCompleted != null) - { - var inner = default(IObservable); - - try - { - inner = _parent._selectorOnCompleted(); + OnCompletedTask(value, index, task); } - catch (Exception ex) + else { - lock (_gate) - { - base._observer.OnError(ex); - base.Dispose(); - } - return; + AttachContinuation(value, index, task); } - - SubscribeInner(inner); } - Final(); - } - - private void Final() - { - _isStopped = true; - if (_group.Count == 1) + private void AttachContinuation(TSource value, int index, Task task) { // - // Notice there can be a race between OnCompleted of the source and any - // of the inner sequences, where both see _group.Count == 1, and one is - // waiting for the lock. There won't be a double OnCompleted observation - // though, because the call to Dispose silences the observer by swapping - // in a NopObserver. + // Separate method to avoid closure in synchronous completion case. // - lock (_gate) - { - base._observer.OnCompleted(); - base.Dispose(); - } + task.ContinueWith(t => OnCompletedTask(value, index, t)); } - else - { - _sourceSubscription.Dispose(); - } - } - private void SubscribeInner(IObservable inner) - { - var innerSubscription = new SingleAssignmentDisposable(); - _group.Add(innerSubscription); - innerSubscription.Disposable = inner.SubscribeSafe(new Iter(this, innerSubscription)); - } + private void OnCompletedTask(TSource value, int index, Task task) + { + switch (task.Status) + { + case TaskStatus.RanToCompletion: + { + var res = default(TResult); + try + { + res = _parent._resultSelector(value, index, task.Result); + } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } - class Iter : IObserver - { - private readonly _ _parent; - private readonly IDisposable _self; + return; + } - public Iter(_ parent, IDisposable self) - { - _parent = parent; - _self = self; - } + lock (_gate) + base._observer.OnNext(res); - public void OnNext(TResult value) - { - lock (_parent._gate) - _parent._observer.OnNext(value); + OnCompleted(); + } + break; + case TaskStatus.Faulted: + { + lock (_gate) + { + base._observer.OnError(task.Exception.InnerException); + base.Dispose(); + } + } + break; + case TaskStatus.Canceled: + { + if (!_cancel.IsDisposed) + { + lock (_gate) + { + base._observer.OnError(new TaskCanceledException(task)); + base.Dispose(); + } + } + } + break; + } } public void OnError(Exception error) { - lock (_parent._gate) + lock (_gate) { - _parent._observer.OnError(error); - _parent.Dispose(); + base._observer.OnError(error); + base.Dispose(); } } public void OnCompleted() { - _parent._group.Remove(_self); - if (_parent._isStopped && _parent._group.Count == 1) + if (Interlocked.Decrement(ref _count) == 0) { - // - // Notice there can be a race between OnCompleted of the source and any - // of the inner sequences, where both see _group.Count == 1, and one is - // waiting for the lock. There won't be a double OnCompleted observation - // though, because the call to Dispose silences the observer by swapping - // in a NopObserver. - // - lock (_parent._gate) + lock (_gate) { - _parent._observer.OnCompleted(); - _parent.Dispose(); + base._observer.OnCompleted(); + base.Dispose(); } } } } } + } - class IndexSelectorImpl : Sink, IObserver + internal static class SelectMany + { + internal sealed class ObservableSelector : Producer { - private readonly SelectMany _parent; + private readonly IObservable _source; + private readonly Func> _selector; + private readonly Func> _selectorOnError; + private readonly Func> _selectorOnCompleted; - public IndexSelectorImpl(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public ObservableSelector(IObservable source, Func> selector) { - _parent = parent; + _source = source; + _selector = selector; } - private object _gate; - private bool _isStopped; - private CompositeDisposable _group; - private SingleAssignmentDisposable _sourceSubscription; - private int _index; - - public IDisposable Run() + public ObservableSelector(IObservable source, Func> selector, Func> selectorOnError, Func> selectorOnCompleted) { - _gate = new object(); - _isStopped = false; - _group = new CompositeDisposable(); - - _sourceSubscription = new SingleAssignmentDisposable(); - _group.Add(_sourceSubscription); - _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + _source = source; + _selector = selector; + _selectorOnError = selectorOnError; + _selectorOnCompleted = selectorOnCompleted; + } - return _group; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var inner = default(IObservable); + private readonly ObservableSelector _parent; - try + public _(ObservableSelector parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - inner = _parent._selectorI(value, checked(_index++)); + _parent = parent; } - catch (Exception ex) + + private object _gate; + private bool _isStopped; + private CompositeDisposable _group; + private SingleAssignmentDisposable _sourceSubscription; + + public IDisposable Run() { - lock (_gate) - { - base._observer.OnError(ex); - base.Dispose(); - } - return; - } + _gate = new object(); + _isStopped = false; + _group = new CompositeDisposable(); - SubscribeInner(inner); - } + _sourceSubscription = new SingleAssignmentDisposable(); + _group.Add(_sourceSubscription); + _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); - public void OnError(Exception error) - { - if (_parent._selectorOnError != null) + return _group; + } + + public void OnNext(TSource value) { var inner = default(IObservable); try { - inner = _parent._selectorOnError(error); + inner = _parent._selector(value); } catch (Exception ex) { @@ -1212,106 +959,72 @@ public void OnError(Exception error) } SubscribeInner(inner); - - Final(); } - else + + public void OnError(Exception error) { - lock (_gate) + if (_parent._selectorOnError != null) { - base._observer.OnError(error); - base.Dispose(); - } - } - } + var inner = default(IObservable); - public void OnCompleted() - { - if (_parent._selectorOnCompleted != null) - { - var inner = default(IObservable); + try + { + inner = _parent._selectorOnError(error); + } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } + return; + } - try - { - inner = _parent._selectorOnCompleted(); + SubscribeInner(inner); + + Final(); } - catch (Exception ex) + else { lock (_gate) { - base._observer.OnError(ex); + base._observer.OnError(error); base.Dispose(); } - return; } - - SubscribeInner(inner); } - Final(); - } - - private void Final() - { - _isStopped = true; - if (_group.Count == 1) + public void OnCompleted() { - // - // Notice there can be a race between OnCompleted of the source and any - // of the inner sequences, where both see _group.Count == 1, and one is - // waiting for the lock. There won't be a double OnCompleted observation - // though, because the call to Dispose silences the observer by swapping - // in a NopObserver. - // - lock (_gate) + if (_parent._selectorOnCompleted != null) { - base._observer.OnCompleted(); - base.Dispose(); - } - } - else - { - _sourceSubscription.Dispose(); - } - } - - private void SubscribeInner(IObservable inner) - { - var innerSubscription = new SingleAssignmentDisposable(); - _group.Add(innerSubscription); - innerSubscription.Disposable = inner.SubscribeSafe(new Iter(this, innerSubscription)); - } - - class Iter : IObserver - { - private readonly IndexSelectorImpl _parent; - private readonly IDisposable _self; - - public Iter(IndexSelectorImpl parent, IDisposable self) - { - _parent = parent; - _self = self; - } + var inner = default(IObservable); - public void OnNext(TResult value) - { - lock (_parent._gate) - _parent._observer.OnNext(value); - } + try + { + inner = _parent._selectorOnCompleted(); + } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } + return; + } - public void OnError(Exception error) - { - lock (_parent._gate) - { - _parent._observer.OnError(error); - _parent.Dispose(); + SubscribeInner(inner); } + + Final(); } - public void OnCompleted() + private void Final() { - _parent._group.Remove(_self); - if (_parent._isStopped && _parent._group.Count == 1) + _isStopped = true; + if (_group.Count == 1) { // // Notice there can be a race between OnCompleted of the source and any @@ -1320,396 +1033,748 @@ public void OnCompleted() // though, because the call to Dispose silences the observer by swapping // in a NopObserver. // - lock (_parent._gate) + lock (_gate) { - _parent._observer.OnCompleted(); - _parent.Dispose(); + base._observer.OnCompleted(); + base.Dispose(); } } + else + { + _sourceSubscription.Dispose(); + } } - } - } - - class NoSelectorImpl : Sink, IObserver - { - private readonly SelectMany _parent; - - public NoSelectorImpl(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - } - public void OnNext(TSource value) - { - var xs = default(IEnumerable); - try - { - xs = _parent._selectorE(value); - } - catch (Exception exception) + private void SubscribeInner(IObservable inner) { - base._observer.OnError(exception); - base.Dispose(); - return; + var innerSubscription = new SingleAssignmentDisposable(); + _group.Add(innerSubscription); + innerSubscription.Disposable = inner.SubscribeSafe(new InnerObserver(this, innerSubscription)); } - var e = default(IEnumerator); - try - { - e = xs.GetEnumerator(); - } - catch (Exception exception) + private sealed class InnerObserver : IObserver { - base._observer.OnError(exception); - base.Dispose(); - return; - } + private readonly _ _parent; + private readonly IDisposable _self; - try - { - var hasNext = true; - while (hasNext) + public InnerObserver(_ parent, IDisposable self) { - hasNext = false; - var current = default(TResult); + _parent = parent; + _self = self; + } - try + public void OnNext(TResult value) + { + lock (_parent._gate) + _parent._observer.OnNext(value); + } + + public void OnError(Exception error) + { + lock (_parent._gate) { - hasNext = e.MoveNext(); - if (hasNext) - current = e.Current; + _parent._observer.OnError(error); + _parent.Dispose(); } - catch (Exception exception) + } + + public void OnCompleted() + { + _parent._group.Remove(_self); + if (_parent._isStopped && _parent._group.Count == 1) { - base._observer.OnError(exception); - base.Dispose(); - return; + // + // Notice there can be a race between OnCompleted of the source and any + // of the inner sequences, where both see _group.Count == 1, and one is + // waiting for the lock. There won't be a double OnCompleted observation + // though, because the call to Dispose silences the observer by swapping + // in a NopObserver. + // + lock (_parent._gate) + { + _parent._observer.OnCompleted(); + _parent.Dispose(); + } } - - if (hasNext) - base._observer.OnNext(current); } } - finally - { - if (e != null) - e.Dispose(); - } } + } + + internal sealed class ObservableSelectorIndexed : Producer + { + private readonly IObservable _source; + private readonly Func> _selector; + private readonly Func> _selectorOnError; + private readonly Func> _selectorOnCompleted; - public void OnError(Exception error) + public ObservableSelectorIndexed(IObservable source, Func> selector) { - base._observer.OnError(error); - base.Dispose(); + _source = source; + _selector = selector; } - public void OnCompleted() + public ObservableSelectorIndexed(IObservable source, Func> selector, Func> selectorOnError, Func> selectorOnCompleted) { - base._observer.OnCompleted(); - base.Dispose(); + _source = source; + _selector = selector; + _selectorOnError = selectorOnError; + _selectorOnCompleted = selectorOnCompleted; } - } - - class Omega : Sink, IObserver - { - private readonly SelectMany _parent; - public Omega(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _parent = parent; + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); } - - private int _index; - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var xs = default(IEnumerable); - try - { - xs = _parent._selectorEI(value, checked(_index++)); - } - catch (Exception exception) + private readonly ObservableSelectorIndexed _parent; + + public _(ObservableSelectorIndexed parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnError(exception); - base.Dispose(); - return; + _parent = parent; } - var e = default(IEnumerator); - try + private object _gate; + private bool _isStopped; + private CompositeDisposable _group; + private SingleAssignmentDisposable _sourceSubscription; + private int _index; + + public IDisposable Run() { - e = xs.GetEnumerator(); + _gate = new object(); + _isStopped = false; + _group = new CompositeDisposable(); + + _sourceSubscription = new SingleAssignmentDisposable(); + _group.Add(_sourceSubscription); + _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + + return _group; } - catch (Exception exception) + + public void OnNext(TSource value) { - base._observer.OnError(exception); - base.Dispose(); - return; + var inner = default(IObservable); + + try + { + inner = _parent._selector(value, checked(_index++)); + } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } + return; + } + + SubscribeInner(inner); } - try + public void OnError(Exception error) { - var hasNext = true; - while (hasNext) + if (_parent._selectorOnError != null) { - hasNext = false; - var current = default(TResult); + var inner = default(IObservable); try { - hasNext = e.MoveNext(); - if (hasNext) - current = e.Current; + inner = _parent._selectorOnError(error); } - catch (Exception exception) + catch (Exception ex) { - base._observer.OnError(exception); - base.Dispose(); + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } return; } - if (hasNext) - base._observer.OnNext(current); + SubscribeInner(inner); + + Final(); + } + else + { + lock (_gate) + { + base._observer.OnError(error); + base.Dispose(); + } } } - finally + + public void OnCompleted() { - if (e != null) - e.Dispose(); + if (_parent._selectorOnCompleted != null) + { + var inner = default(IObservable); + + try + { + inner = _parent._selectorOnCompleted(); + } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } + return; + } + + SubscribeInner(inner); + } + + Final(); } - } - public void OnError(Exception error) - { - base._observer.OnError(error); - base.Dispose(); - } + private void Final() + { + _isStopped = true; + if (_group.Count == 1) + { + // + // Notice there can be a race between OnCompleted of the source and any + // of the inner sequences, where both see _group.Count == 1, and one is + // waiting for the lock. There won't be a double OnCompleted observation + // though, because the call to Dispose silences the observer by swapping + // in a NopObserver. + // + lock (_gate) + { + base._observer.OnCompleted(); + base.Dispose(); + } + } + else + { + _sourceSubscription.Dispose(); + } + } - public void OnCompleted() - { - base._observer.OnCompleted(); - base.Dispose(); + private void SubscribeInner(IObservable inner) + { + var innerSubscription = new SingleAssignmentDisposable(); + _group.Add(innerSubscription); + innerSubscription.Disposable = inner.SubscribeSafe(new InnerObserver(this, innerSubscription)); + } + + private sealed class InnerObserver : IObserver + { + private readonly _ _parent; + private readonly IDisposable _self; + + public InnerObserver(_ parent, IDisposable self) + { + _parent = parent; + _self = self; + } + + public void OnNext(TResult value) + { + lock (_parent._gate) + _parent._observer.OnNext(value); + } + + public void OnError(Exception error) + { + lock (_parent._gate) + { + _parent._observer.OnError(error); + _parent.Dispose(); + } + } + + public void OnCompleted() + { + _parent._group.Remove(_self); + if (_parent._isStopped && _parent._group.Count == 1) + { + // + // Notice there can be a race between OnCompleted of the source and any + // of the inner sequences, where both see _group.Count == 1, and one is + // waiting for the lock. There won't be a double OnCompleted observation + // though, because the call to Dispose silences the observer by swapping + // in a NopObserver. + // + lock (_parent._gate) + { + _parent._observer.OnCompleted(); + _parent.Dispose(); + } + } + } + } } } - class SelectManyImpl : Sink, IObserver + internal sealed class EnumerableSelector : Producer { - private readonly SelectMany _parent; + private readonly IObservable _source; + private readonly Func> _selector; - public SelectManyImpl(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public EnumerableSelector(IObservable source, Func> selector) { - _parent = parent; + _source = source; + _selector = selector; } - private object _gate; - private CancellationDisposable _cancel; - private volatile int _count; - - public IDisposable Run() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _gate = new object(); - _cancel = new CancellationDisposable(); - _count = 1; - - return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + var sink = new _(this, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var task = default(Task); - try + private readonly EnumerableSelector _parent; + + public _(EnumerableSelector parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - Interlocked.Increment(ref _count); - task = _parent._selectorT(value, _cancel.Token); + _parent = parent; } - catch (Exception ex) + + public void OnNext(TSource value) { - lock (_gate) + var xs = default(IEnumerable); + try + { + xs = _parent._selector(value); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + var e = default(IEnumerator); + try + { + e = xs.GetEnumerator(); + } + catch (Exception exception) { - base._observer.OnError(ex); + base._observer.OnError(exception); base.Dispose(); + return; } - return; + try + { + var hasNext = true; + while (hasNext) + { + hasNext = false; + var current = default(TResult); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + current = e.Current; + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + if (hasNext) + base._observer.OnNext(current); + } + } + finally + { + if (e != null) + e.Dispose(); + } } - if (task.IsCompleted) + public void OnError(Exception error) { - OnCompletedTask(task); + base._observer.OnError(error); + base.Dispose(); } - else + + public void OnCompleted() { - task.ContinueWith(OnCompletedTask); + base._observer.OnCompleted(); + base.Dispose(); } } + } + + internal sealed class EnumerableSelectorIndexed : Producer + { + private readonly IObservable _source; + private readonly Func> _selector; + + public EnumerableSelectorIndexed(IObservable source, Func> selector) + { + _source = source; + _selector = selector; + } - private void OnCompletedTask(Task task) + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - switch (task.Status) + var sink = new _(this, observer, cancel); + setSink(sink); + return _source.SubscribeSafe(sink); + } + + private sealed class _ : Sink, IObserver + { + private readonly EnumerableSelectorIndexed _parent; + + public _(EnumerableSelectorIndexed parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - case TaskStatus.RanToCompletion: - { - lock (_gate) - base._observer.OnNext(task.Result); + _parent = parent; + } - OnCompleted(); - } - break; - case TaskStatus.Faulted: + private int _index; + + public void OnNext(TSource value) + { + var xs = default(IEnumerable); + try + { + xs = _parent._selector(value, checked(_index++)); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + var e = default(IEnumerator); + try + { + e = xs.GetEnumerator(); + } + catch (Exception exception) + { + base._observer.OnError(exception); + base.Dispose(); + return; + } + + try + { + var hasNext = true; + while (hasNext) { - lock (_gate) + hasNext = false; + var current = default(TResult); + + try { - base._observer.OnError(task.Exception.InnerException); - base.Dispose(); + hasNext = e.MoveNext(); + if (hasNext) + current = e.Current; } - } - break; - case TaskStatus.Canceled: - { - if (!_cancel.IsDisposed) + catch (Exception exception) { - lock (_gate) - { - base._observer.OnError(new TaskCanceledException(task)); - base.Dispose(); - } + base._observer.OnError(exception); + base.Dispose(); + return; } + + if (hasNext) + base._observer.OnNext(current); } - break; + } + finally + { + if (e != null) + e.Dispose(); + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { base._observer.OnError(error); base.Dispose(); } - } - public void OnCompleted() - { - if (Interlocked.Decrement(ref _count) == 0) + public void OnCompleted() { - lock (_gate) - { - base._observer.OnCompleted(); - base.Dispose(); - } + base._observer.OnCompleted(); + base.Dispose(); } } } - class Sigma : Sink, IObserver + internal sealed class TaskSelector : Producer { - private readonly SelectMany _parent; + private readonly IObservable _source; + private readonly Func> _selector; - public Sigma(SelectMany parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public TaskSelector(IObservable source, Func> selector) { - _parent = parent; + _source = source; + _selector = selector; } - private object _gate; - private CancellationDisposable _cancel; - private volatile int _count; - private int _index; - - public IDisposable Run() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _gate = new object(); - _cancel = new CancellationDisposable(); - _count = 1; - - return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); } - public void OnNext(TSource value) + private sealed class _ : Sink, IObserver { - var task = default(Task); - try + private readonly TaskSelector _parent; + + public _(TaskSelector parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - Interlocked.Increment(ref _count); - task = _parent._selectorTI(value, checked(_index++), _cancel.Token); + _parent = parent; } - catch (Exception ex) + + private object _gate; + private CancellationDisposable _cancel; + private volatile int _count; + + public IDisposable Run() { - lock (_gate) + _gate = new object(); + _cancel = new CancellationDisposable(); + _count = 1; + + return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + } + + public void OnNext(TSource value) + { + var task = default(Task); + try { - base._observer.OnError(ex); - base.Dispose(); + Interlocked.Increment(ref _count); + task = _parent._selector(value, _cancel.Token); } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } - return; + return; + } + + if (task.IsCompleted) + { + OnCompletedTask(task); + } + else + { + task.ContinueWith(OnCompletedTask); + } } - if (task.IsCompleted) + private void OnCompletedTask(Task task) { - OnCompletedTask(task); + switch (task.Status) + { + case TaskStatus.RanToCompletion: + { + lock (_gate) + base._observer.OnNext(task.Result); + + OnCompleted(); + } + break; + case TaskStatus.Faulted: + { + lock (_gate) + { + base._observer.OnError(task.Exception.InnerException); + base.Dispose(); + } + } + break; + case TaskStatus.Canceled: + { + if (!_cancel.IsDisposed) + { + lock (_gate) + { + base._observer.OnError(new TaskCanceledException(task)); + base.Dispose(); + } + } + } + break; + } } - else + + public void OnError(Exception error) { - task.ContinueWith(OnCompletedTask); + lock (_gate) + { + base._observer.OnError(error); + base.Dispose(); + } } + + public void OnCompleted() + { + if (Interlocked.Decrement(ref _count) == 0) + { + lock (_gate) + { + base._observer.OnCompleted(); + base.Dispose(); + } + } + } + } + } + + internal sealed class TaskSelectorIndexed : Producer + { + private readonly IObservable _source; + private readonly Func> _selector; + + public TaskSelectorIndexed(IObservable source, Func> selector) + { + _source = source; + _selector = selector; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); } - private void OnCompletedTask(Task task) + private sealed class _ : Sink, IObserver { - switch (task.Status) + private readonly TaskSelectorIndexed _parent; + + public _(TaskSelectorIndexed parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - case TaskStatus.RanToCompletion: - { - lock (_gate) - base._observer.OnNext(task.Result); + _parent = parent; + } - OnCompleted(); - } - break; - case TaskStatus.Faulted: + private object _gate; + private CancellationDisposable _cancel; + private volatile int _count; + private int _index; + + public IDisposable Run() + { + _gate = new object(); + _cancel = new CancellationDisposable(); + _count = 1; + + return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + } + + public void OnNext(TSource value) + { + var task = default(Task); + try + { + Interlocked.Increment(ref _count); + task = _parent._selector(value, checked(_index++), _cancel.Token); + } + catch (Exception ex) + { + lock (_gate) { - lock (_gate) + base._observer.OnError(ex); + base.Dispose(); + } + + return; + } + + if (task.IsCompleted) + { + OnCompletedTask(task); + } + else + { + task.ContinueWith(OnCompletedTask); + } + } + + private void OnCompletedTask(Task task) + { + switch (task.Status) + { + case TaskStatus.RanToCompletion: { - base._observer.OnError(task.Exception.InnerException); - base.Dispose(); + lock (_gate) + base._observer.OnNext(task.Result); + + OnCompleted(); } - } - break; - case TaskStatus.Canceled: - { - if (!_cancel.IsDisposed) + break; + case TaskStatus.Faulted: { lock (_gate) { - base._observer.OnError(new TaskCanceledException(task)); + base._observer.OnError(task.Exception.InnerException); base.Dispose(); } } - } - break; + break; + case TaskStatus.Canceled: + { + if (!_cancel.IsDisposed) + { + lock (_gate) + { + base._observer.OnError(new TaskCanceledException(task)); + base.Dispose(); + } + } + } + break; + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { - base._observer.OnError(error); - base.Dispose(); + lock (_gate) + { + base._observer.OnError(error); + base.Dispose(); + } } - } - public void OnCompleted() - { - if (Interlocked.Decrement(ref _count) == 0) + public void OnCompleted() { - lock (_gate) + if (Interlocked.Decrement(ref _count) == 0) { - base._observer.OnCompleted(); - base.Dispose(); + lock (_gate) + { + base._observer.OnCompleted(); + base.Dispose(); + } } } } From e83e57f8490f85efb1ac4d479a8833ac84ea0bad Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:11:55 -0700 Subject: [PATCH 65/95] Optimizing layouts of SkipUntil. --- .../Linq/Observable/SkipUntil.cs | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipUntil.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipUntil.cs index 17b3ef9fa..f8063ce61 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipUntil.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipUntil.cs @@ -20,28 +20,25 @@ public SkipUntil(IObservable source, IObservable other) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink + private sealed class _ : Sink { - private readonly SkipUntil _parent; - - public _(SkipUntil parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - public IDisposable Run() + public IDisposable Run(SkipUntil parent) { - var sourceObserver = new T(this); - var otherObserver = new O(this, sourceObserver); + var sourceObserver = new SourceObserver(this); + var otherObserver = new OtherObserver(this, sourceObserver); - var sourceSubscription = _parent._source.SubscribeSafe(sourceObserver); - var otherSubscription = _parent._other.SubscribeSafe(otherObserver); + var sourceSubscription = parent._source.SubscribeSafe(sourceObserver); + var otherSubscription = parent._other.SubscribeSafe(otherObserver); sourceObserver.Disposable = sourceSubscription; otherObserver.Disposable = otherSubscription; @@ -52,13 +49,13 @@ public IDisposable Run() ); } - class T : IObserver + private sealed class SourceObserver : IObserver { private readonly _ _parent; public volatile IObserver _observer; private readonly SingleAssignmentDisposable _subscription; - public T(_ parent) + public SourceObserver(_ parent) { _parent = parent; _observer = NopObserver.Instance; @@ -88,13 +85,13 @@ public void OnCompleted() } } - class O : IObserver + private sealed class OtherObserver : IObserver { private readonly _ _parent; - private readonly T _sourceObserver; + private readonly SourceObserver _sourceObserver; private readonly SingleAssignmentDisposable _subscription; - public O(_ parent, T sourceObserver) + public OtherObserver(_ parent, SourceObserver sourceObserver) { _parent = parent; _sourceObserver = sourceObserver; @@ -158,26 +155,24 @@ public IObservable Combine(DateTimeOffset startTime) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly SkipUntil _parent; private volatile bool _open; - public _(SkipUntil parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - public IDisposable Run() + public IDisposable Run(SkipUntil parent) { - var t = _parent._scheduler.Schedule(_parent._startTime, Tick); - var d = _parent._source.SubscribeSafe(this); + var t = parent._scheduler.Schedule(parent._startTime, Tick); + var d = parent._source.SubscribeSafe(this); return StableCompositeDisposable.Create(t, d); } From d341459d3c78901028ebed5be979d110dadd39ed Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:14:25 -0700 Subject: [PATCH 66/95] Optimizing layouts of TakeUntil. --- .../Linq/Observable/TakeUntil.cs | 54 ++++++++----------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeUntil.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeUntil.cs index a19ca7acb..c46b7243e 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeUntil.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeUntil.cs @@ -20,31 +20,28 @@ public TakeUntil(IObservable source, IObservable other) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink + private sealed class _ : Sink { - private readonly TakeUntil _parent; - - public _(TakeUntil parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - public IDisposable Run() + public IDisposable Run(TakeUntil parent) { - var sourceObserver = new T(this); - var otherObserver = new O(this, sourceObserver); + var sourceObserver = new SourceObserver(this); + var otherObserver = new OtherObserver(this, sourceObserver); // COMPAT - Order of Subscribe calls per v1.0.10621 - var otherSubscription = _parent._other.SubscribeSafe(otherObserver); + var otherSubscription = parent._other.SubscribeSafe(otherObserver); otherObserver.Disposable = otherSubscription; - var sourceSubscription = _parent._source.SubscribeSafe(sourceObserver); + var sourceSubscription = parent._source.SubscribeSafe(sourceObserver); return StableCompositeDisposable.Create( otherSubscription, @@ -58,7 +55,7 @@ public IDisposable Run() * * Notice an approach where the "other" channel performs an Interlocked.Exchange operation on * the _parent._observer field to substitute it with a NopObserver doesn't work, - * because the "other" channel still need to send an OnCompleted message, which could happen + * because the "other" channel still needs to send an OnCompleted message, which could happen * concurrently with another message when the "source" channel has already read from the * _parent._observer field between making the On* call. * @@ -66,12 +63,12 @@ public IDisposable Run() * access to the outgoing observer while dispatching a message. Doing this more fine-grained * than using locks turns out to be tricky and doesn't reduce cost. */ - class T : IObserver + private sealed class SourceObserver : IObserver { private readonly _ _parent; public volatile bool _open; - public T(_ parent) + public SourceObserver(_ parent) { _parent = parent; _open = false; @@ -111,13 +108,13 @@ public void OnCompleted() } } - class O : IObserver + private sealed class OtherObserver : IObserver { private readonly _ _parent; - private readonly T _sourceObserver; + private readonly SourceObserver _sourceObserver; private readonly SingleAssignmentDisposable _subscription; - public O(_ parent, T sourceObserver) + public OtherObserver(_ parent, SourceObserver sourceObserver) { _parent = parent; _sourceObserver = sourceObserver; @@ -191,29 +188,24 @@ public IObservable Combine(DateTimeOffset endTime) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly TakeUntil _parent; + private readonly object _gate = new object(); - public _(TakeUntil parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } - private object _gate; - - public IDisposable Run() + public IDisposable Run(TakeUntil parent) { - _gate = new object(); - - var t = _parent._scheduler.Schedule(_parent._endTime, Tick); - var d = _parent._source.SubscribeSafe(this); + var t = parent._scheduler.Schedule(parent._endTime, Tick); + var d = parent._source.SubscribeSafe(this); return StableCompositeDisposable.Create(t, d); } From 6195a077b0460dbe071d86c487e0fca87759bbb0 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:20:12 -0700 Subject: [PATCH 67/95] Sealing sinks for Sum operators. --- .../System.Reactive/Linq/Observable/Sum.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Sum.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Sum.cs index 8a32ab1b4..c72198775 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Sum.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Sum.cs @@ -20,7 +20,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double _sum; @@ -66,7 +66,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double _sum; // This is what LINQ to Objects does! @@ -112,7 +112,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private decimal _sum; @@ -158,7 +158,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private int _sum; @@ -215,7 +215,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private long _sum; @@ -272,7 +272,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double _sum; @@ -319,7 +319,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cance return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private double _sum; // This is what LINQ to Objects does! @@ -366,7 +366,7 @@ protected override IDisposable Run(IObserver observer, IDisposable can return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private decimal _sum; @@ -413,7 +413,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private int _sum; @@ -471,7 +471,7 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private long _sum; From c495634396cb085d4ebd56c47fb322d8cdc164fc Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:21:52 -0700 Subject: [PATCH 68/95] Optimizing layout of Switch. --- .../System.Reactive/Linq/Observable/Switch.cs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Switch.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Switch.cs index 325792b19..ff3ebda5b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Switch.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Switch.cs @@ -17,19 +17,16 @@ public Switch(IObservable> sources) protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - var sink = new _(this, observer, cancel); + var sink = new _(observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink, IObserver> + private sealed class _ : Sink, IObserver> { - private readonly Switch _parent; - - public _(Switch parent, IObserver observer, IDisposable cancel) + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; } private object _gate; @@ -39,7 +36,7 @@ public _(Switch parent, IObserver observer, IDisposable cancel private ulong _latest; private bool _hasLatest; - public IDisposable Run() + public IDisposable Run(Switch parent) { _gate = new object(); _innerSubscription = new SerialDisposable(); @@ -49,7 +46,7 @@ public IDisposable Run() var subscription = new SingleAssignmentDisposable(); _subscription = subscription; - subscription.Disposable = _parent._sources.SubscribeSafe(this); + subscription.Disposable = parent._sources.SubscribeSafe(this); return StableCompositeDisposable.Create(_subscription, _innerSubscription); } @@ -65,7 +62,7 @@ public void OnNext(IObservable value) var d = new SingleAssignmentDisposable(); _innerSubscription.Disposable = d; - d.Disposable = value.SubscribeSafe(new Iter(this, id, d)); + d.Disposable = value.SubscribeSafe(new InnerObserver(this, id, d)); } public void OnError(Exception error) @@ -91,13 +88,13 @@ public void OnCompleted() } } - class Iter : IObserver + private sealed class InnerObserver : IObserver { private readonly _ _parent; private readonly ulong _id; private readonly IDisposable _self; - public Iter(_ parent, ulong id, IDisposable self) + public InnerObserver(_ parent, ulong id, IDisposable self) { _parent = parent; _id = id; @@ -109,7 +106,9 @@ public void OnNext(TSource value) lock (_parent._gate) { if (_parent._latest == _id) + { _parent._observer.OnNext(value); + } } } From 6ee70bb452fcb2d81f27906e4012d2dfb7c1247a Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:22:55 -0700 Subject: [PATCH 69/95] Marking lock field in Synchronize as readonly. --- .../Source/src/System.Reactive/Linq/Observable/Synchronize.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs index 5cfa50138..51de5811a 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Synchronize.cs @@ -29,7 +29,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - private object _gate; + private readonly object _gate; public _(object gate, IObserver observer, IDisposable cancel) : base(observer, cancel) From cee84504c78236cfa0f61ee376b9d2e152e045f0 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:23:45 -0700 Subject: [PATCH 70/95] Marking lock field in Switch as readonly. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/Switch.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Switch.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Switch.cs index ff3ebda5b..55c7b647f 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Switch.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Switch.cs @@ -24,12 +24,13 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver> { + private readonly object _gate = new object(); + public _(IObserver observer, IDisposable cancel) : base(observer, cancel) { } - private object _gate; private IDisposable _subscription; private SerialDisposable _innerSubscription; private bool _isStopped; @@ -38,7 +39,6 @@ public _(IObserver observer, IDisposable cancel) public IDisposable Run(Switch parent) { - _gate = new object(); _innerSubscription = new SerialDisposable(); _isStopped = false; _latest = 0UL; From 808738da3c38c3915c4c38e9d76abc7c802329c2 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:34:56 -0700 Subject: [PATCH 71/95] Adding some comments to TakeLast. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLast.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLast.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLast.cs index e5ad288b5..d4effeafa 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLast.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeLast.cs @@ -32,6 +32,8 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Count _parent; private Queue _queue; @@ -139,6 +141,8 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Time _parent; private Queue> _queue; From 9be16736f28e443d8075ef61ced79a5bd4008d2c Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:35:06 -0700 Subject: [PATCH 72/95] Fixing SelectMany operator instantiation. --- ...QueryLanguage.StandardSequenceOperators.cs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs index a27d6cddb..9f089ab81 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs @@ -230,22 +230,22 @@ public virtual IObservable SelectMany(IObservable SelectMany(IObservable source, Func> selector) { - return new SelectMany(source, (x, token) => selector(x)); + return new SelectMany.TaskSelector(source, (x, token) => selector(x)); } public virtual IObservable SelectMany(IObservable source, Func> selector) { - return new SelectMany(source, (x, i, token) => selector(x, i)); + return new SelectMany.TaskSelectorIndexed(source, (x, i, token) => selector(x, i)); } public virtual IObservable SelectMany(IObservable source, Func> selector) { - return new SelectMany(source, selector); + return new SelectMany.TaskSelector(source, selector); } public virtual IObservable SelectMany(IObservable source, Func> selector) { - return new SelectMany(source, selector); + return new SelectMany.TaskSelectorIndexed(source, selector); } public virtual IObservable SelectMany(IObservable source, Func> collectionSelector, Func resultSelector) @@ -260,62 +260,62 @@ public virtual IObservable SelectMany(IO public virtual IObservable SelectMany(IObservable source, Func> taskSelector, Func resultSelector) { - return new SelectMany(source, (x, token) => taskSelector(x), resultSelector); + return new SelectMany.TaskSelector(source, (x, token) => taskSelector(x), resultSelector); } public virtual IObservable SelectMany(IObservable source, Func> taskSelector, Func resultSelector) { - return new SelectMany(source, (x, i, token) => taskSelector(x, i), resultSelector); + return new SelectMany.TaskSelectorIndexed(source, (x, i, token) => taskSelector(x, i), resultSelector); } public virtual IObservable SelectMany(IObservable source, Func> taskSelector, Func resultSelector) { - return new SelectMany(source, taskSelector, resultSelector); + return new SelectMany.TaskSelector(source, taskSelector, resultSelector); } public virtual IObservable SelectMany(IObservable source, Func> taskSelector, Func resultSelector) { - return new SelectMany(source, taskSelector, resultSelector); + return new SelectMany.TaskSelectorIndexed(source, taskSelector, resultSelector); } private static IObservable SelectMany_(IObservable source, Func> selector) { - return new SelectMany(source, selector); + return new SelectMany.ObservableSelector(source, selector); } private static IObservable SelectMany_(IObservable source, Func> selector) { - return new SelectMany(source, selector); + return new SelectMany.ObservableSelectorIndexed(source, selector); } private static IObservable SelectMany_(IObservable source, Func> collectionSelector, Func resultSelector) { - return new SelectMany(source, collectionSelector, resultSelector); + return new SelectMany.ObservableSelector(source, collectionSelector, resultSelector); } private static IObservable SelectMany_(IObservable source, Func> collectionSelector, Func resultSelector) { - return new SelectMany(source, collectionSelector, resultSelector); + return new SelectMany.ObservableSelectorIndexed(source, collectionSelector, resultSelector); } public virtual IObservable SelectMany(IObservable source, Func> onNext, Func> onError, Func> onCompleted) { - return new SelectMany(source, onNext, onError, onCompleted); + return new SelectMany.ObservableSelector(source, onNext, onError, onCompleted); } public virtual IObservable SelectMany(IObservable source, Func> onNext, Func> onError, Func> onCompleted) { - return new SelectMany(source, onNext, onError, onCompleted); + return new SelectMany.ObservableSelectorIndexed(source, onNext, onError, onCompleted); } public virtual IObservable SelectMany(IObservable source, Func> selector) { - return new SelectMany(source, selector); + return new SelectMany.EnumerableSelector(source, selector); } public virtual IObservable SelectMany(IObservable source, Func> selector) { - return new SelectMany(source, selector); + return new SelectMany.EnumerableSelectorIndexed(source, selector); } public virtual IObservable SelectMany(IObservable source, Func> collectionSelector, Func resultSelector) @@ -330,12 +330,12 @@ public virtual IObservable SelectMany(IO private static IObservable SelectMany_(IObservable source, Func> collectionSelector, Func resultSelector) { - return new SelectMany(source, collectionSelector, resultSelector); + return new SelectMany.EnumerableSelector(source, collectionSelector, resultSelector); } private static IObservable SelectMany_(IObservable source, Func> collectionSelector, Func resultSelector) { - return new SelectMany(source, collectionSelector, resultSelector); + return new SelectMany.EnumerableSelectorIndexed(source, collectionSelector, resultSelector); } #endregion From ad172aa1bb6cc1897489565f7058af362b21b7aa Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:35:22 -0700 Subject: [PATCH 73/95] Further reducing object layout of SkipWhile. --- .../Linq/Observable/SkipWhile.cs | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipWhile.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipWhile.cs index f0c00de45..7705c9375 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipWhile.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SkipWhile.cs @@ -26,23 +26,22 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - private readonly Func _predicate; - private bool _running; + private Func _predicate; public _(Func predicate, IObserver observer, IDisposable cancel) : base(observer, cancel) { _predicate = predicate; - _running = false; } public void OnNext(TSource value) { - if (!_running) + if (_predicate != null) { + var shouldStart = default(bool); try { - _running = !_predicate(value); + shouldStart = !_predicate(value); } catch (Exception exception) { @@ -50,9 +49,15 @@ public void OnNext(TSource value) base.Dispose(); return; } - } - if (_running) + if (shouldStart) + { + _predicate = null; + + base._observer.OnNext(value); + } + } + else { base._observer.OnNext(value); } @@ -92,25 +97,24 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - private readonly Func _predicate; - private bool _running; + private Func _predicate; private int _index; public _(Func predicate, IObserver observer, IDisposable cancel) : base(observer, cancel) { _predicate = predicate; - _running = false; _index = 0; } public void OnNext(TSource value) { - if (!_running) + if (_predicate != null) { + var shouldStart = default(bool); try { - _running = !_predicate(value, checked(_index++)); + shouldStart = !_predicate(value, checked(_index++)); } catch (Exception exception) { @@ -118,9 +122,15 @@ public void OnNext(TSource value) base.Dispose(); return; } - } - if (_running) + if (shouldStart) + { + _predicate = null; + + base._observer.OnNext(value); + } + } + else { base._observer.OnNext(value); } From 5c35ea3785b7e1c962692a8fd3a79949a45ecea2 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:48:20 -0700 Subject: [PATCH 74/95] Optimizing layouts of Throttle. --- .../Linq/Observable/Throttle.cs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throttle.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throttle.cs index be94efcb7..a2859c6ea 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throttle.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throttle.cs @@ -27,8 +27,10 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return sink.Run(); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { + // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Throttle _parent; public _(Throttle parent, IObserver observer, IDisposable cancel) @@ -94,7 +96,7 @@ public void OnError(Exception error) _hasValue = false; _id = unchecked(_id + 1); - } + } } public void OnCompleted() @@ -105,7 +107,7 @@ public void OnCompleted() { if (_hasValue) base._observer.OnNext(_value); - + base._observer.OnCompleted(); base.Dispose(); @@ -131,17 +133,17 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { - private readonly Throttle _parent; + private readonly Func> _throttleSelector; public _(Throttle parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _throttleSelector = parent._throttleSelector; } private object _gate; @@ -150,7 +152,7 @@ public _(Throttle parent, IObserver observer, IDisp private SerialDisposable _cancelable; private ulong _id; - public IDisposable Run() + public IDisposable Run(Throttle parent) { _gate = new object(); _value = default(TSource); @@ -158,7 +160,7 @@ public IDisposable Run() _cancelable = new SerialDisposable(); _id = 0UL; - var subscription = _parent._source.SubscribeSafe(this); + var subscription = parent._source.SubscribeSafe(this); return StableCompositeDisposable.Create(subscription, _cancelable); } @@ -168,7 +170,7 @@ public void OnNext(TSource value) var throttle = default(IObservable); try { - throttle = _parent._throttleSelector(value); + throttle = _throttleSelector(value); } catch (Exception error) { @@ -192,7 +194,7 @@ public void OnNext(TSource value) var d = new SingleAssignmentDisposable(); _cancelable.Disposable = d; - d.Disposable = throttle.SubscribeSafe(new Delta(this, value, currentid, d)); + d.Disposable = throttle.SubscribeSafe(new ThrottleObserver(this, value, currentid, d)); } public void OnError(Exception error) @@ -226,14 +228,14 @@ public void OnCompleted() } } - class Delta : IObserver + private sealed class ThrottleObserver : IObserver { private readonly _ _parent; private readonly TSource _value; private readonly ulong _currentid; private readonly IDisposable _self; - public Delta(_ parent, TSource value, ulong currentid, IDisposable self) + public ThrottleObserver(_ parent, TSource value, ulong currentid, IDisposable self) { _parent = parent; _value = value; From 597061bc93576cc70e53baafc3595f0571a1838a Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:51:28 -0700 Subject: [PATCH 75/95] Marking a field in ToArray as readonly --- Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs index a5ea2800b..074de207d 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToArray.cs @@ -24,7 +24,7 @@ protected override IDisposable Run(IObserver observer, IDisposable ca private sealed class _ : Sink, IObserver { - private List _list; + private readonly List _list; public _(IObserver observer, IDisposable cancel) : base(observer, cancel) From e4de57fa984518ab65c50eaa45517664166daa5e Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 12:53:03 -0700 Subject: [PATCH 76/95] Marking a field in ToList as readonly. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs index 712d6a524..d2ddf0893 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToList.cs @@ -24,7 +24,7 @@ protected override IDisposable Run(IObserver> observer, IDisposab private sealed class _ : Sink>, IObserver { - private List _list; + private readonly List _list; public _(IObserver> observer, IDisposable cancel) : base(observer, cancel) From 2dc321e6bb72041af93fe04e5578b9195b0d10c5 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 16:57:09 -0700 Subject: [PATCH 77/95] Optimizing the layout of SelectMany variants. --- .../Linq/Observable/SelectMany.cs | 546 ++++++++++-------- ...QueryLanguage.StandardSequenceOperators.cs | 4 +- 2 files changed, 313 insertions(+), 237 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SelectMany.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SelectMany.cs index 904a21f7d..903b1b86b 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/SelectMany.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/SelectMany.cs @@ -28,33 +28,34 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } private sealed class _ : Sink, IObserver { - private readonly ObservableSelector _parent; + private readonly object _gate = new object(); + private readonly SingleAssignmentDisposable _sourceSubscription = new SingleAssignmentDisposable(); + private readonly CompositeDisposable _group = new CompositeDisposable(); + + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; public _(ObservableSelector parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _collectionSelector = parent._collectionSelector; + _resultSelector = parent._resultSelector; + + _group.Add(_sourceSubscription); } - private object _gate; private bool _isStopped; - private CompositeDisposable _group; - private SingleAssignmentDisposable _sourceSubscription; - public IDisposable Run() + public IDisposable Run(IObservable source) { - _gate = new object(); _isStopped = false; - _group = new CompositeDisposable(); - _sourceSubscription = new SingleAssignmentDisposable(); - _group.Add(_sourceSubscription); - _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + _sourceSubscription.Disposable = source.SubscribeSafe(this); return _group; } @@ -65,7 +66,7 @@ public void OnNext(TSource value) try { - collection = _parent._collectionSelector(value); + collection = _collectionSelector(value); } catch (Exception ex) { @@ -134,7 +135,7 @@ public void OnNext(TCollection value) try { - res = _parent._parent._resultSelector(_value, value); + res = _parent._resultSelector(_value, value); } catch (Exception ex) { @@ -199,34 +200,35 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } private sealed class _ : Sink, IObserver { - private readonly ObservableSelectorIndexed _parent; + private readonly object _gate = new object(); + private readonly SingleAssignmentDisposable _sourceSubscription = new SingleAssignmentDisposable(); + private readonly CompositeDisposable _group = new CompositeDisposable(); + + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; public _(ObservableSelectorIndexed parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _collectionSelector = parent._collectionSelector; + _resultSelector = parent._resultSelector; + + _group.Add(_sourceSubscription); } - private object _gate; private bool _isStopped; - private CompositeDisposable _group; - private SingleAssignmentDisposable _sourceSubscription; private int _index; - public IDisposable Run() + public IDisposable Run(IObservable source) { - _gate = new object(); _isStopped = false; - _group = new CompositeDisposable(); - _sourceSubscription = new SingleAssignmentDisposable(); - _group.Add(_sourceSubscription); - _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + _sourceSubscription.Disposable = source.SubscribeSafe(this); return _group; } @@ -238,7 +240,7 @@ public void OnNext(TSource value) try { - collection = _parent._collectionSelector(value, index); + collection = _collectionSelector(value, index); } catch (Exception ex) { @@ -311,7 +313,7 @@ public void OnNext(TCollection value) try { - res = _parent._parent._resultSelector(_value, _valueIndex, value, checked(_index++)); + res = _parent._resultSelector(_value, _valueIndex, value, checked(_index++)); } catch (Exception ex) { @@ -381,12 +383,14 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - private readonly EnumerableSelector _parent; + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; public _(EnumerableSelector parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _collectionSelector = parent._collectionSelector; + _resultSelector = parent._resultSelector; } public void OnNext(TSource value) @@ -394,7 +398,7 @@ public void OnNext(TSource value) var xs = default(IEnumerable); try { - xs = _parent._collectionSelector(value); + xs = _collectionSelector(value); } catch (Exception exception) { @@ -427,7 +431,7 @@ public void OnNext(TSource value) { hasNext = e.MoveNext(); if (hasNext) - current = _parent._resultSelector(value, e.Current); + current = _resultSelector(value, e.Current); } catch (Exception exception) { @@ -483,12 +487,14 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - private readonly EnumerableSelectorIndexed _parent; + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; public _(EnumerableSelectorIndexed parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _collectionSelector = parent._collectionSelector; + _resultSelector = parent._resultSelector; } private int _index; @@ -500,7 +506,7 @@ public void OnNext(TSource value) var xs = default(IEnumerable); try { - xs = _parent._collectionSelector(value, index); + xs = _collectionSelector(value, index); } catch (Exception exception) { @@ -534,7 +540,7 @@ public void OnNext(TSource value) { hasNext = e.MoveNext(); if (hasNext) - current = _parent._resultSelector(value, index, e.Current, checked(eIndex++)); + current = _resultSelector(value, index, e.Current, checked(eIndex++)); } catch (Exception exception) { @@ -585,30 +591,31 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } private sealed class _ : Sink, IObserver { - private readonly TaskSelector _parent; + private readonly object _gate = new object(); + private readonly CancellationDisposable _cancel = new CancellationDisposable(); + + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; public _(TaskSelector parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _collectionSelector = parent._collectionSelector; + _resultSelector = parent._resultSelector; } - private object _gate; - private CancellationDisposable _cancel; private volatile int _count; - public IDisposable Run() + public IDisposable Run(IObservable source) { - _gate = new object(); - _cancel = new CancellationDisposable(); _count = 1; - return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + return StableCompositeDisposable.Create(source.SubscribeSafe(this), _cancel); } public void OnNext(TSource value) @@ -617,7 +624,7 @@ public void OnNext(TSource value) try { Interlocked.Increment(ref _count); - task = _parent._collectionSelector(value, _cancel.Token); + task = _collectionSelector(value, _cancel.Token); } catch (Exception ex) { @@ -657,7 +664,7 @@ private void OnCompletedTask(TSource value, Task task) var res = default(TResult); try { - res = _parent._resultSelector(value, task.Result); + res = _resultSelector(value, task.Result); } catch (Exception ex) { @@ -740,31 +747,32 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } private sealed class _ : Sink, IObserver { - private readonly TaskSelectorIndexed _parent; + private readonly object _gate = new object(); + private readonly CancellationDisposable _cancel = new CancellationDisposable(); + + private readonly Func> _collectionSelector; + private readonly Func _resultSelector; public _(TaskSelectorIndexed parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _collectionSelector = parent._collectionSelector; + _resultSelector = parent._resultSelector; } - private object _gate; - private CancellationDisposable _cancel; private volatile int _count; private int _index; - public IDisposable Run() + public IDisposable Run(IObservable source) { - _gate = new object(); - _cancel = new CancellationDisposable(); _count = 1; - return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + return StableCompositeDisposable.Create(source.SubscribeSafe(this), _cancel); } public void OnNext(TSource value) @@ -775,7 +783,7 @@ public void OnNext(TSource value) try { Interlocked.Increment(ref _count); - task = _parent._collectionSelector(value, index, _cancel.Token); + task = _collectionSelector(value, index, _cancel.Token); } catch (Exception ex) { @@ -815,7 +823,7 @@ private void OnCompletedTask(TSource value, int index, Task task) var res = default(TResult); try { - res = _parent._resultSelector(value, index, task.Result); + res = _resultSelector(value, index, task.Result); } catch (Exception ex) { @@ -884,12 +892,10 @@ public void OnCompleted() internal static class SelectMany { - internal sealed class ObservableSelector : Producer + internal class ObservableSelector : Producer { - private readonly IObservable _source; - private readonly Func> _selector; - private readonly Func> _selectorOnError; - private readonly Func> _selectorOnCompleted; + protected readonly IObservable _source; + protected readonly Func> _selector; public ObservableSelector(IObservable source, Func> selector) { @@ -897,45 +903,36 @@ public ObservableSelector(IObservable source, Func source, Func> selector, Func> selectorOnError, Func> selectorOnCompleted) - { - _source = source; - _selector = selector; - _selectorOnError = selectorOnError; - _selectorOnCompleted = selectorOnCompleted; - } - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } - private sealed class _ : Sink, IObserver + protected class _ : Sink, IObserver { - private readonly ObservableSelector _parent; + protected readonly object _gate = new object(); + private readonly SingleAssignmentDisposable _sourceSubscription = new SingleAssignmentDisposable(); + private readonly CompositeDisposable _group = new CompositeDisposable(); + + private readonly Func> _selector; public _(ObservableSelector parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _selector = parent._selector; + + _group.Add(_sourceSubscription); } - private object _gate; private bool _isStopped; - private CompositeDisposable _group; - private SingleAssignmentDisposable _sourceSubscription; - public IDisposable Run() + public IDisposable Run(IObservable source) { - _gate = new object(); _isStopped = false; - _group = new CompositeDisposable(); - _sourceSubscription = new SingleAssignmentDisposable(); - _group.Add(_sourceSubscription); - _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + _sourceSubscription.Disposable = source.SubscribeSafe(this); return _group; } @@ -946,7 +943,7 @@ public void OnNext(TSource value) try { - inner = _parent._selector(value); + inner = _selector(value); } catch (Exception ex) { @@ -961,67 +958,21 @@ public void OnNext(TSource value) SubscribeInner(inner); } - public void OnError(Exception error) + public virtual void OnError(Exception error) { - if (_parent._selectorOnError != null) - { - var inner = default(IObservable); - - try - { - inner = _parent._selectorOnError(error); - } - catch (Exception ex) - { - lock (_gate) - { - base._observer.OnError(ex); - base.Dispose(); - } - return; - } - - SubscribeInner(inner); - - Final(); - } - else + lock (_gate) { - lock (_gate) - { - base._observer.OnError(error); - base.Dispose(); - } + base._observer.OnError(error); + base.Dispose(); } } - public void OnCompleted() + public virtual void OnCompleted() { - if (_parent._selectorOnCompleted != null) - { - var inner = default(IObservable); - - try - { - inner = _parent._selectorOnCompleted(); - } - catch (Exception ex) - { - lock (_gate) - { - base._observer.OnError(ex); - base.Dispose(); - } - return; - } - - SubscribeInner(inner); - } - Final(); } - private void Final() + protected void Final() { _isStopped = true; if (_group.Count == 1) @@ -1045,7 +996,7 @@ private void Final() } } - private void SubscribeInner(IObservable inner) + protected void SubscribeInner(IObservable inner) { var innerSubscription = new SingleAssignmentDisposable(); _group.Add(innerSubscription); @@ -1101,23 +1052,14 @@ public void OnCompleted() } } - internal sealed class ObservableSelectorIndexed : Producer + internal sealed class ObservableSelectors : ObservableSelector { - private readonly IObservable _source; - private readonly Func> _selector; private readonly Func> _selectorOnError; private readonly Func> _selectorOnCompleted; - public ObservableSelectorIndexed(IObservable source, Func> selector) - { - _source = source; - _selector = selector; - } - - public ObservableSelectorIndexed(IObservable source, Func> selector, Func> selectorOnError, Func> selectorOnCompleted) + public ObservableSelectors(IObservable source, Func> selector, Func> selectorOnError, Func> selectorOnCompleted) + : base(source, selector) { - _source = source; - _selector = selector; _selectorOnError = selectorOnError; _selectorOnCompleted = selectorOnCompleted; } @@ -1126,68 +1068,30 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } - private sealed class _ : Sink, IObserver + new private sealed class _ : ObservableSelector._ { - private readonly ObservableSelectorIndexed _parent; + private readonly Func> _selectorOnError; + private readonly Func> _selectorOnCompleted; - public _(ObservableSelectorIndexed parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public _(ObservableSelectors parent, IObserver observer, IDisposable cancel) + : base(parent, observer, cancel) { - _parent = parent; + _selectorOnError = parent._selectorOnError; + _selectorOnCompleted = parent._selectorOnCompleted; } - private object _gate; - private bool _isStopped; - private CompositeDisposable _group; - private SingleAssignmentDisposable _sourceSubscription; - private int _index; - - public IDisposable Run() + public override void OnError(Exception error) { - _gate = new object(); - _isStopped = false; - _group = new CompositeDisposable(); - - _sourceSubscription = new SingleAssignmentDisposable(); - _group.Add(_sourceSubscription); - _sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); - - return _group; - } - - public void OnNext(TSource value) - { - var inner = default(IObservable); - - try - { - inner = _parent._selector(value, checked(_index++)); - } - catch (Exception ex) - { - lock (_gate) - { - base._observer.OnError(ex); - base.Dispose(); - } - return; - } - - SubscribeInner(inner); - } - - public void OnError(Exception error) - { - if (_parent._selectorOnError != null) + if (_selectorOnError != null) { var inner = default(IObservable); try { - inner = _parent._selectorOnError(error); + inner = _selectorOnError(error); } catch (Exception ex) { @@ -1205,23 +1109,19 @@ public void OnError(Exception error) } else { - lock (_gate) - { - base._observer.OnError(error); - base.Dispose(); - } + base.OnError(error); } } - public void OnCompleted() + public override void OnCompleted() { - if (_parent._selectorOnCompleted != null) + if (_selectorOnCompleted != null) { var inner = default(IObservable); try { - inner = _parent._selectorOnCompleted(); + inner = _selectorOnCompleted(); } catch (Exception ex) { @@ -1238,8 +1138,91 @@ public void OnCompleted() Final(); } + } + } + + internal class ObservableSelectorIndexed : Producer + { + protected readonly IObservable _source; + protected readonly Func> _selector; + + public ObservableSelectorIndexed(IObservable source, Func> selector) + { + _source = source; + _selector = selector; + } - private void Final() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(_source); + } + + protected class _ : Sink, IObserver + { + private readonly object _gate = new object(); + private readonly SingleAssignmentDisposable _sourceSubscription = new SingleAssignmentDisposable(); + private readonly CompositeDisposable _group = new CompositeDisposable(); + + protected readonly Func> _selector; + + public _(ObservableSelectorIndexed parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _selector = parent._selector; + + _group.Add(_sourceSubscription); + } + + private bool _isStopped; + private int _index; + + public IDisposable Run(IObservable source) + { + _isStopped = false; + + _sourceSubscription.Disposable = source.SubscribeSafe(this); + + return _group; + } + + public void OnNext(TSource value) + { + var inner = default(IObservable); + + try + { + inner = _selector(value, checked(_index++)); + } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } + return; + } + + SubscribeInner(inner); + } + + public virtual void OnError(Exception error) + { + lock (_gate) + { + base._observer.OnError(error); + base.Dispose(); + } + } + + public virtual void OnCompleted() + { + Final(); + } + + protected void Final() { _isStopped = true; if (_group.Count == 1) @@ -1263,7 +1246,7 @@ private void Final() } } - private void SubscribeInner(IObservable inner) + protected void SubscribeInner(IObservable inner) { var innerSubscription = new SingleAssignmentDisposable(); _group.Add(innerSubscription); @@ -1319,6 +1302,101 @@ public void OnCompleted() } } + internal sealed class ObservableSelectorsIndexed : ObservableSelectorIndexed + { + private readonly Func> _selectorOnError; + private readonly Func> _selectorOnCompleted; + + public ObservableSelectorsIndexed(IObservable source, Func> selector, Func> selectorOnError, Func> selectorOnCompleted) + : base(source, selector) + { + _selectorOnError = selectorOnError; + _selectorOnCompleted = selectorOnCompleted; + } + + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(_source); + } + + new private sealed class _ : ObservableSelectorIndexed._ + { + private readonly object _gate = new object(); + private readonly SingleAssignmentDisposable _sourceSubscription = new SingleAssignmentDisposable(); + private readonly CompositeDisposable _group = new CompositeDisposable(); + + private readonly Func> _selectorOnError; + private readonly Func> _selectorOnCompleted; + + public _(ObservableSelectorsIndexed parent, IObserver observer, IDisposable cancel) + : base(parent, observer, cancel) + { + _selectorOnError = parent._selectorOnError; + _selectorOnCompleted = parent._selectorOnCompleted; + + _group.Add(_sourceSubscription); + } + + public override void OnError(Exception error) + { + if (_selectorOnError != null) + { + var inner = default(IObservable); + + try + { + inner = _selectorOnError(error); + } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } + return; + } + + SubscribeInner(inner); + + Final(); + } + else + { + base.OnError(error); + } + } + + public override void OnCompleted() + { + if (_selectorOnCompleted != null) + { + var inner = default(IObservable); + + try + { + inner = _selectorOnCompleted(); + } + catch (Exception ex) + { + lock (_gate) + { + base._observer.OnError(ex); + base.Dispose(); + } + return; + } + + SubscribeInner(inner); + } + + Final(); + } + } + } + internal sealed class EnumerableSelector : Producer { private readonly IObservable _source; @@ -1339,12 +1417,12 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - private readonly EnumerableSelector _parent; + private readonly Func> _selector; public _(EnumerableSelector parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _selector = parent._selector; } public void OnNext(TSource value) @@ -1352,7 +1430,7 @@ public void OnNext(TSource value) var xs = default(IEnumerable); try { - xs = _parent._selector(value); + xs = _selector(value); } catch (Exception exception) { @@ -1439,12 +1517,12 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - private readonly EnumerableSelectorIndexed _parent; + private readonly Func> _selector; public _(EnumerableSelectorIndexed parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _selector = parent._selector; } private int _index; @@ -1454,7 +1532,7 @@ public void OnNext(TSource value) var xs = default(IEnumerable); try { - xs = _parent._selector(value, checked(_index++)); + xs = _selector(value, checked(_index++)); } catch (Exception exception) { @@ -1536,30 +1614,29 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } private sealed class _ : Sink, IObserver { - private readonly TaskSelector _parent; + private readonly object _gate = new object(); + private readonly CancellationDisposable _cancel = new CancellationDisposable(); + + private readonly Func> _selector; public _(TaskSelector parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _selector = parent._selector; } - private object _gate; - private CancellationDisposable _cancel; private volatile int _count; - public IDisposable Run() + public IDisposable Run(IObservable source) { - _gate = new object(); - _cancel = new CancellationDisposable(); _count = 1; - return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + return StableCompositeDisposable.Create(source.SubscribeSafe(this), _cancel); } public void OnNext(TSource value) @@ -1568,7 +1645,7 @@ public void OnNext(TSource value) try { Interlocked.Increment(ref _count); - task = _parent._selector(value, _cancel.Token); + task = _selector(value, _cancel.Token); } catch (Exception ex) { @@ -1665,31 +1742,30 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } private sealed class _ : Sink, IObserver { - private readonly TaskSelectorIndexed _parent; + private readonly object _gate = new object(); + private readonly CancellationDisposable _cancel = new CancellationDisposable(); + + private readonly Func> _selector; public _(TaskSelectorIndexed parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _selector = parent._selector; } - private object _gate; - private CancellationDisposable _cancel; private volatile int _count; private int _index; - public IDisposable Run() + public IDisposable Run(IObservable source) { - _gate = new object(); - _cancel = new CancellationDisposable(); _count = 1; - return StableCompositeDisposable.Create(_parent._source.SubscribeSafe(this), _cancel); + return StableCompositeDisposable.Create(source.SubscribeSafe(this), _cancel); } public void OnNext(TSource value) @@ -1698,7 +1774,7 @@ public void OnNext(TSource value) try { Interlocked.Increment(ref _count); - task = _parent._selector(value, checked(_index++), _cancel.Token); + task = _selector(value, checked(_index++), _cancel.Token); } catch (Exception ex) { diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs index 9f089ab81..74966aea7 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.StandardSequenceOperators.cs @@ -300,12 +300,12 @@ private static IObservable SelectMany_(I public virtual IObservable SelectMany(IObservable source, Func> onNext, Func> onError, Func> onCompleted) { - return new SelectMany.ObservableSelector(source, onNext, onError, onCompleted); + return new SelectMany.ObservableSelectors(source, onNext, onError, onCompleted); } public virtual IObservable SelectMany(IObservable source, Func> onNext, Func> onError, Func> onCompleted) { - return new SelectMany.ObservableSelectorIndexed(source, onNext, onError, onCompleted); + return new SelectMany.ObservableSelectorsIndexed(source, onNext, onError, onCompleted); } public virtual IObservable SelectMany(IObservable source, Func> selector) From 5d2231a9563a169aca775880478fac445c98ebd6 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 16:57:27 -0700 Subject: [PATCH 78/95] Removing unused ObserveOn implementations. --- .../Linq/Observable/ObserveOn.cs | 87 ------------------- 1 file changed, 87 deletions(-) delete mode 100644 Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs deleted file mode 100644 index 72f5514d7..000000000 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ObserveOn.cs +++ /dev/null @@ -1,87 +0,0 @@ -// 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.Reactive.Concurrency; -using System.Threading; - -namespace System.Reactive.Linq.ObservableImpl -{ - internal static class ObserveOn - { - internal sealed class Scheduler : Producer - { - private readonly IObservable _source; - private readonly IScheduler _scheduler; - - public Scheduler(IObservable source, IScheduler scheduler) - { - _source = source; - _scheduler = scheduler; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - var sink = new ObserveOnObserver(_scheduler, observer, cancel); - setSink(sink); - return _source.Subscribe(sink); - } - } - - internal sealed class Context : Producer - { - private readonly IObservable _source; - private readonly SynchronizationContext _context; - - public Context(IObservable source, SynchronizationContext context) - { - _source = source; - _context = context; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - var sink = new _(_context, observer, cancel); - setSink(sink); - return _source.Subscribe(sink); - } - - private sealed class _ : Sink, IObserver - { - private readonly SynchronizationContext _context; - - public _(SynchronizationContext context, IObserver observer, IDisposable cancel) - : base(observer, cancel) - { - _context = context; - } - - public void OnNext(TSource value) - { - _context.PostWithStartComplete(() => - { - base._observer.OnNext(value); - }); - } - - public void OnError(Exception error) - { - _context.PostWithStartComplete(() => - { - base._observer.OnError(error); - base.Dispose(); - }); - } - - public void OnCompleted() - { - _context.PostWithStartComplete(() => - { - base._observer.OnCompleted(); - base.Dispose(); - }); - } - } - } - } -} From 8c67f362eae47e92707e8ee2dec209e84ff0f6aa Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 17:08:29 -0700 Subject: [PATCH 79/95] Optimizing layout of Range --- .../System.Reactive/Linq/Observable/Range.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Range.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Range.cs index e6bd49f23..bafac0a3f 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Range.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Range.cs @@ -24,37 +24,39 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_scheduler); } - class _ : Sink + private sealed class _ : Sink { - private readonly Range _parent; + private readonly int _start; + private readonly int _count; public _(Range parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _start = parent._start; + _count = parent._count; } - public IDisposable Run() + public IDisposable Run(IScheduler scheduler) { - var longRunning = _parent._scheduler.AsLongRunning(); + var longRunning = scheduler.AsLongRunning(); if (longRunning != null) { return longRunning.ScheduleLongRunning(0, Loop); } else { - return _parent._scheduler.Schedule(0, LoopRec); + return scheduler.Schedule(0, LoopRec); } } private void Loop(int i, ICancelable cancel) { - while (!cancel.IsDisposed && i < _parent._count) + while (!cancel.IsDisposed && i < _count) { - base._observer.OnNext(_parent._start + i); + base._observer.OnNext(_start + i); i++; } @@ -66,9 +68,9 @@ private void Loop(int i, ICancelable cancel) private void LoopRec(int i, Action recurse) { - if (i < _parent._count) + if (i < _count) { - base._observer.OnNext(_parent._start + i); + base._observer.OnNext(_start + i); recurse(i + 1); } else From d6ae41d5522473c37452d85d8e9afcf0b8714c96 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 17:14:18 -0700 Subject: [PATCH 80/95] Optimizing layouts of ToDictionary and ToLookup. --- .../Linq/Observable/ToDictionary.cs | 16 ++++++++++------ .../System.Reactive/Linq/Observable/ToLookup.cs | 16 ++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToDictionary.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToDictionary.cs index 58c7ed806..40ec6a2ce 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToDictionary.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToDictionary.cs @@ -28,23 +28,27 @@ protected override IDisposable Run(IObserver> observ return _source.SubscribeSafe(sink); } - class _ : Sink>, IObserver + private sealed class _ : Sink>, IObserver { - private readonly ToDictionary _parent; - private Dictionary _dictionary; + // CONSIDER: This sink has a parent reference that can be considered for removal. + + private readonly Func _keySelector; + private readonly Func _elementSelector; + private readonly Dictionary _dictionary; public _(ToDictionary parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - _dictionary = new Dictionary(_parent._comparer); + _keySelector = parent._keySelector; + _elementSelector = parent._elementSelector; + _dictionary = new Dictionary(parent._comparer); } public void OnNext(TSource value) { try { - _dictionary.Add(_parent._keySelector(value), _parent._elementSelector(value)); + _dictionary.Add(_keySelector(value), _elementSelector(value)); } catch (Exception ex) { diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToLookup.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToLookup.cs index 36c327a4f..9f85f431a 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToLookup.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToLookup.cs @@ -29,23 +29,27 @@ protected override IDisposable Run(IObserver> observer, return _source.SubscribeSafe(sink); } - class _ : Sink>, IObserver + private sealed class _ : Sink>, IObserver { - private readonly ToLookup _parent; - private Lookup _lookup; + // CONSIDER: This sink has a parent reference that can be considered for removal. + + private readonly Func _keySelector; + private readonly Func _elementSelector; + private readonly Lookup _lookup; public _(ToLookup parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - _lookup = new Lookup(_parent._comparer); + _keySelector = parent._keySelector; + _elementSelector = parent._elementSelector; + _lookup = new Lookup(parent._comparer); } public void OnNext(TSource value) { try { - _lookup.Add(_parent._keySelector(value), _parent._elementSelector(value)); + _lookup.Add(_keySelector(value), _elementSelector(value)); } catch (Exception ex) { From 9e9efec26ad426e3ebd1d6455be36245595e47ae Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 17:15:12 -0700 Subject: [PATCH 81/95] Removing some comments. --- .../Source/src/System.Reactive/Linq/Observable/ToDictionary.cs | 2 -- Rx.NET/Source/src/System.Reactive/Linq/Observable/ToLookup.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToDictionary.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToDictionary.cs index 40ec6a2ce..0c4982c31 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToDictionary.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToDictionary.cs @@ -30,8 +30,6 @@ protected override IDisposable Run(IObserver> observ private sealed class _ : Sink>, IObserver { - // CONSIDER: This sink has a parent reference that can be considered for removal. - private readonly Func _keySelector; private readonly Func _elementSelector; private readonly Dictionary _dictionary; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToLookup.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToLookup.cs index 9f85f431a..baa87b3ea 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToLookup.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/ToLookup.cs @@ -31,8 +31,6 @@ protected override IDisposable Run(IObserver> observer, private sealed class _ : Sink>, IObserver { - // CONSIDER: This sink has a parent reference that can be considered for removal. - private readonly Func _keySelector; private readonly Func _elementSelector; private readonly Lookup _lookup; From faa8a771f2d11f234f87e67b469e82afdca57249 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 17:33:18 -0700 Subject: [PATCH 82/95] Optimizing layouts of DistinctUntilChanged. --- .../Linq/Observable/DistinctUntilChanged.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DistinctUntilChanged.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DistinctUntilChanged.cs index da0e78c99..a9df10f86 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/DistinctUntilChanged.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/DistinctUntilChanged.cs @@ -28,16 +28,18 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Func _keySelector; + private readonly IEqualityComparer _comparer; - private readonly DistinctUntilChanged _parent; private TKey _currentKey; private bool _hasCurrentKey; public _(DistinctUntilChanged parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _keySelector = parent._keySelector; + _comparer = parent._comparer; + _currentKey = default(TKey); _hasCurrentKey = false; } @@ -47,7 +49,7 @@ public void OnNext(TSource value) var key = default(TKey); try { - key = _parent._keySelector(value); + key = _keySelector(value); } catch (Exception exception) { @@ -61,7 +63,7 @@ public void OnNext(TSource value) { try { - comparerEquals = _parent._comparer.Equals(_currentKey, key); + comparerEquals = _comparer.Equals(_currentKey, key); } catch (Exception exception) { From 81a05e57d9bab0db4cd7fbb880931cc86a8edefb Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 17:33:25 -0700 Subject: [PATCH 83/95] Optimizing layouts of Aggregate. --- .../System.Reactive/Linq/Observable/Aggregate.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs index 951af3de7..14f98dd67 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Aggregate.cs @@ -164,23 +164,25 @@ protected override IDisposable Run(IObserver observer, IDisposable canc private sealed class _ : Sink, IObserver { - // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Func _accumulator; + private readonly Func _resultSelector; - private readonly Aggregate _parent; private TAccumulate _accumulation; public _(Aggregate parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - _accumulation = _parent._seed; + _accumulator = parent._accumulator; + _resultSelector = parent._resultSelector; + + _accumulation = parent._seed; } public void OnNext(TSource value) { try { - _accumulation = _parent._accumulator(_accumulation, value); + _accumulation = _accumulator(_accumulation, value); } catch (Exception exception) { @@ -200,7 +202,7 @@ public void OnCompleted() var result = default(TResult); try { - result = _parent._resultSelector(_accumulation); + result = _resultSelector(_accumulation); } catch (Exception exception) { From d02c0b6f1f32de65be8c1667c3a7fbaf6c08de66 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 17:33:29 -0700 Subject: [PATCH 84/95] Optimizing layouts of Contains. --- .../src/System.Reactive/Linq/Observable/Contains.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs index a5158ba19..824089efd 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Contains.cs @@ -28,14 +28,14 @@ protected override IDisposable Run(IObserver observer, IDisposable cancel, private sealed class _ : Sink, IObserver { - // CONSIDER: This sink has a parent reference that can be considered for removal. - - private readonly Contains _parent; + private readonly TSource _value; + private readonly IEqualityComparer _comparer; public _(Contains parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _value = parent._value; + _comparer = parent._comparer; } public void OnNext(TSource value) @@ -43,7 +43,7 @@ public void OnNext(TSource value) var res = false; try { - res = _parent._comparer.Equals(value, _parent._value); + res = _comparer.Equals(value, _value); } catch (Exception ex) { From 5982cab30e09e0bdb1ace65deb83303415e3c7f4 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 18:07:49 -0700 Subject: [PATCH 85/95] Optimizing layouts of Timeout. --- .../Linq/Observable/Timeout.cs | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timeout.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timeout.cs index 17ccef7a1..bce0d4462 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timeout.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Timeout.cs @@ -28,50 +28,49 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } private sealed class _ : Sink, IObserver { - // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly TimeSpan _dueTime; + private readonly IObservable _other; + private readonly IScheduler _scheduler; - private readonly Relative _parent; + private readonly object _gate = new object(); + private SerialDisposable _subscription = new SerialDisposable(); + private SerialDisposable _timer = new SerialDisposable(); public _(Relative parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _dueTime = parent._dueTime; + _other = parent._other; + _scheduler = parent._scheduler; } - private SerialDisposable _subscription; - private SerialDisposable _timer; - - private object _gate; private ulong _id; private bool _switched; - public IDisposable Run() + public IDisposable Run(IObservable source) { - _subscription = new SerialDisposable(); - _timer = new SerialDisposable(); var original = new SingleAssignmentDisposable(); _subscription.Disposable = original; - _gate = new object(); _id = 0UL; _switched = false; CreateTimer(); - original.Disposable = _parent._source.SubscribeSafe(this); + original.Disposable = source.SubscribeSafe(this); return StableCompositeDisposable.Create(_subscription, _timer); } private void CreateTimer() { - _timer.Disposable = _parent._scheduler.Schedule(_id, _parent._dueTime, Timeout); + _timer.Disposable = _scheduler.Schedule(_id, _dueTime, Timeout); } private IDisposable Timeout(IScheduler _, ulong myid) @@ -85,7 +84,7 @@ private IDisposable Timeout(IScheduler _, ulong myid) } if (timerWins) - _subscription.Disposable = _parent._other.SubscribeSafe(this.GetForwarder()); + _subscription.Disposable = _other.SubscribeSafe(this.GetForwarder()); return Disposable.Empty; } @@ -178,24 +177,23 @@ private sealed class _ : Sink, IObserver { private readonly IObservable _other; + private readonly object _gate = new object(); + private readonly SerialDisposable _subscription = new SerialDisposable(); + public _(IObservable other, IObserver observer, IDisposable cancel) : base(observer, cancel) { _other = other; } - private SerialDisposable _subscription; - private object _gate; private bool _switched; public IDisposable Run(Absolute parent) { - _subscription = new SerialDisposable(); var original = new SingleAssignmentDisposable(); _subscription.Disposable = original; - _gate = new object(); _switched = false; var timer = parent._scheduler.Schedule(parent._dueTime, Timeout); @@ -284,42 +282,40 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } private sealed class _ : Sink, IObserver { - // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly Func> _timeoutSelector; + private readonly IObservable _other; - private readonly Timeout _parent; + private readonly object _gate = new object(); + private readonly SerialDisposable _subscription = new SerialDisposable(); + private readonly SerialDisposable _timer = new SerialDisposable(); public _(Timeout parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _timeoutSelector = parent._timeoutSelector; + _other = parent._other; } - private SerialDisposable _subscription; - private SerialDisposable _timer; - private object _gate; private ulong _id; private bool _switched; - public IDisposable Run() + public IDisposable Run(Timeout parent) { - _subscription = new SerialDisposable(); - _timer = new SerialDisposable(); var original = new SingleAssignmentDisposable(); _subscription.Disposable = original; - _gate = new object(); _id = 0UL; _switched = false; - SetTimer(_parent._firstTimeout); + SetTimer(parent._firstTimeout); - original.Disposable = _parent._source.SubscribeSafe(this); + original.Disposable = parent._source.SubscribeSafe(this); return StableCompositeDisposable.Create(_subscription, _timer); } @@ -333,7 +329,7 @@ public void OnNext(TSource value) var timeout = default(IObservable); try { - timeout = _parent._timeoutSelector(value); + timeout = _timeoutSelector(value); } catch (Exception error) { @@ -389,7 +385,7 @@ public TimeoutObserver(_ parent, ulong id, IDisposable self) public void OnNext(TTimeout value) { if (TimerWins()) - _parent._subscription.Disposable = _parent._parent._other.SubscribeSafe(_parent.GetForwarder()); + _parent._subscription.Disposable = _parent._other.SubscribeSafe(_parent.GetForwarder()); _self.Dispose(); } @@ -406,7 +402,7 @@ public void OnError(Exception error) public void OnCompleted() { if (TimerWins()) - _parent._subscription.Disposable = _parent._parent._other.SubscribeSafe(_parent.GetForwarder()); + _parent._subscription.Disposable = _parent._other.SubscribeSafe(_parent.GetForwarder()); } private bool TimerWins() From 13698ed492bdb3bdce8de27343ea775385af9783 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 18:07:57 -0700 Subject: [PATCH 86/95] Optimizing layouts of Throttle. --- .../System.Reactive/Linq/Observable/Throttle.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throttle.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throttle.cs index a2859c6ea..5ae66fa42 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throttle.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Throttle.cs @@ -24,19 +24,19 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } private sealed class _ : Sink, IObserver { - // CONSIDER: This sink has a parent reference that can be considered for removal. - - private readonly Throttle _parent; + private readonly TimeSpan _dueTime; + private readonly IScheduler _scheduler; public _(Throttle parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _dueTime = parent._dueTime; + _scheduler = parent._scheduler; } private object _gate; @@ -45,7 +45,7 @@ public _(Throttle parent, IObserver observer, IDisposable canc private SerialDisposable _cancelable; private ulong _id; - public IDisposable Run() + public IDisposable Run(IObservable source) { _gate = new object(); _value = default(TSource); @@ -53,7 +53,7 @@ public IDisposable Run() _cancelable = new SerialDisposable(); _id = 0UL; - var subscription = _parent._source.SubscribeSafe(this); + var subscription = source.SubscribeSafe(this); return StableCompositeDisposable.Create(subscription, _cancelable); } @@ -70,7 +70,7 @@ public void OnNext(TSource value) } var d = new SingleAssignmentDisposable(); _cancelable.Disposable = d; - d.Disposable = _parent._scheduler.Schedule(currentid, _parent._dueTime, Propagate); + d.Disposable = _scheduler.Schedule(currentid, _dueTime, Propagate); } private IDisposable Propagate(IScheduler self, ulong currentid) From 8e1d2d47cb88b8910d3f805525239edbf89370d1 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 20:38:34 -0700 Subject: [PATCH 87/95] Optimizing layouts of Buffer. --- .../System.Reactive/Linq/Observable/Buffer.cs | 968 +++++++++--------- .../Linq/QueryLanguage.Multiple.cs | 4 +- .../Linq/QueryLanguage.Single.cs | 2 +- .../Linq/QueryLanguage.Time.cs | 13 +- 4 files changed, 502 insertions(+), 485 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Buffer.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Buffer.cs index 1dbf9a77c..b6b0e9a63 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Buffer.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Buffer.cs @@ -8,697 +8,709 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Buffer : Producer> + internal static class Buffer { - private readonly IObservable _source; - private readonly int _count; - private readonly int _skip; - - private readonly TimeSpan _timeSpan; - private readonly TimeSpan _timeShift; - private readonly IScheduler _scheduler; - - public Buffer(IObservable source, int count, int skip) - { - _source = source; - _count = count; - _skip = skip; - } - - public Buffer(IObservable source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler) + internal sealed class Count : Producer> { - _source = source; - _timeSpan = timeSpan; - _timeShift = timeShift; - _scheduler = scheduler; - } + private readonly IObservable _source; + private readonly int _count; + private readonly int _skip; - public Buffer(IObservable source, TimeSpan timeSpan, int count, IScheduler scheduler) - { - _source = source; - _timeSpan = timeSpan; - _count = count; - _scheduler = scheduler; - } - - protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) - { - if (_scheduler == null) + public Count(IObservable source, int count, int skip) { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _count = count; + _skip = skip; } - else if (_count > 0) + + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - var sink = new Impl(this, observer, cancel); + var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); - } - else - { - if (_timeSpan == _timeShift) - { - var sink = new BufferTimeShift(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - else - { - var sink = new BufferImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); - } + return sink.Run(_source); } - } - - class _ : Sink>, IObserver - { - private readonly Buffer _parent; - public _(Buffer parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink>, IObserver { - _parent = parent; - } + private readonly Queue> _queue = new Queue>(); - private Queue> _queue; - private int _n; + private readonly int _count; + private readonly int _skip; - public IDisposable Run() - { - _queue = new Queue>(); - _n = 0; + public _(Count parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + _count = parent._count; + _skip = parent._skip; + } - CreateWindow(); - return _parent._source.SubscribeSafe(this); - } + private int _n; - private void CreateWindow() - { - var s = new List(); - _queue.Enqueue(s); - } + public IDisposable Run(IObservable source) + { + _n = 0; - public void OnNext(TSource value) - { - foreach (var s in _queue) - s.Add(value); + CreateWindow(); + return source.SubscribeSafe(this); + } - var c = _n - _parent._count + 1; - if (c >= 0 && c % _parent._skip == 0) + private void CreateWindow() { - var s = _queue.Dequeue(); - if (s.Count > 0) - base._observer.OnNext(s); + var s = new List(); + _queue.Enqueue(s); } - _n++; - if (_n % _parent._skip == 0) - CreateWindow(); - } + public void OnNext(TSource value) + { + foreach (var s in _queue) + s.Add(value); - public void OnError(Exception error) - { - while (_queue.Count > 0) - _queue.Dequeue().Clear(); + var c = _n - _count + 1; + if (c >= 0 && c % _skip == 0) + { + var s = _queue.Dequeue(); + if (s.Count > 0) + base._observer.OnNext(s); + } - base._observer.OnError(error); - base.Dispose(); - } + _n++; + if (_n % _skip == 0) + CreateWindow(); + } - public void OnCompleted() - { - while (_queue.Count > 0) + public void OnError(Exception error) { - var s = _queue.Dequeue(); - if (s.Count > 0) - base._observer.OnNext(s); + while (_queue.Count > 0) + _queue.Dequeue().Clear(); + + base._observer.OnError(error); + base.Dispose(); } - base._observer.OnCompleted(); - base.Dispose(); + public void OnCompleted() + { + while (_queue.Count > 0) + { + var s = _queue.Dequeue(); + if (s.Count > 0) + base._observer.OnNext(s); + } + + base._observer.OnCompleted(); + base.Dispose(); + } } } - class BufferImpl : Sink>, IObserver + internal sealed class TimeSliding : Producer> { - private readonly Buffer _parent; + private readonly IObservable _source; + + private readonly TimeSpan _timeSpan; + private readonly TimeSpan _timeShift; + private readonly IScheduler _scheduler; - public BufferImpl(Buffer parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + public TimeSliding(IObservable source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler) { - _parent = parent; + _source = source; + _timeSpan = timeSpan; + _timeShift = timeShift; + _scheduler = scheduler; } - private TimeSpan _totalTime; - private TimeSpan _nextShift; - private TimeSpan _nextSpan; - - private object _gate; - private Queue> _q; - - private SerialDisposable _timerD; + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(this); + } - public IDisposable Run() + private sealed class _ : Sink>, IObserver { - _totalTime = TimeSpan.Zero; - _nextShift = _parent._timeShift; - _nextSpan = _parent._timeSpan; + private readonly TimeSpan _timeShift; + private readonly IScheduler _scheduler; - _gate = new object(); - _q = new Queue>(); + private readonly object _gate = new object(); + private readonly Queue> _q = new Queue>(); + private readonly SerialDisposable _timerD = new SerialDisposable(); - _timerD = new SerialDisposable(); + public _(TimeSliding parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + _timeShift = parent._timeShift; + _scheduler = parent._scheduler; + } - CreateWindow(); - CreateTimer(); + private TimeSpan _totalTime; + private TimeSpan _nextShift; + private TimeSpan _nextSpan; - var subscription = _parent._source.SubscribeSafe(this); + public IDisposable Run(TimeSliding parent) + { + _totalTime = TimeSpan.Zero; + _nextShift = parent._timeShift; + _nextSpan = parent._timeSpan; - return StableCompositeDisposable.Create(_timerD, subscription); - } + CreateWindow(); + CreateTimer(); - private void CreateWindow() - { - var s = new List(); - _q.Enqueue(s); - } + var subscription = parent._source.SubscribeSafe(this); - private void CreateTimer() - { - var m = new SingleAssignmentDisposable(); - _timerD.Disposable = m; + return StableCompositeDisposable.Create(_timerD, subscription); + } - var isSpan = false; - var isShift = false; - if (_nextSpan == _nextShift) + private void CreateWindow() { - isSpan = true; - isShift = true; + var s = new List(); + _q.Enqueue(s); } - else if (_nextSpan < _nextShift) - isSpan = true; - else - isShift = true; - var newTotalTime = isSpan ? _nextSpan : _nextShift; - var ts = newTotalTime - _totalTime; - _totalTime = newTotalTime; + private void CreateTimer() + { + var m = new SingleAssignmentDisposable(); + _timerD.Disposable = m; - if (isSpan) - _nextSpan += _parent._timeShift; - if (isShift) - _nextShift += _parent._timeShift; + var isSpan = false; + var isShift = false; + if (_nextSpan == _nextShift) + { + isSpan = true; + isShift = true; + } + else if (_nextSpan < _nextShift) + isSpan = true; + else + isShift = true; - m.Disposable = _parent._scheduler.Schedule(new State { isSpan = isSpan, isShift = isShift }, ts, Tick); - } + var newTotalTime = isSpan ? _nextSpan : _nextShift; + var ts = newTotalTime - _totalTime; + _totalTime = newTotalTime; - struct State - { - public bool isSpan; - public bool isShift; - } + if (isSpan) + _nextSpan += _timeShift; + if (isShift) + _nextShift += _timeShift; - private IDisposable Tick(IScheduler self, State state) - { - lock (_gate) + m.Disposable = _scheduler.Schedule(new State { isSpan = isSpan, isShift = isShift }, ts, Tick); + } + + private struct State { - // - // Before v2, the two operations below were reversed. This doesn't have an observable - // difference for Buffer, but is done to keep code consistent with Window, where we - // took a breaking change in v2 to ensure consistency across overloads. For more info, - // see the comment in Tick for Window. - // - if (state.isSpan) - { - var s = _q.Dequeue(); - base._observer.OnNext(s); - } + public bool isSpan; + public bool isShift; + } - if (state.isShift) + private IDisposable Tick(IScheduler self, State state) + { + lock (_gate) { - CreateWindow(); + // + // Before v2, the two operations below were reversed. This doesn't have an observable + // difference for Buffer, but is done to keep code consistent with Window, where we + // took a breaking change in v2 to ensure consistency across overloads. For more info, + // see the comment in Tick for Window. + // + if (state.isSpan) + { + var s = _q.Dequeue(); + base._observer.OnNext(s); + } + + if (state.isShift) + { + CreateWindow(); + } } - } - CreateTimer(); + CreateTimer(); - return Disposable.Empty; - } + return Disposable.Empty; + } - public void OnNext(TSource value) - { - lock (_gate) + public void OnNext(TSource value) { - foreach (var s in _q) - s.Add(value); + lock (_gate) + { + foreach (var s in _q) + s.Add(value); + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { - while (_q.Count > 0) - _q.Dequeue().Clear(); + lock (_gate) + { + while (_q.Count > 0) + _q.Dequeue().Clear(); - base._observer.OnError(error); - base.Dispose(); + base._observer.OnError(error); + base.Dispose(); + } } - } - public void OnCompleted() - { - lock (_gate) + public void OnCompleted() { - while (_q.Count > 0) - base._observer.OnNext(_q.Dequeue()); + lock (_gate) + { + while (_q.Count > 0) + base._observer.OnNext(_q.Dequeue()); - base._observer.OnCompleted(); - base.Dispose(); + base._observer.OnCompleted(); + base.Dispose(); + } } } } - class BufferTimeShift : Sink>, IObserver + internal sealed class TimeHopping : Producer> { - private readonly Buffer _parent; + private readonly IObservable _source; - public BufferTimeShift(Buffer parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + private readonly TimeSpan _timeSpan; + private readonly IScheduler _scheduler; + + public TimeHopping(IObservable source, TimeSpan timeSpan, IScheduler scheduler) { - _parent = parent; + _source = source; + _timeSpan = timeSpan; + _scheduler = scheduler; } - private object _gate; - private List _list; + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) + { + var sink = new _( observer, cancel); + setSink(sink); + return sink.Run(this); + } - public IDisposable Run() + private sealed class _ : Sink>, IObserver { - _gate = new object(); - _list = new List(); + private readonly object _gate = new object(); - var d = _parent._scheduler.SchedulePeriodic(_parent._timeSpan, Tick); - var s = _parent._source.SubscribeSafe(this); + public _(IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + } - return StableCompositeDisposable.Create(d, s); - } + private List _list; - private void Tick() - { - lock (_gate) + public IDisposable Run(TimeHopping parent) { - base._observer.OnNext(_list); _list = new List(); + + var d = parent._scheduler.SchedulePeriodic(parent._timeSpan, Tick); + var s = parent._source.SubscribeSafe(this); + + return StableCompositeDisposable.Create(d, s); } - } - public void OnNext(TSource value) - { - lock (_gate) + private void Tick() { - _list.Add(value); + lock (_gate) + { + base._observer.OnNext(_list); + _list = new List(); + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnNext(TSource value) { - _list.Clear(); + lock (_gate) + { + _list.Add(value); + } + } - base._observer.OnError(error); - base.Dispose(); + public void OnError(Exception error) + { + lock (_gate) + { + _list.Clear(); + + base._observer.OnError(error); + base.Dispose(); + } } - } - public void OnCompleted() - { - lock (_gate) + public void OnCompleted() { - base._observer.OnNext(_list); - base._observer.OnCompleted(); - base.Dispose(); + lock (_gate) + { + base._observer.OnNext(_list); + base._observer.OnCompleted(); + base.Dispose(); + } } } } - class Impl : Sink>, IObserver + internal sealed class Ferry : Producer> { - private readonly Buffer _parent; + private readonly IObservable _source; + private readonly int _count; + private readonly TimeSpan _timeSpan; + private readonly IScheduler _scheduler; - public Impl(Buffer parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + public Ferry(IObservable source, TimeSpan timeSpan, int count, IScheduler scheduler) { - _parent = parent; + _source = source; + _timeSpan = timeSpan; + _count = count; + _scheduler = scheduler; } - private object _gate; - private IList _s; - private int _n; - private int _windowId; - - private SerialDisposable _timerD; - - public IDisposable Run() + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - _gate = new object(); - _s = default(IList); - _n = 0; - _windowId = 0; - - _timerD = new SerialDisposable(); - - _s = new List(); - CreateTimer(0); - - var subscription = _parent._source.SubscribeSafe(this); - - return StableCompositeDisposable.Create(_timerD, subscription); + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(); } - private void CreateTimer(int id) + private sealed class _ : Sink>, IObserver { - var m = new SingleAssignmentDisposable(); - _timerD.Disposable = m; + private readonly Ferry _parent; - m.Disposable = _parent._scheduler.Schedule(id, _parent._timeSpan, Tick); - } + private readonly object _gate = new object(); + private readonly SerialDisposable _timerD = new SerialDisposable(); - private IDisposable Tick(IScheduler self, int id) - { - var d = Disposable.Empty; - - var newId = 0; - lock (_gate) + public _(Ferry parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) { - if (id != _windowId) - return d; + _parent = parent; + } - _n = 0; - newId = ++_windowId; + private IList _s; + private int _n; + private int _windowId; - var res = _s; + public IDisposable Run() + { _s = new List(); - base._observer.OnNext(res); + _n = 0; + _windowId = 0; + + CreateTimer(0); + + var subscription = _parent._source.SubscribeSafe(this); - CreateTimer(newId); + return StableCompositeDisposable.Create(_timerD, subscription); } - return d; - } + private void CreateTimer(int id) + { + var m = new SingleAssignmentDisposable(); + _timerD.Disposable = m; - public void OnNext(TSource value) - { - var newWindow = false; - var newId = 0; + m.Disposable = _parent._scheduler.Schedule(id, _parent._timeSpan, Tick); + } - lock (_gate) + private IDisposable Tick(IScheduler self, int id) { - _s.Add(value); + var d = Disposable.Empty; - _n++; - if (_n == _parent._count) + var newId = 0; + lock (_gate) { - newWindow = true; + if (id != _windowId) + return d; + _n = 0; newId = ++_windowId; var res = _s; _s = new List(); base._observer.OnNext(res); - } - if (newWindow) CreateTimer(newId); + } + + return d; } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnNext(TSource value) { - _s.Clear(); - base._observer.OnError(error); - base.Dispose(); + var newWindow = false; + var newId = 0; + + lock (_gate) + { + _s.Add(value); + + _n++; + if (_n == _parent._count) + { + newWindow = true; + _n = 0; + newId = ++_windowId; + + var res = _s; + _s = new List(); + base._observer.OnNext(res); + } + + if (newWindow) + CreateTimer(newId); + } } - } - public void OnCompleted() - { - lock (_gate) + public void OnError(Exception error) { - base._observer.OnNext(_s); - base._observer.OnCompleted(); - base.Dispose(); + lock (_gate) + { + _s.Clear(); + base._observer.OnError(error); + base.Dispose(); + } + } + + public void OnCompleted() + { + lock (_gate) + { + base._observer.OnNext(_s); + base._observer.OnCompleted(); + base.Dispose(); + } } } } } - internal sealed class Buffer : Producer> + internal static class Buffer { - private readonly IObservable _source; - private readonly Func> _bufferClosingSelector; - private readonly IObservable _bufferBoundaries; - - public Buffer(IObservable source, Func> bufferClosingSelector) + internal sealed class Selector : Producer> { - _source = source; - _bufferClosingSelector = bufferClosingSelector; - } + private readonly IObservable _source; + private readonly Func> _bufferClosingSelector; - public Buffer(IObservable source, IObservable bufferBoundaries) - { - _source = source; - _bufferBoundaries = bufferBoundaries; - } - - protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) - { - if (_bufferClosingSelector != null) + public Selector(IObservable source, Func> bufferClosingSelector) { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _bufferClosingSelector = bufferClosingSelector; } - else + + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - var sink = new Beta(this, observer, cancel); + var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } - } - class _ : Sink>, IObserver - { - private readonly Buffer _parent; - - public _(Buffer parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink>, IObserver { - _parent = parent; - } + private readonly object _gate = new object(); + private readonly AsyncLock _bufferGate = new AsyncLock(); + private readonly SerialDisposable _bufferClosingSubscription = new SerialDisposable(); - private IList _buffer; - private object _gate; - private AsyncLock _bufferGate; + private readonly Func> _bufferClosingSelector; - private SerialDisposable _m; + public _(Selector parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + _bufferClosingSelector = parent._bufferClosingSelector; + } - public IDisposable Run() - { - _buffer = new List(); - _gate = new object(); - _bufferGate = new AsyncLock(); + private IList _buffer; - _m = new SerialDisposable(); - var groupDisposable = new CompositeDisposable(2) { _m }; + public IDisposable Run(IObservable source) + { + _buffer = new List(); - groupDisposable.Add(_parent._source.SubscribeSafe(this)); + var groupDisposable = StableCompositeDisposable.Create(_bufferClosingSubscription, source.SubscribeSafe(this)); - _bufferGate.Wait(CreateBufferClose); + _bufferGate.Wait(CreateBufferClose); - return groupDisposable; - } + return groupDisposable; + } - private void CreateBufferClose() - { - var bufferClose = default(IObservable); - try + private void CreateBufferClose() { - bufferClose = _parent._bufferClosingSelector(); + var bufferClose = default(IObservable); + try + { + bufferClose = _bufferClosingSelector(); + } + catch (Exception exception) + { + lock (_gate) + { + base._observer.OnError(exception); + base.Dispose(); + } + return; + } + + var closingSubscription = new SingleAssignmentDisposable(); + _bufferClosingSubscription.Disposable = closingSubscription; + closingSubscription.Disposable = bufferClose.SubscribeSafe(new BufferClosingObserver(this, closingSubscription)); } - catch (Exception exception) + + private void CloseBuffer(IDisposable closingSubscription) { + closingSubscription.Dispose(); + lock (_gate) { - base._observer.OnError(exception); - base.Dispose(); + var res = _buffer; + _buffer = new List(); + base._observer.OnNext(res); } - return; - } - var closingSubscription = new SingleAssignmentDisposable(); - _m.Disposable = closingSubscription; - closingSubscription.Disposable = bufferClose.SubscribeSafe(new Omega(this, closingSubscription)); - } - - private void CloseBuffer(IDisposable closingSubscription) - { - closingSubscription.Dispose(); + _bufferGate.Wait(CreateBufferClose); + } - lock (_gate) + private sealed class BufferClosingObserver : IObserver { - var res = _buffer; - _buffer = new List(); - base._observer.OnNext(res); - } + private readonly _ _parent; + private readonly IDisposable _self; - _bufferGate.Wait(CreateBufferClose); - } + public BufferClosingObserver(_ parent, IDisposable self) + { + _parent = parent; + _self = self; + } - class Omega : IObserver - { - private readonly _ _parent; - private readonly IDisposable _self; + public void OnNext(TBufferClosing value) + { + _parent.CloseBuffer(_self); + } - public Omega(_ parent, IDisposable self) - { - _parent = parent; - _self = self; + public void OnError(Exception error) + { + _parent.OnError(error); + } + + public void OnCompleted() + { + _parent.CloseBuffer(_self); + } } - public void OnNext(TBufferClosing value) + public void OnNext(TSource value) { - _parent.CloseBuffer(_self); + lock (_gate) + { + _buffer.Add(value); + } } public void OnError(Exception error) { - _parent.OnError(error); + lock (_gate) + { + _buffer.Clear(); + base._observer.OnError(error); + base.Dispose(); + } } public void OnCompleted() { - _parent.CloseBuffer(_self); + lock (_gate) + { + base._observer.OnNext(_buffer); + base._observer.OnCompleted(); + base.Dispose(); + } } } + } - public void OnNext(TSource value) + internal sealed class Boundaries : Producer> + { + private readonly IObservable _source; + private readonly IObservable _bufferBoundaries; + + public Boundaries(IObservable source, IObservable bufferBoundaries) { - lock (_gate) - { - _buffer.Add(value); - } + _source = source; + _bufferBoundaries = bufferBoundaries; } - public void OnError(Exception error) + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - lock (_gate) - { - _buffer.Clear(); - base._observer.OnError(error); - base.Dispose(); - } + var sink = new _(observer, cancel); + setSink(sink); + return sink.Run(this); } - public void OnCompleted() + private sealed class _ : Sink>, IObserver { - lock (_gate) + private readonly object _gate = new object(); + + public _(IObserver> observer, IDisposable cancel) + : base(observer, cancel) { - base._observer.OnNext(_buffer); - base._observer.OnCompleted(); - base.Dispose(); } - } - } - - class Beta : Sink>, IObserver - { - private readonly Buffer _parent; - public Beta(Buffer parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) - { - _parent = parent; - } + private IList _buffer; - private IList _buffer; - private object _gate; + public IDisposable Run(Boundaries parent) + { + _buffer = new List(); - private RefCountDisposable _refCountDisposable; + var sourceSubscription = parent._source.SubscribeSafe(this); + var boundariesSubscription = parent._bufferBoundaries.SubscribeSafe(new BufferClosingObserver(this)); - public IDisposable Run() - { - _buffer = new List(); - _gate = new object(); + return StableCompositeDisposable.Create(sourceSubscription, boundariesSubscription); + } - var d = new CompositeDisposable(2); - _refCountDisposable = new RefCountDisposable(d); + private sealed class BufferClosingObserver : IObserver + { + private readonly _ _parent; - d.Add(_parent._source.SubscribeSafe(this)); - d.Add(_parent._bufferBoundaries.SubscribeSafe(new Omega(this))); + public BufferClosingObserver(_ parent) + { + _parent = parent; + } - return _refCountDisposable; - } + public void OnNext(TBufferClosing value) + { + lock (_parent._gate) + { + var res = _parent._buffer; + _parent._buffer = new List(); + _parent._observer.OnNext(res); + } + } - class Omega : IObserver - { - private readonly Beta _parent; + public void OnError(Exception error) + { + _parent.OnError(error); + } - public Omega(Beta parent) - { - _parent = parent; + public void OnCompleted() + { + _parent.OnCompleted(); + } } - public void OnNext(TBufferClosing value) + public void OnNext(TSource value) { - lock (_parent._gate) + lock (_gate) { - var res = _parent._buffer; - _parent._buffer = new List(); - _parent._observer.OnNext(res); + _buffer.Add(value); } } public void OnError(Exception error) { - _parent.OnError(error); + lock (_gate) + { + _buffer.Clear(); + base._observer.OnError(error); + base.Dispose(); + } } public void OnCompleted() { - _parent.OnCompleted(); - } - } - - public void OnNext(TSource value) - { - lock (_gate) - { - _buffer.Add(value); - } - } - - public void OnError(Exception error) - { - lock (_gate) - { - _buffer.Clear(); - base._observer.OnError(error); - base.Dispose(); - } - } - - public void OnCompleted() - { - lock (_gate) - { - base._observer.OnNext(_buffer); - base._observer.OnCompleted(); - base.Dispose(); + lock (_gate) + { + base._observer.OnNext(_buffer); + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs index b47f741bf..43b0a93cd 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs @@ -51,7 +51,7 @@ private static IObservable Amb_(IObservable leftSourc public virtual IObservable> Buffer(IObservable source, Func> bufferClosingSelector) { - return new Buffer(source, bufferClosingSelector); + return new Buffer.Selector(source, bufferClosingSelector); } public virtual IObservable> Buffer(IObservable source, IObservable bufferOpenings, Func> bufferClosingSelector) @@ -61,7 +61,7 @@ public virtual IObservable> Buffer> Buffer(IObservable source, IObservable bufferBoundaries) { - return new Buffer(source, bufferBoundaries); + return new Buffer.Boundaries(source, bufferBoundaries); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs index 155c1ea54..4e08395f0 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs @@ -41,7 +41,7 @@ public virtual IObservable> Buffer(IObservable private static IObservable> Buffer_(IObservable source, int count, int skip) { - return new Buffer(source, count, skip); + return new Buffer.Count(source, count, skip); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index 9e81adb26..7f7da49da 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -19,12 +19,17 @@ internal partial class QueryLanguage public virtual IObservable> Buffer(IObservable source, TimeSpan timeSpan) { - return Buffer_(source, timeSpan, timeSpan, SchedulerDefaults.TimeBasedOperations); + return Buffer_(source, timeSpan, SchedulerDefaults.TimeBasedOperations); } public virtual IObservable> Buffer(IObservable source, TimeSpan timeSpan, IScheduler scheduler) { - return Buffer_(source, timeSpan, timeSpan, scheduler); + return Buffer_(source, timeSpan, scheduler); + } + + private static IObservable> Buffer_(IObservable source, TimeSpan timeSpan, IScheduler scheduler) + { + return new Buffer.TimeHopping(source, timeSpan, scheduler); } public virtual IObservable> Buffer(IObservable source, TimeSpan timeSpan, TimeSpan timeShift) @@ -39,7 +44,7 @@ public virtual IObservable> Buffer(IObservable private static IObservable> Buffer_(IObservable source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler) { - return new Buffer(source, timeSpan, timeShift, scheduler); + return new Buffer.TimeSliding(source, timeSpan, timeShift, scheduler); } #endregion @@ -58,7 +63,7 @@ public virtual IObservable> Buffer(IObservable private static IObservable> Buffer_(IObservable source, TimeSpan timeSpan, int count, IScheduler scheduler) { - return new Buffer(source, timeSpan, count, scheduler); + return new Buffer.Ferry(source, timeSpan, count, scheduler); } #endregion From b28629988e34300d41f00ed0f939f820c08f9887 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 20:42:59 -0700 Subject: [PATCH 88/95] Removing unused usings. --- .../src/System.Reactive/Linq/QueryLanguage.Aggregates.cs | 1 - .../Source/src/System.Reactive/Linq/QueryLanguage.Awaiter.cs | 1 - .../Source/src/System.Reactive/Linq/QueryLanguage.Blocking.cs | 2 -- .../src/System.Reactive/Linq/QueryLanguage.Concurrency.cs | 1 - .../Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs | 4 ---- .../Source/src/System.Reactive/Linq/QueryLanguage.Single.cs | 2 -- 6 files changed, 11 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs index fb761db4f..14b97c0e1 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Aggregates.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; -using System.Reactive.Disposables; namespace System.Reactive.Linq { diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Awaiter.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Awaiter.cs index 4d7c7a4a5..beb571681 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Awaiter.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Awaiter.cs @@ -2,7 +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; using System.Threading; using System.Reactive.Disposables; using System.Reactive.Subjects; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Blocking.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Blocking.cs index 3218e8fad..18a771872 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Blocking.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Blocking.cs @@ -2,10 +2,8 @@ // 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; using System.Collections.Generic; using System.Threading; -using System.Reactive.Disposables; namespace System.Reactive.Linq { diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Concurrency.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Concurrency.cs index 8ac7834b9..4e1d5c3c1 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Concurrency.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Concurrency.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Reactive.Concurrency; -using System.Reactive.Disposables; using System.Threading; namespace System.Reactive.Linq diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs index 43b0a93cd..1f6fdac65 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs @@ -2,13 +2,9 @@ // 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; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Reactive.Concurrency; -using System.Reactive.Disposables; -using System.Reactive.Subjects; using System.Reactive.Threading.Tasks; using System.Threading.Tasks; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs index 4e08395f0..085cd24d0 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs @@ -5,8 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Reactive.Concurrency; -using System.Reactive.Disposables; -using System.Reactive.Subjects; namespace System.Reactive.Linq { From 64481f95db5226b342e5ce68a5d70b7177597033 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 21:29:57 -0700 Subject: [PATCH 89/95] Optimizing layouts of Window. --- .../System.Reactive/Linq/Observable/Window.cs | 1039 +++++++++-------- .../Linq/QueryLanguage.Multiple.cs | 4 +- .../Linq/QueryLanguage.Single.cs | 2 +- .../Linq/QueryLanguage.Time.cs | 13 +- 4 files changed, 544 insertions(+), 514 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Window.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Window.cs index eea76f974..7afa6dae9 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Window.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Window.cs @@ -9,448 +9,444 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Window : Producer> + internal static class Window { - private readonly IObservable _source; - private readonly int _count; - private readonly int _skip; - - private readonly TimeSpan _timeSpan; - private readonly TimeSpan _timeShift; - private readonly IScheduler _scheduler; - - public Window(IObservable source, int count, int skip) - { - _source = source; - _count = count; - _skip = skip; - } - - public Window(IObservable source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler) + internal sealed class Count : Producer> { - _source = source; - _timeSpan = timeSpan; - _timeShift = timeShift; - _scheduler = scheduler; - } + private readonly IObservable _source; + private readonly int _count; + private readonly int _skip; - public Window(IObservable source, TimeSpan timeSpan, int count, IScheduler scheduler) - { - _source = source; - _timeSpan = timeSpan; - _count = count; - _scheduler = scheduler; - } - - protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) - { - if (_scheduler == null) + public Count(IObservable source, int count, int skip) { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _count = count; + _skip = skip; } - else if (_count > 0) + + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - var sink = new BoundedWindowImpl(this, observer, cancel); + var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } - else - { - if (_timeSpan == _timeShift) - { - var sink = new TimeShiftImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - else - { - var sink = new WindowImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - } - } - - class _ : Sink>, IObserver - { - private readonly Window _parent; - public _(Window parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink>, IObserver { - _parent = parent; - } + private readonly Queue> _queue = new Queue>(); + private readonly SingleAssignmentDisposable _m = new SingleAssignmentDisposable(); + private readonly RefCountDisposable _refCountDisposable; - private Queue> _queue; - private int _n; - private SingleAssignmentDisposable _m; - private RefCountDisposable _refCountDisposable; + private readonly int _count; + private readonly int _skip; - public IDisposable Run() - { - _queue = new Queue>(); - _n = 0; - _m = new SingleAssignmentDisposable(); - _refCountDisposable = new RefCountDisposable(_m); + public _(Count parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + _refCountDisposable = new RefCountDisposable(_m); - var firstWindow = CreateWindow(); - base._observer.OnNext(firstWindow); + _count = parent._count; + _skip = parent._skip; + } - _m.Disposable = _parent._source.SubscribeSafe(this); + private int _n; - return _refCountDisposable; - } + public IDisposable Run(IObservable source) + { + _n = 0; - private IObservable CreateWindow() - { - var s = new Subject(); - _queue.Enqueue(s); - return new WindowObservable(s, _refCountDisposable); - } + var firstWindow = CreateWindow(); + base._observer.OnNext(firstWindow); - public void OnNext(TSource value) - { - foreach (var s in _queue) - s.OnNext(value); + _m.Disposable = source.SubscribeSafe(this); - var c = _n - _parent._count + 1; - if (c >= 0 && c % _parent._skip == 0) + return _refCountDisposable; + } + + private IObservable CreateWindow() { - var s = _queue.Dequeue(); - s.OnCompleted(); + var s = new Subject(); + _queue.Enqueue(s); + return new WindowObservable(s, _refCountDisposable); } - _n++; - if (_n % _parent._skip == 0) + public void OnNext(TSource value) { - var newWindow = CreateWindow(); - base._observer.OnNext(newWindow); + foreach (var s in _queue) + s.OnNext(value); + + var c = _n - _count + 1; + if (c >= 0 && c % _skip == 0) + { + var s = _queue.Dequeue(); + s.OnCompleted(); + } + + _n++; + if (_n % _skip == 0) + { + var newWindow = CreateWindow(); + base._observer.OnNext(newWindow); + } } - } - public void OnError(Exception error) - { - while (_queue.Count > 0) - _queue.Dequeue().OnError(error); + public void OnError(Exception error) + { + while (_queue.Count > 0) + _queue.Dequeue().OnError(error); - base._observer.OnError(error); - base.Dispose(); - } + base._observer.OnError(error); + base.Dispose(); + } - public void OnCompleted() - { - while (_queue.Count > 0) - _queue.Dequeue().OnCompleted(); + public void OnCompleted() + { + while (_queue.Count > 0) + _queue.Dequeue().OnCompleted(); - base._observer.OnCompleted(); - base.Dispose(); + base._observer.OnCompleted(); + base.Dispose(); + } } } - class WindowImpl : Sink>, IObserver + internal sealed class TimeSliding : Producer> { - private readonly Window _parent; + private readonly IObservable _source; + private readonly TimeSpan _timeSpan; + private readonly TimeSpan _timeShift; + private readonly IScheduler _scheduler; - public WindowImpl(Window parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + public TimeSliding(IObservable source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler) { - _parent = parent; + _source = source; + _timeSpan = timeSpan; + _timeShift = timeShift; + _scheduler = scheduler; } - private TimeSpan _totalTime; - private TimeSpan _nextShift; - private TimeSpan _nextSpan; - - private object _gate; - private Queue> _q; - - private SerialDisposable _timerD; - private RefCountDisposable _refCountDisposable; + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(this); + } - public IDisposable Run() + private sealed class _ : Sink>, IObserver { - _totalTime = TimeSpan.Zero; - _nextShift = _parent._timeShift; - _nextSpan = _parent._timeSpan; + private readonly object _gate = new object(); + private readonly Queue> _q = new Queue>(); + private readonly SerialDisposable _timerD = new SerialDisposable(); - _gate = new object(); - _q = new Queue>(); + private readonly IScheduler _scheduler; + private readonly TimeSpan _timeShift; - _timerD = new SerialDisposable(); + public _(TimeSliding parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + _scheduler = parent._scheduler; + _timeShift = parent._timeShift; + } - var groupDisposable = new CompositeDisposable(2) { _timerD }; - _refCountDisposable = new RefCountDisposable(groupDisposable); + private RefCountDisposable _refCountDisposable; + private TimeSpan _totalTime; + private TimeSpan _nextShift; + private TimeSpan _nextSpan; - CreateWindow(); - CreateTimer(); + public IDisposable Run(TimeSliding parent) + { + _totalTime = TimeSpan.Zero; + _nextShift = parent._timeShift; + _nextSpan = parent._timeSpan; - groupDisposable.Add(_parent._source.SubscribeSafe(this)); + var groupDisposable = new CompositeDisposable(2) { _timerD }; + _refCountDisposable = new RefCountDisposable(groupDisposable); - return _refCountDisposable; - } + CreateWindow(); + CreateTimer(); - private void CreateWindow() - { - var s = new Subject(); - _q.Enqueue(s); - base._observer.OnNext(new WindowObservable(s, _refCountDisposable)); - } + groupDisposable.Add(parent._source.SubscribeSafe(this)); - private void CreateTimer() - { - var m = new SingleAssignmentDisposable(); - _timerD.Disposable = m; + return _refCountDisposable; + } - var isSpan = false; - var isShift = false; - if (_nextSpan == _nextShift) + private void CreateWindow() { - isSpan = true; - isShift = true; + var s = new Subject(); + _q.Enqueue(s); + base._observer.OnNext(new WindowObservable(s, _refCountDisposable)); } - else if (_nextSpan < _nextShift) - isSpan = true; - else - isShift = true; - var newTotalTime = isSpan ? _nextSpan : _nextShift; - var ts = newTotalTime - _totalTime; - _totalTime = newTotalTime; + private void CreateTimer() + { + var m = new SingleAssignmentDisposable(); + _timerD.Disposable = m; - if (isSpan) - _nextSpan += _parent._timeShift; - if (isShift) - _nextShift += _parent._timeShift; + var isSpan = false; + var isShift = false; + if (_nextSpan == _nextShift) + { + isSpan = true; + isShift = true; + } + else if (_nextSpan < _nextShift) + isSpan = true; + else + isShift = true; - m.Disposable = _parent._scheduler.Schedule(new State { isSpan = isSpan, isShift = isShift }, ts, Tick); - } + var newTotalTime = isSpan ? _nextSpan : _nextShift; + var ts = newTotalTime - _totalTime; + _totalTime = newTotalTime; - struct State - { - public bool isSpan; - public bool isShift; - } + if (isSpan) + _nextSpan += _timeShift; + if (isShift) + _nextShift += _timeShift; - private IDisposable Tick(IScheduler self, State state) - { - lock (_gate) + m.Disposable = _scheduler.Schedule(new State { isSpan = isSpan, isShift = isShift }, ts, Tick); + } + + struct State { - // - // BREAKING CHANGE v2 > v1.x - Making behavior of sending OnCompleted to the window - // before sending out a new window consistent across all - // overloads of Window and Buffer. Before v2, the two - // operations below were reversed. - // - if (state.isSpan) - { - var s = _q.Dequeue(); - s.OnCompleted(); - } + public bool isSpan; + public bool isShift; + } - if (state.isShift) + private IDisposable Tick(IScheduler self, State state) + { + lock (_gate) { - CreateWindow(); + // + // BREAKING CHANGE v2 > v1.x - Making behavior of sending OnCompleted to the window + // before sending out a new window consistent across all + // overloads of Window and Buffer. Before v2, the two + // operations below were reversed. + // + if (state.isSpan) + { + var s = _q.Dequeue(); + s.OnCompleted(); + } + + if (state.isShift) + { + CreateWindow(); + } } - } - CreateTimer(); + CreateTimer(); - return Disposable.Empty; - } + return Disposable.Empty; + } - public void OnNext(TSource value) - { - lock (_gate) + public void OnNext(TSource value) { - foreach (var s in _q) - s.OnNext(value); + lock (_gate) + { + foreach (var s in _q) + s.OnNext(value); + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { - foreach (var s in _q) - s.OnError(error); + lock (_gate) + { + foreach (var s in _q) + s.OnError(error); - base._observer.OnError(error); - base.Dispose(); + base._observer.OnError(error); + base.Dispose(); + } } - } - public void OnCompleted() - { - lock (_gate) + public void OnCompleted() { - foreach (var s in _q) - s.OnCompleted(); + lock (_gate) + { + foreach (var s in _q) + s.OnCompleted(); - base._observer.OnCompleted(); - base.Dispose(); + base._observer.OnCompleted(); + base.Dispose(); + } } } } - class TimeShiftImpl : Sink>, IObserver + internal sealed class TimeHopping : Producer> { - private readonly Window _parent; + private readonly IObservable _source; + private readonly TimeSpan _timeSpan; + private readonly IScheduler _scheduler; - public TimeShiftImpl(Window parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + public TimeHopping(IObservable source, TimeSpan timeSpan, IScheduler scheduler) { - _parent = parent; + _source = source; + _timeSpan = timeSpan; + _scheduler = scheduler; } - private object _gate; - private Subject _subject; - private RefCountDisposable _refCountDisposable; + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) + { + var sink = new _(observer, cancel); + setSink(sink); + return sink.Run(this); + } - public IDisposable Run() + private sealed class _ : Sink>, IObserver { - _gate = new object(); + private readonly object _gate = new object(); + + public _(IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + } - var groupDisposable = new CompositeDisposable(2); - _refCountDisposable = new RefCountDisposable(groupDisposable); + private Subject _subject; + private RefCountDisposable _refCountDisposable; - CreateWindow(); + public IDisposable Run(TimeHopping parent) + { + var groupDisposable = new CompositeDisposable(2); + _refCountDisposable = new RefCountDisposable(groupDisposable); - groupDisposable.Add(_parent._scheduler.SchedulePeriodic(_parent._timeSpan, Tick)); - groupDisposable.Add(_parent._source.SubscribeSafe(this)); + CreateWindow(); - return _refCountDisposable; - } + groupDisposable.Add(parent._scheduler.SchedulePeriodic(parent._timeSpan, Tick)); + groupDisposable.Add(parent._source.SubscribeSafe(this)); - private void Tick() - { - lock (_gate) + return _refCountDisposable; + } + + private void Tick() { - _subject.OnCompleted(); - CreateWindow(); + lock (_gate) + { + _subject.OnCompleted(); + CreateWindow(); + } } - } - private void CreateWindow() - { - _subject = new Subject(); - base._observer.OnNext(new WindowObservable(_subject, _refCountDisposable)); - } + private void CreateWindow() + { + _subject = new Subject(); + base._observer.OnNext(new WindowObservable(_subject, _refCountDisposable)); + } - public void OnNext(TSource value) - { - lock (_gate) + public void OnNext(TSource value) { - _subject.OnNext(value); + lock (_gate) + { + _subject.OnNext(value); + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { - _subject.OnError(error); + lock (_gate) + { + _subject.OnError(error); - base._observer.OnError(error); - base.Dispose(); + base._observer.OnError(error); + base.Dispose(); + } } - } - public void OnCompleted() - { - lock (_gate) + public void OnCompleted() { - _subject.OnCompleted(); + lock (_gate) + { + _subject.OnCompleted(); - base._observer.OnCompleted(); - base.Dispose(); + base._observer.OnCompleted(); + base.Dispose(); + } } } } - class BoundedWindowImpl : Sink>, IObserver + internal sealed class Ferry : Producer> { - private readonly Window _parent; + private readonly IObservable _source; + private readonly int _count; + private readonly TimeSpan _timeSpan; + private readonly IScheduler _scheduler; - public BoundedWindowImpl(Window parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + public Ferry(IObservable source, TimeSpan timeSpan, int count, IScheduler scheduler) { - _parent = parent; + _source = source; + _timeSpan = timeSpan; + _count = count; + _scheduler = scheduler; } - private object _gate; - private ISubject _s; - private int _n; - private int _windowId; - - private SerialDisposable _timerD; - private RefCountDisposable _refCountDisposable; - - public IDisposable Run() + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - _gate = new object(); - _s = default(ISubject); - _n = 0; - _windowId = 0; - - _timerD = new SerialDisposable(); - var groupDisposable = new CompositeDisposable(2) { _timerD }; - _refCountDisposable = new RefCountDisposable(groupDisposable); - - _s = new Subject(); - base._observer.OnNext(new WindowObservable(_s, _refCountDisposable)); - CreateTimer(0); - - groupDisposable.Add(_parent._source.SubscribeSafe(this)); - - return _refCountDisposable; + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(_source); } - private void CreateTimer(int id) + private sealed class _ : Sink>, IObserver { - var m = new SingleAssignmentDisposable(); - _timerD.Disposable = m; - - m.Disposable = _parent._scheduler.Schedule(id, _parent._timeSpan, Tick); - } + private readonly object _gate = new object(); + private readonly SerialDisposable _timerD = new SerialDisposable(); - private IDisposable Tick(IScheduler self, int id) - { - var d = Disposable.Empty; + private readonly int _count; + private readonly TimeSpan _timeSpan; + private readonly IScheduler _scheduler; - var newId = 0; - lock (_gate) + public _(Ferry parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) { - if (id != _windowId) - return d; + _count = parent._count; + _timeSpan = parent._timeSpan; + _scheduler = parent._scheduler; + } + + private ISubject _s; + private int _n; + private int _windowId; + + private RefCountDisposable _refCountDisposable; + public IDisposable Run(IObservable source) + { + _s = default(ISubject); _n = 0; - newId = ++_windowId; + _windowId = 0; + + var groupDisposable = new CompositeDisposable(2) { _timerD }; + _refCountDisposable = new RefCountDisposable(groupDisposable); - _s.OnCompleted(); _s = new Subject(); base._observer.OnNext(new WindowObservable(_s, _refCountDisposable)); - } + CreateTimer(0); - CreateTimer(newId); + groupDisposable.Add(source.SubscribeSafe(this)); - return d; - } + return _refCountDisposable; + } - public void OnNext(TSource value) - { - var newWindow = false; - var newId = 0; + private void CreateTimer(int id) + { + var m = new SingleAssignmentDisposable(); + _timerD.Disposable = m; + + m.Disposable = _scheduler.Schedule(id, _timeSpan, Tick); + } - lock (_gate) + private IDisposable Tick(IScheduler self, int id) { - _s.OnNext(value); + var d = Disposable.Empty; - _n++; - if (_n == _parent._count) + var newId = 0; + lock (_gate) { - newWindow = true; + if (id != _windowId) + return d; + _n = 0; newId = ++_windowId; @@ -458,288 +454,317 @@ public void OnNext(TSource value) _s = new Subject(); base._observer.OnNext(new WindowObservable(_s, _refCountDisposable)); } - } - if (newWindow) CreateTimer(newId); - } - public void OnError(Exception error) - { - lock (_gate) + return d; + } + + public void OnNext(TSource value) { - _s.OnError(error); - base._observer.OnError(error); - base.Dispose(); + var newWindow = false; + var newId = 0; + + lock (_gate) + { + _s.OnNext(value); + + _n++; + if (_n == _count) + { + newWindow = true; + _n = 0; + newId = ++_windowId; + + _s.OnCompleted(); + _s = new Subject(); + base._observer.OnNext(new WindowObservable(_s, _refCountDisposable)); + } + } + + if (newWindow) + CreateTimer(newId); } - } - public void OnCompleted() - { - lock (_gate) + public void OnError(Exception error) { - _s.OnCompleted(); - base._observer.OnCompleted(); - base.Dispose(); + lock (_gate) + { + _s.OnError(error); + base._observer.OnError(error); + base.Dispose(); + } + } + + public void OnCompleted() + { + lock (_gate) + { + _s.OnCompleted(); + base._observer.OnCompleted(); + base.Dispose(); + } } } } } - internal sealed class Window : Producer> + internal static class Window { - private readonly IObservable _source; - private readonly Func> _windowClosingSelector; - private readonly IObservable _windowBoundaries; - - public Window(IObservable source, Func> windowClosingSelector) + internal sealed class Selector : Producer> { - _source = source; - _windowClosingSelector = windowClosingSelector; - } + private readonly IObservable _source; + private readonly Func> _windowClosingSelector; - public Window(IObservable source, IObservable windowBoundaries) - { - _source = source; - _windowBoundaries = windowBoundaries; - } - - protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) - { - if (_windowClosingSelector != null) + public Selector(IObservable source, Func> windowClosingSelector) { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _windowClosingSelector = windowClosingSelector; } - else + + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - var sink = new Beta(this, observer, cancel); + var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(_source); } - } - - class _ : Sink>, IObserver - { - private readonly Window _parent; - public _(Window parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink>, IObserver { - _parent = parent; - } + private readonly object _gate = new object(); + private readonly AsyncLock _windowGate = new AsyncLock(); + private readonly SerialDisposable _m = new SerialDisposable(); - private ISubject _window; - private object _gate; - private AsyncLock _windowGate; + private readonly Func> _windowClosingSelector; - private SerialDisposable _m; - private RefCountDisposable _refCountDisposable; + public _(Selector parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + _windowClosingSelector = parent._windowClosingSelector; + } - public IDisposable Run() - { - _window = new Subject(); - _gate = new object(); - _windowGate = new AsyncLock(); + private ISubject _window; + private RefCountDisposable _refCountDisposable; - _m = new SerialDisposable(); - var groupDisposable = new CompositeDisposable(2) { _m }; - _refCountDisposable = new RefCountDisposable(groupDisposable); + public IDisposable Run(IObservable source) + { + _window = new Subject(); - var window = new WindowObservable(_window, _refCountDisposable); - base._observer.OnNext(window); + var groupDisposable = new CompositeDisposable(2) { _m }; + _refCountDisposable = new RefCountDisposable(groupDisposable); - groupDisposable.Add(_parent._source.SubscribeSafe(this)); + var window = new WindowObservable(_window, _refCountDisposable); + base._observer.OnNext(window); - _windowGate.Wait(CreateWindowClose); + groupDisposable.Add(source.SubscribeSafe(this)); - return _refCountDisposable; - } + _windowGate.Wait(CreateWindowClose); - private void CreateWindowClose() - { - var windowClose = default(IObservable); - try - { - windowClose = _parent._windowClosingSelector(); + return _refCountDisposable; } - catch (Exception exception) + + private void CreateWindowClose() { - lock (_gate) + var windowClose = default(IObservable); + try { - base._observer.OnError(exception); - base.Dispose(); + windowClose = _windowClosingSelector(); } - return; + catch (Exception exception) + { + lock (_gate) + { + base._observer.OnError(exception); + base.Dispose(); + } + return; + } + + var closingSubscription = new SingleAssignmentDisposable(); + _m.Disposable = closingSubscription; + closingSubscription.Disposable = windowClose.SubscribeSafe(new WindowClosingObserver(this, closingSubscription)); } - var closingSubscription = new SingleAssignmentDisposable(); - _m.Disposable = closingSubscription; - closingSubscription.Disposable = windowClose.SubscribeSafe(new Omega(this, closingSubscription)); - } + private void CloseWindow(IDisposable closingSubscription) + { + closingSubscription.Dispose(); - private void CloseWindow(IDisposable closingSubscription) - { - closingSubscription.Dispose(); + lock (_gate) + { + _window.OnCompleted(); + _window = new Subject(); - lock (_gate) - { - _window.OnCompleted(); - _window = new Subject(); + var window = new WindowObservable(_window, _refCountDisposable); + base._observer.OnNext(window); + } - var window = new WindowObservable(_window, _refCountDisposable); - base._observer.OnNext(window); + _windowGate.Wait(CreateWindowClose); } - _windowGate.Wait(CreateWindowClose); - } + private sealed class WindowClosingObserver : IObserver + { + private readonly _ _parent; + private readonly IDisposable _self; - class Omega : IObserver - { - private readonly _ _parent; - private readonly IDisposable _self; + public WindowClosingObserver(_ parent, IDisposable self) + { + _parent = parent; + _self = self; + } - public Omega(_ parent, IDisposable self) - { - _parent = parent; - _self = self; + public void OnNext(TWindowClosing value) + { + _parent.CloseWindow(_self); + } + + public void OnError(Exception error) + { + _parent.OnError(error); + } + + public void OnCompleted() + { + _parent.CloseWindow(_self); + } } - public void OnNext(TWindowClosing value) + public void OnNext(TSource value) { - _parent.CloseWindow(_self); + lock (_gate) + { + _window.OnNext(value); + } } public void OnError(Exception error) { - _parent.OnError(error); + lock (_gate) + { + _window.OnError(error); + base._observer.OnError(error); + base.Dispose(); + } } public void OnCompleted() { - _parent.CloseWindow(_self); + lock (_gate) + { + _window.OnCompleted(); + base._observer.OnCompleted(); + base.Dispose(); + } } } + } - public void OnNext(TSource value) - { - lock (_gate) - { - _window.OnNext(value); - } - } + internal sealed class Boundaries : Producer> + { + private readonly IObservable _source; + private readonly IObservable _windowBoundaries; - public void OnError(Exception error) + public Boundaries(IObservable source, IObservable windowBoundaries) { - lock (_gate) - { - _window.OnError(error); - base._observer.OnError(error); - base.Dispose(); - } + _source = source; + _windowBoundaries = windowBoundaries; } - public void OnCompleted() + protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - lock (_gate) - { - _window.OnCompleted(); - base._observer.OnCompleted(); - base.Dispose(); - } + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(this); } - } - - class Beta : Sink>, IObserver - { - private readonly Window _parent; - public Beta(Window parent, IObserver> observer, IDisposable cancel) - : base(observer, cancel) + private sealed class _ : Sink>, IObserver { - _parent = parent; - } - - private ISubject _window; - private object _gate; + private readonly object _gate = new object(); - private RefCountDisposable _refCountDisposable; + private readonly IObservable _windowBoundaries; - public IDisposable Run() - { - _window = new Subject(); - _gate = new object(); + public _(Boundaries parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + _windowBoundaries = parent._windowBoundaries; + } - var d = new CompositeDisposable(2); - _refCountDisposable = new RefCountDisposable(d); + private ISubject _window; + private RefCountDisposable _refCountDisposable; - var window = new WindowObservable(_window, _refCountDisposable); - base._observer.OnNext(window); + public IDisposable Run(Boundaries parent) + { + _window = new Subject(); - d.Add(_parent._source.SubscribeSafe(this)); - d.Add(_parent._windowBoundaries.SubscribeSafe(new Omega(this))); + var d = new CompositeDisposable(2); + _refCountDisposable = new RefCountDisposable(d); - return _refCountDisposable; - } + var window = new WindowObservable(_window, _refCountDisposable); + base._observer.OnNext(window); - class Omega : IObserver - { - private readonly Beta _parent; + d.Add(parent._source.SubscribeSafe(this)); + d.Add(parent._windowBoundaries.SubscribeSafe(new WindowClosingObserver(this))); - public Omega(Beta parent) - { - _parent = parent; + return _refCountDisposable; } - public void OnNext(TWindowClosing value) + private sealed class WindowClosingObserver : IObserver { - lock (_parent._gate) + private readonly _ _parent; + + public WindowClosingObserver(_ parent) { - _parent._window.OnCompleted(); - _parent._window = new Subject(); + _parent = parent; + } - var window = new WindowObservable(_parent._window, _parent._refCountDisposable); - _parent._observer.OnNext(window); + public void OnNext(TWindowClosing value) + { + lock (_parent._gate) + { + _parent._window.OnCompleted(); + _parent._window = new Subject(); + + var window = new WindowObservable(_parent._window, _parent._refCountDisposable); + _parent._observer.OnNext(window); + } } - } - public void OnError(Exception error) - { - _parent.OnError(error); - } + public void OnError(Exception error) + { + _parent.OnError(error); + } - public void OnCompleted() - { - _parent.OnCompleted(); + public void OnCompleted() + { + _parent.OnCompleted(); + } } - } - public void OnNext(TSource value) - { - lock (_gate) + public void OnNext(TSource value) { - _window.OnNext(value); + lock (_gate) + { + _window.OnNext(value); + } } - } - public void OnError(Exception error) - { - lock (_gate) + public void OnError(Exception error) { - _window.OnError(error); - base._observer.OnError(error); - base.Dispose(); + lock (_gate) + { + _window.OnError(error); + base._observer.OnError(error); + base.Dispose(); + } } - } - public void OnCompleted() - { - lock (_gate) + public void OnCompleted() { - _window.OnCompleted(); - base._observer.OnCompleted(); - base.Dispose(); + lock (_gate) + { + _window.OnCompleted(); + base._observer.OnCompleted(); + base.Dispose(); + } } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs index 1f6fdac65..7d42abf25 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.cs @@ -369,7 +369,7 @@ public virtual IObservable TakeUntil(IObservable> Window(IObservable source, Func> windowClosingSelector) { - return new Window(source, windowClosingSelector); + return new Window.Selector(source, windowClosingSelector); } public virtual IObservable> Window(IObservable source, IObservable windowOpenings, Func> windowClosingSelector) @@ -379,7 +379,7 @@ public virtual IObservable> Window> Window(IObservable source, IObservable windowBoundaries) { - return new Window(source, windowBoundaries); + return new Window.Boundaries(source, windowBoundaries); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs index 085cd24d0..3a4292b25 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Single.cs @@ -294,7 +294,7 @@ public virtual IObservable> Window(IObservable> Window_(IObservable source, int count, int skip) { - return new Window(source, count, skip); + return new Window.Count(source, count, skip); } #endregion diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index 7f7da49da..801eff9e1 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -615,12 +615,17 @@ private static IObservable> Timestamp_(IObservable public virtual IObservable> Window(IObservable source, TimeSpan timeSpan) { - return Window_(source, timeSpan, timeSpan, SchedulerDefaults.TimeBasedOperations); + return Window_(source, timeSpan, SchedulerDefaults.TimeBasedOperations); } public virtual IObservable> Window(IObservable source, TimeSpan timeSpan, IScheduler scheduler) { - return Window_(source, timeSpan, timeSpan, scheduler); + return Window_(source, timeSpan, scheduler); + } + + private static IObservable> Window_(IObservable source, TimeSpan timeSpan, IScheduler scheduler) + { + return new Window.TimeHopping(source, timeSpan, scheduler); } public virtual IObservable> Window(IObservable source, TimeSpan timeSpan, TimeSpan timeShift) @@ -635,7 +640,7 @@ public virtual IObservable> Window(IObservable> Window_(IObservable source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler) { - return new Window(source, timeSpan, timeShift, scheduler); + return new Window.TimeSliding(source, timeSpan, timeShift, scheduler); } #endregion @@ -654,7 +659,7 @@ public virtual IObservable> Window(IObservable> Window_(IObservable source, TimeSpan timeSpan, int count, IScheduler scheduler) { - return new Window(source, timeSpan, count, scheduler); + return new Window.Ferry(source, timeSpan, count, scheduler); } #endregion From b6a710081cce45dc84dbf04914cd063ec8737270 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 22:03:28 -0700 Subject: [PATCH 90/95] Further reduction of Window layout. --- .../System.Reactive/Linq/Observable/Window.cs | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Window.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Window.cs index 7afa6dae9..f54119c7c 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Window.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Window.cs @@ -405,65 +405,61 @@ public _(Ferry parent, IObserver> observer, IDisposable can _scheduler = parent._scheduler; } - private ISubject _s; + private Subject _s; private int _n; - private int _windowId; private RefCountDisposable _refCountDisposable; public IDisposable Run(IObservable source) { - _s = default(ISubject); _n = 0; - _windowId = 0; var groupDisposable = new CompositeDisposable(2) { _timerD }; _refCountDisposable = new RefCountDisposable(groupDisposable); _s = new Subject(); base._observer.OnNext(new WindowObservable(_s, _refCountDisposable)); - CreateTimer(0); + CreateTimer(_s); groupDisposable.Add(source.SubscribeSafe(this)); return _refCountDisposable; } - private void CreateTimer(int id) + private void CreateTimer(Subject window) { var m = new SingleAssignmentDisposable(); _timerD.Disposable = m; - m.Disposable = _scheduler.Schedule(id, _timeSpan, Tick); + m.Disposable = _scheduler.Schedule(window, _timeSpan, Tick); } - private IDisposable Tick(IScheduler self, int id) + private IDisposable Tick(IScheduler self, Subject window) { var d = Disposable.Empty; - var newId = 0; + var newWindow = default(Subject); lock (_gate) { - if (id != _windowId) + if (window != _s) return d; _n = 0; - newId = ++_windowId; + newWindow = new Subject(); _s.OnCompleted(); - _s = new Subject(); + _s = newWindow; base._observer.OnNext(new WindowObservable(_s, _refCountDisposable)); } - CreateTimer(newId); + CreateTimer(newWindow); return d; } public void OnNext(TSource value) { - var newWindow = false; - var newId = 0; + var newWindow = default(Subject); lock (_gate) { @@ -472,18 +468,17 @@ public void OnNext(TSource value) _n++; if (_n == _count) { - newWindow = true; _n = 0; - newId = ++_windowId; + newWindow = new Subject(); _s.OnCompleted(); - _s = new Subject(); + _s = newWindow; base._observer.OnNext(new WindowObservable(_s, _refCountDisposable)); } } - if (newWindow) - CreateTimer(newId); + if (newWindow != null) + CreateTimer(newWindow); } public void OnError(Exception error) From 28a0d6e7dd259fd6e9f75bab2730ce9fc4dc9660 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 22:04:23 -0700 Subject: [PATCH 91/95] Sealing the sink for Distinct. --- Rx.NET/Source/src/System.Reactive/Linq/Observable/Distinct.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Distinct.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Distinct.cs index ea0c07954..392ecb00c 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Distinct.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Distinct.cs @@ -26,7 +26,7 @@ protected override IDisposable Run(IObserver observer, IDisposable canc return _source.SubscribeSafe(sink); } - class _ : Sink, IObserver + private sealed class _ : Sink, IObserver { private readonly Func _keySelector; private HashSet _hashSet; From 1881892886c4c8303c2579a02a198a117ee50524 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 22:24:29 -0700 Subject: [PATCH 92/95] Optimizing layouts of GroupJoin and Join. --- .../Linq/Observable/GroupJoin.cs | 63 ++++++++++--------- .../System.Reactive/Linq/Observable/Join.cs | 39 ++++++------ 2 files changed, 50 insertions(+), 52 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupJoin.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupJoin.cs index 54d2c3c39..fbca0dd73 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupJoin.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupJoin.cs @@ -29,52 +29,53 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } - class _ : Sink + private sealed class _ : Sink { - private readonly GroupJoin _parent; + private readonly object _gate = new object(); + private readonly CompositeDisposable _group = new CompositeDisposable(); + private readonly RefCountDisposable _refCount; + private readonly SortedDictionary> _leftMap = new SortedDictionary>(); + private readonly SortedDictionary _rightMap = new SortedDictionary(); + + private readonly Func> _leftDurationSelector; + private readonly Func> _rightDurationSelector; + private readonly Func, TResult> _resultSelector; public _(GroupJoin parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - } + _refCount = new RefCountDisposable(_group); + _leftMap = new SortedDictionary>(); + _rightMap = new SortedDictionary(); - private object _gate; - private CompositeDisposable _group; - private RefCountDisposable _refCount; + _leftDurationSelector = parent._leftDurationSelector; + _rightDurationSelector = parent._rightDurationSelector; + _resultSelector = parent._resultSelector; + } private int _leftID; - private SortedDictionary> _leftMap; - private int _rightID; - private SortedDictionary _rightMap; - public IDisposable Run() + public IDisposable Run(GroupJoin parent) { - _gate = new object(); - _group = new CompositeDisposable(); - _refCount = new RefCountDisposable(_group); - var leftSubscription = new SingleAssignmentDisposable(); _group.Add(leftSubscription); _leftID = 0; - _leftMap = new SortedDictionary>(); var rightSubscription = new SingleAssignmentDisposable(); _group.Add(rightSubscription); _rightID = 0; - _rightMap = new SortedDictionary(); - leftSubscription.Disposable = _parent._left.SubscribeSafe(new LeftObserver(this, leftSubscription)); - rightSubscription.Disposable = _parent._right.SubscribeSafe(new RightObserver(this, rightSubscription)); + leftSubscription.Disposable = parent._left.SubscribeSafe(new LeftObserver(this, leftSubscription)); + rightSubscription.Disposable = parent._right.SubscribeSafe(new RightObserver(this, rightSubscription)); return _refCount; } - class LeftObserver : IObserver + private sealed class LeftObserver : IObserver { private readonly _ _parent; private readonly IDisposable _self; @@ -119,7 +120,7 @@ public void OnNext(TLeft value) var duration = default(IObservable); try { - duration = _parent._parent._leftDurationSelector(value); + duration = _parent._leftDurationSelector(value); } catch (Exception exception) { @@ -128,12 +129,12 @@ public void OnNext(TLeft value) } // BREAKING CHANGE v2 > v1.x - The duration sequence is subscribed to before the result sequence is evaluated. - md.Disposable = duration.SubscribeSafe(new Delta(this, id, s, md)); + md.Disposable = duration.SubscribeSafe(new DurationObserver(this, id, s, md)); var result = default(TResult); try { - result = _parent._parent._resultSelector(value, window); + result = _parent._resultSelector(value, window); } catch (Exception exception) { @@ -155,14 +156,14 @@ public void OnNext(TLeft value) } } - class Delta : IObserver + private sealed class DurationObserver : IObserver { private readonly LeftObserver _parent; private readonly int _id; private readonly IObserver _group; private readonly IDisposable _self; - public Delta(LeftObserver parent, int id, IObserver group, IDisposable self) + public DurationObserver(LeftObserver parent, int id, IObserver group, IDisposable self) { _parent = parent; _id = id; @@ -212,7 +213,7 @@ public void OnCompleted() } } - class RightObserver : IObserver + private sealed class RightObserver : IObserver { private readonly _ _parent; private readonly IDisposable _self; @@ -250,7 +251,7 @@ public void OnNext(TRight value) var duration = default(IObservable); try { - duration = _parent._parent._rightDurationSelector(value); + duration = _parent._rightDurationSelector(value); } catch (Exception exception) { @@ -258,7 +259,7 @@ public void OnNext(TRight value) return; } - md.Disposable = duration.SubscribeSafe(new Delta(this, id, md)); + md.Disposable = duration.SubscribeSafe(new DurationObserver(this, id, md)); lock (_parent._gate) { @@ -272,13 +273,13 @@ public void OnNext(TRight value) } } - class Delta : IObserver + private sealed class DurationObserver : IObserver { private readonly RightObserver _parent; private readonly int _id; private readonly IDisposable _self; - public Delta(RightObserver parent, int id, IDisposable self) + public DurationObserver(RightObserver parent, int id, IDisposable self) { _parent = parent; _id = id; diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Join.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Join.cs index 3723cdd9e..cb2ee58aa 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Join.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Join.cs @@ -28,51 +28,48 @@ protected override IDisposable Run(IObserver observer, IDisposable canc { var sink = new _(this, observer, cancel); setSink(sink); - return sink.Run(); + return sink.Run(this); } private sealed class _ : Sink { - // CONSIDER: This sink has a parent reference that can be considered for removal. + private readonly object _gate = new object(); + private readonly CompositeDisposable _group = new CompositeDisposable(); + private readonly SortedDictionary _leftMap = new SortedDictionary(); + private readonly SortedDictionary _rightMap = new SortedDictionary(); - private readonly Join _parent; + private readonly Func> _leftDurationSelector; + private readonly Func> _rightDurationSelector; + private readonly Func _resultSelector; public _(Join parent, IObserver observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _leftDurationSelector = parent._leftDurationSelector; + _rightDurationSelector = parent._rightDurationSelector; + _resultSelector = parent._resultSelector; } - private object _gate; - private CompositeDisposable _group; - private bool _leftDone; private int _leftID; - private SortedDictionary _leftMap; private bool _rightDone; private int _rightID; - private SortedDictionary _rightMap; - public IDisposable Run() + public IDisposable Run(Join parent) { - _gate = new object(); - _group = new CompositeDisposable(); - var leftSubscription = new SingleAssignmentDisposable(); _group.Add(leftSubscription); _leftDone = false; _leftID = 0; - _leftMap = new SortedDictionary(); var rightSubscription = new SingleAssignmentDisposable(); _group.Add(rightSubscription); _rightDone = false; _rightID = 0; - _rightMap = new SortedDictionary(); - leftSubscription.Disposable = _parent._left.SubscribeSafe(new LeftObserver(this, leftSubscription)); - rightSubscription.Disposable = _parent._right.SubscribeSafe(new RightObserver(this, rightSubscription)); + leftSubscription.Disposable = parent._left.SubscribeSafe(new LeftObserver(this, leftSubscription)); + rightSubscription.Disposable = parent._right.SubscribeSafe(new RightObserver(this, rightSubscription)); return _group; } @@ -119,7 +116,7 @@ public void OnNext(TLeft value) var duration = default(IObservable); try { - duration = _parent._parent._leftDurationSelector(value); + duration = _parent._leftDurationSelector(value); } catch (Exception exception) { @@ -139,7 +136,7 @@ public void OnNext(TLeft value) var result = default(TResult); try { - result = _parent._parent._resultSelector(value, rightValue.Value); + result = _parent._resultSelector(value, rightValue.Value); } catch (Exception exception) { @@ -252,7 +249,7 @@ public void OnNext(TRight value) var duration = default(IObservable); try { - duration = _parent._parent._rightDurationSelector(value); + duration = _parent._rightDurationSelector(value); } catch (Exception exception) { @@ -272,7 +269,7 @@ public void OnNext(TRight value) var result = default(TResult); try { - result = _parent._parent._resultSelector(leftValue.Value, value); + result = _parent._resultSelector(leftValue.Value, value); } catch (Exception exception) { From f70ed17d38e182375c2b0fa236c0d918f76faf3d Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Tue, 18 Apr 2017 22:53:24 -0700 Subject: [PATCH 93/95] Optimizing GroupBy[Until] operator layouts. --- .../System.Reactive/Linq/GroupedObservable.cs | 12 +-- .../Linq/Observable/GroupBy.cs | 52 ++++++------ .../Linq/Observable/GroupByUntil.cs | 82 +++++++++---------- 3 files changed, 71 insertions(+), 75 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/GroupedObservable.cs b/Rx.NET/Source/src/System.Reactive/Linq/GroupedObservable.cs index 8bcdf4662..146ae370c 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/GroupedObservable.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/GroupedObservable.cs @@ -7,29 +7,25 @@ namespace System.Reactive.Linq { - class GroupedObservable : ObservableBase, IGroupedObservable + internal sealed class GroupedObservable : ObservableBase, IGroupedObservable { - private readonly TKey _key; private readonly IObservable _subject; private readonly RefCountDisposable _refCount; public GroupedObservable(TKey key, ISubject subject, RefCountDisposable refCount) { - _key = key; + Key = key; _subject = subject; _refCount = refCount; } public GroupedObservable(TKey key, ISubject subject) { - _key = key; + Key = key; _subject = subject; } - public TKey Key - { - get { return _key; } - } + public TKey Key { get; } protected override IDisposable SubscribeCore(IObserver observer) { diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupBy.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupBy.cs index fce92ec7f..460756705 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupBy.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupBy.cs @@ -25,48 +25,52 @@ public GroupBy(IObservable source, Func keySelector, Fun _comparer = comparer; } - private CompositeDisposable _groupDisposable; - private RefCountDisposable _refCountDisposable; - protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - _groupDisposable = new CompositeDisposable(); - _refCountDisposable = new RefCountDisposable(_groupDisposable); - var sink = new _(this, observer, cancel); setSink(sink); - _groupDisposable.Add(_source.SubscribeSafe(sink)); - - return _refCountDisposable; + return sink.Run(_source); } - class _ : Sink>, IObserver + private sealed class _ : Sink>, IObserver { - private readonly GroupBy _parent; - private readonly Dictionary> _map; - private ISubject _null; + private readonly Func _keySelector; + private readonly Func _elementSelector; + private readonly Dictionary> _map; + + private RefCountDisposable _refCountDisposable; + private Subject _null; public _(GroupBy parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; + _keySelector = parent._keySelector; + _elementSelector = parent._elementSelector; - if (_parent._capacity.HasValue) + if (parent._capacity.HasValue) { - _map = new Dictionary>(_parent._capacity.Value, _parent._comparer); + _map = new Dictionary>(parent._capacity.Value, parent._comparer); } else { - _map = new Dictionary>(_parent._comparer); + _map = new Dictionary>(parent._comparer); } } + public IDisposable Run(IObservable source) + { + var sourceSubscription = new SingleAssignmentDisposable(); + _refCountDisposable = new RefCountDisposable(sourceSubscription); + sourceSubscription.Disposable = source.SubscribeSafe(this); + return _refCountDisposable; + } + public void OnNext(TSource value) { var key = default(TKey); try { - key = _parent._keySelector(value); + key = _keySelector(value); } catch (Exception exception) { @@ -75,7 +79,7 @@ public void OnNext(TSource value) } var fireNewMapEntry = false; - var writer = default(ISubject); + var writer = default(Subject); try { // @@ -124,14 +128,14 @@ public void OnNext(TSource value) if (fireNewMapEntry) { - var group = new GroupedObservable(key, writer, _parent._refCountDisposable); + var group = new GroupedObservable(key, writer, _refCountDisposable); _observer.OnNext(group); } var element = default(TElement); try { - element = _parent._elementSelector(value); + element = _elementSelector(value); } catch (Exception exception) { @@ -149,8 +153,7 @@ public void OnError(Exception error) public void OnCompleted() { - if (_null != null) - _null.OnCompleted(); + _null?.OnCompleted(); foreach (var w in _map.Values) w.OnCompleted(); @@ -161,8 +164,7 @@ public void OnCompleted() private void Error(Exception exception) { - if (_null != null) - _null.OnError(exception); + _null?.OnError(exception); foreach (var w in _map.Values) w.OnError(exception); diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupByUntil.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupByUntil.cs index a3a579679..f26d69a49 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupByUntil.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/GroupByUntil.cs @@ -2,6 +2,7 @@ // 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.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reactive.Disposables; @@ -28,34 +29,42 @@ public GroupByUntil(IObservable source, Func keySelector _comparer = comparer; } - private CompositeDisposable _groupDisposable; - private RefCountDisposable _refCountDisposable; - protected override IDisposable Run(IObserver> observer, IDisposable cancel, Action setSink) { - _groupDisposable = new CompositeDisposable(); - _refCountDisposable = new RefCountDisposable(_groupDisposable); - var sink = new _(this, observer, cancel); setSink(sink); - _groupDisposable.Add(_source.SubscribeSafe(sink)); - - return _refCountDisposable; + return sink.Run(_source); } - class _ : Sink>, IObserver + private sealed class _ : Sink>, IObserver { - private readonly GroupByUntil _parent; + private readonly object _nullGate = new object(); + private readonly CompositeDisposable _groupDisposable = new CompositeDisposable(); + private readonly RefCountDisposable _refCountDisposable; private readonly Map> _map; + + private readonly Func _keySelector; + private readonly Func _elementSelector; + private readonly Func, IObservable> _durationSelector; + private ISubject _null; - private object _nullGate; public _(GroupByUntil parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) { - _parent = parent; - _map = new Map>(_parent._capacity, _parent._comparer); - _nullGate = new object(); + _refCountDisposable = new RefCountDisposable(_groupDisposable); + _map = new Map>(parent._capacity, parent._comparer); + + _keySelector = parent._keySelector; + _elementSelector = parent._elementSelector; + _durationSelector = parent._durationSelector; + } + + public IDisposable Run(IObservable source) + { + _groupDisposable.Add(source.SubscribeSafe(this)); + + return _refCountDisposable; } private ISubject NewSubject() @@ -70,7 +79,7 @@ public void OnNext(TSource value) var key = default(TKey); try { - key = _parent._keySelector(value); + key = _keySelector(value); } catch (Exception exception) { @@ -116,14 +125,14 @@ public void OnNext(TSource value) if (fireNewMapEntry) { - var group = new GroupedObservable(key, writer, _parent._refCountDisposable); + var group = new GroupedObservable(key, writer, _refCountDisposable); var duration = default(IObservable); var durationGroup = new GroupedObservable(key, writer); try { - duration = _parent._durationSelector(durationGroup); + duration = _durationSelector(durationGroup); } catch (Exception exception) { @@ -135,14 +144,14 @@ public void OnNext(TSource value) base._observer.OnNext(group); var md = new SingleAssignmentDisposable(); - _parent._groupDisposable.Add(md); - md.Disposable = duration.SubscribeSafe(new Delta(this, key, writer, md)); + _groupDisposable.Add(md); + md.Disposable = duration.SubscribeSafe(new DurationObserver(this, key, writer, md)); } var element = default(TElement); try { - element = _parent._elementSelector(value); + element = _elementSelector(value); } catch (Exception exception) { @@ -171,14 +180,14 @@ public void OnNext(TSource value) writer.OnNext(element); } - class Delta : IObserver + private sealed class DurationObserver : IObserver { private readonly _ _parent; private readonly TKey _key; private readonly ISubject _writer; private readonly IDisposable _self; - public Delta(_ parent, TKey key, ISubject writer, IDisposable self) + public DurationObserver(_ parent, TKey key, ISubject writer, IDisposable self) { _parent = parent; _key = key; @@ -218,7 +227,7 @@ public void OnCompleted() } } - _parent._parent._groupDisposable.Remove(_self); + _parent._groupDisposable.Remove(_self); } } @@ -238,8 +247,7 @@ public void OnCompleted() lock (_nullGate) @null = _null; - if (@null != null) - @null.OnCompleted(); + @null?.OnCompleted(); foreach (var w in _map.Values) w.OnCompleted(); @@ -261,8 +269,7 @@ private void Error(Exception exception) lock (_nullGate) @null = _null; - if (@null != null) - @null.OnError(exception); + @null?.OnError(exception); foreach (var w in _map.Values) w.OnError(exception); @@ -286,22 +293,19 @@ internal sealed class Map // compromise. private const int DEFAULT_CONCURRENCY_MULTIPLIER = 4; - private static int DefaultConcurrencyLevel - { - get { return DEFAULT_CONCURRENCY_MULTIPLIER * Environment.ProcessorCount; } - } + private static int DefaultConcurrencyLevel => DEFAULT_CONCURRENCY_MULTIPLIER * Environment.ProcessorCount; - private readonly System.Collections.Concurrent.ConcurrentDictionary _map; + private readonly ConcurrentDictionary _map; public Map(int? capacity, IEqualityComparer comparer) { if (capacity.HasValue) { - _map = new System.Collections.Concurrent.ConcurrentDictionary(DefaultConcurrencyLevel, capacity.Value, comparer); + _map = new ConcurrentDictionary(DefaultConcurrencyLevel, capacity.Value, comparer); } else { - _map = new System.Collections.Concurrent.ConcurrentDictionary(comparer); + _map = new ConcurrentDictionary(comparer); } } @@ -334,13 +338,7 @@ public TValue GetOrAdd(TKey key, Func valueFactory, out bool added) return value; } - public IEnumerable Values - { - get - { - return _map.Values.ToArray(); - } - } + public IEnumerable Values => _map.Values.ToArray(); public bool Remove(TKey key) { From f9cab0f2a1aacebeb2bdcdb2fd8537a40de918b4 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Wed, 19 Apr 2017 09:48:35 -0700 Subject: [PATCH 94/95] Initial improvements for Delay layouts. --- .../System.Reactive/Linq/Observable/Delay.cs | 270 ++++++++++-------- .../Linq/QueryLanguage.Time.cs | 9 +- 2 files changed, 153 insertions(+), 126 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Delay.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Delay.cs index 41befff83..4c3f820ea 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Delay.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Delay.cs @@ -545,184 +545,216 @@ private void DrainQueue(ICancelable cancel) } } - internal sealed class Delay : Producer + internal static class Delay { - private readonly IObservable _source; - private readonly IObservable _subscriptionDelay; - private readonly Func> _delaySelector; - - public Delay(IObservable source, IObservable subscriptionDelay, Func> delaySelector) - { - _source = source; - _subscriptionDelay = subscriptionDelay; - _delaySelector = delaySelector; - } - - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + internal class Selector : Producer { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); - } + protected readonly IObservable _source; + private readonly Func> _delaySelector; - class _ : Sink, IObserver - { - private readonly Delay _parent; - - public _(Delay parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Selector(IObservable source, Func> delaySelector) { - _parent = parent; + _source = source; + _delaySelector = delaySelector; } - private CompositeDisposable _delays; - private object _gate; - private bool _atEnd; - private SerialDisposable _subscription; + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(this); + } - public IDisposable Run() + protected class _ : Sink, IObserver + where TParent : Selector { - _delays = new CompositeDisposable(); - _gate = new object(); - _atEnd = false; - _subscription = new SerialDisposable(); + private readonly CompositeDisposable _delays = new CompositeDisposable(); + private object _gate = new object(); - if (_parent._subscriptionDelay == null) + private readonly Func> _delaySelector; + + public _(Selector parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - Start(); + _delaySelector = parent._delaySelector; } - else + + private bool _atEnd; + private IDisposable _subscription; + + public IDisposable Run(TParent parent) { - _subscription.Disposable = _parent._subscriptionDelay.SubscribeSafe(new SubscriptionDelay(this)); - } + _atEnd = false; - return StableCompositeDisposable.Create(_subscription, _delays); - } + _subscription = RunCore(parent); - private void Start() - { - _subscription.Disposable = _parent._source.SubscribeSafe(this); - } + return StableCompositeDisposable.Create(_subscription, _delays); + } - public void OnNext(TSource value) - { - var delay = default(IObservable); - try + protected virtual IDisposable RunCore(TParent parent) { - delay = _parent._delaySelector(value); + return parent._source.SubscribeSafe(this); } - catch (Exception error) + + public void OnNext(TSource value) + { + var delay = default(IObservable); + try + { + delay = _delaySelector(value); + } + catch (Exception error) + { + lock (_gate) + { + base._observer.OnError(error); + base.Dispose(); + } + + return; + } + + var d = new SingleAssignmentDisposable(); + _delays.Add(d); + d.Disposable = delay.SubscribeSafe(new DelayObserver(this, value, d)); + } + + public void OnError(Exception error) { lock (_gate) { base._observer.OnError(error); base.Dispose(); } - - return; } - var d = new SingleAssignmentDisposable(); - _delays.Add(d); - d.Disposable = delay.SubscribeSafe(new Delta(this, value, d)); - } + public void OnCompleted() + { + lock (_gate) + { + _atEnd = true; + _subscription.Dispose(); - public void OnError(Exception error) - { - lock (_gate) + CheckDone(); + } + } + + private void CheckDone() { - base._observer.OnError(error); - base.Dispose(); + if (_atEnd && _delays.Count == 0) + { + base._observer.OnCompleted(); + base.Dispose(); + } } - } - public void OnCompleted() - { - lock (_gate) + private sealed class DelayObserver : IObserver { - _atEnd = true; - _subscription.Dispose(); + private readonly _ _parent; + private readonly TSource _value; + private readonly IDisposable _self; + + public DelayObserver(_ parent, TSource value, IDisposable self) + { + _parent = parent; + _value = value; + _self = self; + } + + public void OnNext(TDelay value) + { + lock (_parent._gate) + { + _parent._observer.OnNext(_value); + + _parent._delays.Remove(_self); + _parent.CheckDone(); + } + } - CheckDone(); + public void OnError(Exception error) + { + lock (_parent._gate) + { + _parent._observer.OnError(error); + _parent.Dispose(); + } + } + + public void OnCompleted() + { + lock (_parent._gate) + { + _parent._observer.OnNext(_value); + + _parent._delays.Remove(_self); + _parent.CheckDone(); + } + } } } + } - private void CheckDone() + internal sealed class SelectorWithSubscriptionDelay : Selector + { + private readonly IObservable _subscriptionDelay; + + public SelectorWithSubscriptionDelay(IObservable source, IObservable subscriptionDelay, Func> delaySelector) + : base(source, delaySelector) { - if (_atEnd && _delays.Count == 0) - { - base._observer.OnCompleted(); - base.Dispose(); - } + _subscriptionDelay = subscriptionDelay; } - class SubscriptionDelay : IObserver + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - private readonly _ _parent; + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(this); + } - public SubscriptionDelay(_ parent) + private sealed class _ : _ + { + public _(SelectorWithSubscriptionDelay parent, IObserver observer, IDisposable cancel) + : base(parent, observer, cancel) { - _parent = parent; } - public void OnNext(TDelay value) + protected override IDisposable RunCore(SelectorWithSubscriptionDelay parent) { - _parent.Start(); - } + var subscription = new SerialDisposable(); - public void OnError(Exception error) - { - _parent._observer.OnError(error); - _parent.Dispose(); - } + subscription.Disposable = parent._subscriptionDelay.SubscribeSafe(new SubscriptionDelayObserver(this, parent._source, subscription)); - public void OnCompleted() - { - _parent.Start(); + return subscription; } - } - - class Delta : IObserver - { - private readonly _ _parent; - private readonly TSource _value; - private readonly IDisposable _self; - public Delta(_ parent, TSource value, IDisposable self) + private sealed class SubscriptionDelayObserver : IObserver { - _parent = parent; - _value = value; - _self = self; - } + private readonly _ _parent; + private readonly IObservable _source; + private readonly SerialDisposable _subscription; - public void OnNext(TDelay value) - { - lock (_parent._gate) + public SubscriptionDelayObserver(_ parent, IObservable source, SerialDisposable subscription) { - _parent._observer.OnNext(_value); + _parent = parent; + _source = source; + _subscription = subscription; + } - _parent._delays.Remove(_self); - _parent.CheckDone(); + public void OnNext(TDelay value) + { + _subscription.Disposable = _source.SubscribeSafe(_parent); } - } - public void OnError(Exception error) - { - lock (_parent._gate) + public void OnError(Exception error) { _parent._observer.OnError(error); _parent.Dispose(); } - } - public void OnCompleted() - { - lock (_parent._gate) + public void OnCompleted() { - _parent._observer.OnNext(_value); - - _parent._delays.Remove(_self); - _parent.CheckDone(); + _subscription.Disposable = _source.SubscribeSafe(_parent); } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index 801eff9e1..34ede5bfa 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -114,17 +114,12 @@ private static IObservable Delay_(IObservable source, public virtual IObservable Delay(IObservable source, Func> delayDurationSelector) { - return Delay_(source, null, delayDurationSelector); + return new Delay.Selector(source, delayDurationSelector); } public virtual IObservable Delay(IObservable source, IObservable subscriptionDelay, Func> delayDurationSelector) { - return Delay_(source, subscriptionDelay, delayDurationSelector); - } - - private static IObservable Delay_(IObservable source, IObservable subscriptionDelay, Func> delayDurationSelector) - { - return new Delay(source, subscriptionDelay, delayDurationSelector); + return new Delay.SelectorWithSubscriptionDelay(source, subscriptionDelay, delayDurationSelector); } #endregion From 84ce7f707499ec868760d290e22f167caa1b6b40 Mon Sep 17 00:00:00 2001 From: Bart De Smet Date: Wed, 19 Apr 2017 14:36:15 -0700 Subject: [PATCH 95/95] More layout optimizations for Delay. --- .../System.Reactive/Linq/Observable/Delay.cs | 847 ++++++++++-------- .../Linq/QueryLanguage.Time.cs | 4 +- 2 files changed, 458 insertions(+), 393 deletions(-) diff --git a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Delay.cs b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Delay.cs index 4c3f820ea..306a7a460 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/Observable/Delay.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/Observable/Delay.cs @@ -9,537 +9,602 @@ namespace System.Reactive.Linq.ObservableImpl { - internal sealed class Delay : Producer + internal static class Delay { - private readonly IObservable _source; - private readonly TimeSpan? _dueTimeR; - private readonly DateTimeOffset? _dueTimeA; - private readonly IScheduler _scheduler; - - public Delay(IObservable source, TimeSpan dueTime, IScheduler scheduler) + internal abstract class Base : Producer { - _source = source; - _dueTimeR = dueTime; - _scheduler = scheduler; - } - - public Delay(IObservable source, DateTimeOffset dueTime, IScheduler scheduler) - { - _source = source; - _dueTimeA = dueTime; - _scheduler = scheduler; - } + protected readonly IObservable _source; + protected readonly IScheduler _scheduler; - protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) - { - if (_scheduler.AsLongRunning() != null) - { - var sink = new LongRunningImpl(this, observer, cancel); - setSink(sink); - return sink.Run(); - } - else + public Base(IObservable source, IScheduler scheduler) { - var sink = new _(this, observer, cancel); - setSink(sink); - return sink.Run(); + _source = source; + _scheduler = scheduler; } - } - - class _ : Sink, IObserver - { - private readonly Delay _parent; - public _(Delay parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + protected abstract class _ : Sink, IObserver + where TParent : Base { - _parent = parent; - } + protected readonly object _gate = new object(); + protected readonly SerialDisposable _cancelable = new SerialDisposable(); - private IScheduler _scheduler; - private IDisposable _sourceSubscription; - private SerialDisposable _cancelable; - private TimeSpan _delay; - private IStopwatch _watch; - - private object _gate; - private bool _ready; - private bool _active; - private bool _running; - private Queue> _queue; - private bool _hasCompleted; - private TimeSpan _completeAt; - private bool _hasFailed; - private Exception _exception; - - public IDisposable Run() - { - _scheduler = _parent._scheduler; + protected readonly IScheduler _scheduler; + + public _(TParent parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + _scheduler = parent._scheduler; + } - _cancelable = new SerialDisposable(); + private IDisposable _sourceSubscription; - _gate = new object(); - _active = false; - _running = false; - _queue = new Queue>(); - _hasCompleted = false; - _completeAt = default(TimeSpan); - _hasFailed = false; - _exception = default(Exception); + protected IStopwatch _watch; + protected TimeSpan _delay; + protected bool _ready; + protected bool _active; + protected bool _running; + protected Queue> _queue = new Queue>(); - _watch = _scheduler.StartStopwatch(); + private bool _hasCompleted; + private TimeSpan _completeAt; + private bool _hasFailed; + private Exception _exception; - if (_parent._dueTimeA.HasValue) + public IDisposable Run(TParent parent) { - _ready = false; + _active = false; + _running = false; + _queue = new Queue>(); + _hasCompleted = false; + _completeAt = default(TimeSpan); + _hasFailed = false; + _exception = default(Exception); - var dueTimeA = _parent._dueTimeA.Value; - _cancelable.Disposable = _scheduler.Schedule(dueTimeA, Start); - } - else - { - _ready = true; + _watch = _scheduler.StartStopwatch(); + + RunCore(parent); + + var sourceSubscription = new SingleAssignmentDisposable(); + _sourceSubscription = sourceSubscription; + sourceSubscription.Disposable = parent._source.SubscribeSafe(this); - var dueTimeR = _parent._dueTimeR.Value; - _delay = Scheduler.Normalize(dueTimeR); + return StableCompositeDisposable.Create(_sourceSubscription, _cancelable); } - var sourceSubscription = new SingleAssignmentDisposable(); - _sourceSubscription = sourceSubscription; - sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); + protected abstract void RunCore(TParent parent); - return StableCompositeDisposable.Create(_sourceSubscription, _cancelable); - } + public void OnNext(TSource value) + { + var next = _watch.Elapsed.Add(_delay); + var shouldRun = false; - private void Start() - { - var next = default(TimeSpan); - var shouldRun = false; + lock (_gate) + { + _queue.Enqueue(new System.Reactive.TimeInterval(value, next)); - lock (_gate) + shouldRun = _ready && !_active; + _active = true; + } + + if (shouldRun) + { + _cancelable.Disposable = _scheduler.Schedule(_delay, DrainQueue); + } + } + + public void OnError(Exception error) { - _delay = _watch.Elapsed; + _sourceSubscription.Dispose(); - var oldQueue = _queue; - _queue = new Queue>(); + var shouldRun = false; - if (oldQueue.Count > 0) + lock (_gate) { - next = oldQueue.Peek().Interval; + _queue.Clear(); - while (oldQueue.Count > 0) - { - var item = oldQueue.Dequeue(); - _queue.Enqueue(new Reactive.TimeInterval(item.Value, item.Interval.Add(_delay))); - } + _exception = error; + _hasFailed = true; - shouldRun = true; - _active = true; + shouldRun = !_running; } - _ready = true; + if (shouldRun) + { + base._observer.OnError(error); + base.Dispose(); + } } - if (shouldRun) + public void OnCompleted() { - _cancelable.Disposable = _scheduler.Schedule(next, DrainQueue); - } - } + _sourceSubscription.Dispose(); - public void OnNext(TSource value) - { - var next = _watch.Elapsed.Add(_delay); - var shouldRun = false; + var next = _watch.Elapsed.Add(_delay); + var shouldRun = false; - lock (_gate) - { - _queue.Enqueue(new System.Reactive.TimeInterval(value, next)); + lock (_gate) + { + _completeAt = next; + _hasCompleted = true; + + shouldRun = _ready && !_active; + _active = true; + } - shouldRun = _ready && !_active; - _active = true; + if (shouldRun) + { + _cancelable.Disposable = _scheduler.Schedule(_delay, DrainQueue); + } } - if (shouldRun) + protected void DrainQueue(Action recurse) { - _cancelable.Disposable = _scheduler.Schedule(_delay, DrainQueue); + lock (_gate) + { + if (_hasFailed) + return; + _running = true; + } + + // + // The shouldYield flag was added to address TFS 487881: "Delay can be unfair". In the old + // implementation, the loop below kept running while there was work for immediate dispatch, + // potentially causing a long running work item on the target scheduler. With the addition + // of long-running scheduling in Rx v2.0, we can check whether the scheduler supports this + // interface and perform different processing (see LongRunningImpl). To reduce the code + // churn in the old loop code here, we set the shouldYield flag to true after the first + // dispatch iteration, in order to break from the loop and enter the recursive scheduling path. + // + var shouldYield = false; + + while (true) + { + var hasFailed = false; + var error = default(Exception); + + var hasValue = false; + var value = default(TSource); + var hasCompleted = false; + + var shouldRecurse = false; + var recurseDueTime = default(TimeSpan); + + lock (_gate) + { + if (_hasFailed) + { + error = _exception; + hasFailed = true; + _running = false; + } + else + { + var now = _watch.Elapsed; + + if (_queue.Count > 0) + { + var nextDue = _queue.Peek().Interval; + + if (nextDue.CompareTo(now) <= 0 && !shouldYield) + { + value = _queue.Dequeue().Value; + hasValue = true; + } + else + { + shouldRecurse = true; + recurseDueTime = Scheduler.Normalize(nextDue.Subtract(now)); + _running = false; + } + } + else if (_hasCompleted) + { + if (_completeAt.CompareTo(now) <= 0 && !shouldYield) + { + hasCompleted = true; + } + else + { + shouldRecurse = true; + recurseDueTime = Scheduler.Normalize(_completeAt.Subtract(now)); + _running = false; + } + } + else + { + _running = false; + _active = false; + } + } + } /* lock (_gate) */ + + if (hasValue) + { + base._observer.OnNext(value); + shouldYield = true; + } + else + { + if (hasCompleted) + { + base._observer.OnCompleted(); + base.Dispose(); + } + else if (hasFailed) + { + base._observer.OnError(error); + base.Dispose(); + } + else if (shouldRecurse) + { + recurse(recurseDueTime); + } + + return; + } + } /* while (true) */ } } - public void OnError(Exception error) + protected abstract class L : Sink, IObserver + where TParent : Base { - _sourceSubscription.Dispose(); + protected readonly object _gate = new object(); + protected readonly SerialDisposable _cancelable = new SerialDisposable(); + private readonly SemaphoreSlim _evt = new SemaphoreSlim(0); - var shouldRun = false; + private readonly IScheduler _scheduler; - lock (_gate) + public L(TParent parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) { - _queue.Clear(); + _scheduler = parent._scheduler; + } - _exception = error; - _hasFailed = true; + private IDisposable _sourceSubscription; - shouldRun = !_running; - } + protected IStopwatch _watch; + protected TimeSpan _delay; + protected Queue> _queue; - if (shouldRun) + private CancellationTokenSource _stop; + private bool _hasCompleted; + private TimeSpan _completeAt; + private bool _hasFailed; + private Exception _exception; + + public IDisposable Run(TParent parent) { - base._observer.OnError(error); - base.Dispose(); - } - } + _queue = new Queue>(); + _hasCompleted = false; + _completeAt = default(TimeSpan); + _hasFailed = false; + _exception = default(Exception); - public void OnCompleted() - { - _sourceSubscription.Dispose(); + _watch = _scheduler.StartStopwatch(); - var next = _watch.Elapsed.Add(_delay); - var shouldRun = false; + RunCore(parent); - lock (_gate) - { - _completeAt = next; - _hasCompleted = true; + var sourceSubscription = new SingleAssignmentDisposable(); + _sourceSubscription = sourceSubscription; + sourceSubscription.Disposable = parent._source.SubscribeSafe(this); - shouldRun = _ready && !_active; - _active = true; + return StableCompositeDisposable.Create(_sourceSubscription, _cancelable); } - if (shouldRun) + protected abstract void RunCore(TParent parent); + + protected void ScheduleDrain() { - _cancelable.Disposable = _scheduler.Schedule(_delay, DrainQueue); + _stop = new CancellationTokenSource(); + _cancelable.Disposable = Disposable.Create(_stop.Cancel); + + _scheduler.AsLongRunning().ScheduleLongRunning(DrainQueue); } - } - private void DrainQueue(Action recurse) - { - lock (_gate) + public void OnNext(TSource value) { - if (_hasFailed) - return; - _running = true; - } + var next = _watch.Elapsed.Add(_delay); + + lock (_gate) + { + _queue.Enqueue(new System.Reactive.TimeInterval(value, next)); - // - // The shouldYield flag was added to address TFS 487881: "Delay can be unfair". In the old - // implementation, the loop below kept running while there was work for immediate dispatch, - // potentially causing a long running work item on the target scheduler. With the addition - // of long-running scheduling in Rx v2.0, we can check whether the scheduler supports this - // interface and perform different processing (see LongRunningImpl). To reduce the code - // churn in the old loop code here, we set the shouldYield flag to true after the first - // dispatch iteration, in order to break from the loop and enter the recursive scheduling path. - // - var shouldYield = false; + _evt.Release(); + } + } - while (true) + public void OnError(Exception error) { - var hasFailed = false; - var error = default(Exception); + _sourceSubscription.Dispose(); + + lock (_gate) + { + _queue.Clear(); - var hasValue = false; - var value = default(TSource); - var hasCompleted = false; + _exception = error; + _hasFailed = true; - var shouldRecurse = false; - var recurseDueTime = default(TimeSpan); + _evt.Release(); + } + } + + public void OnCompleted() + { + _sourceSubscription.Dispose(); + + var next = _watch.Elapsed.Add(_delay); lock (_gate) { - if (_hasFailed) + _completeAt = next; + _hasCompleted = true; + + _evt.Release(); + } + } + + private void DrainQueue(ICancelable cancel) + { + while (true) + { + try { - error = _exception; - hasFailed = true; - _running = false; + _evt.Wait(_stop.Token); } - else + catch (OperationCanceledException) { - var now = _watch.Elapsed; + return; + } + + var hasFailed = false; + var error = default(Exception); - if (_queue.Count > 0) + var hasValue = false; + var value = default(TSource); + var hasCompleted = false; + + var shouldWait = false; + var waitTime = default(TimeSpan); + + lock (_gate) + { + if (_hasFailed) { - var nextDue = _queue.Peek().Interval; + error = _exception; + hasFailed = true; + } + else + { + var now = _watch.Elapsed; - if (nextDue.CompareTo(now) <= 0 && !shouldYield) + if (_queue.Count > 0) { - value = _queue.Dequeue().Value; + var next = _queue.Dequeue(); + hasValue = true; + value = next.Value; + + var nextDue = next.Interval; + if (nextDue.CompareTo(now) > 0) + { + shouldWait = true; + waitTime = Scheduler.Normalize(nextDue.Subtract(now)); + } } - else + else if (_hasCompleted) { - shouldRecurse = true; - recurseDueTime = Scheduler.Normalize(nextDue.Subtract(now)); - _running = false; + hasCompleted = true; + + if (_completeAt.CompareTo(now) > 0) + { + shouldWait = true; + waitTime = Scheduler.Normalize(_completeAt.Subtract(now)); + } } } - else if (_hasCompleted) + } /* lock (_gate) */ + + if (shouldWait) + { + var timer = new ManualResetEventSlim(); + _scheduler.Schedule(waitTime, () => { timer.Set(); }); + + try { - if (_completeAt.CompareTo(now) <= 0 && !shouldYield) - { - hasCompleted = true; - } - else - { - shouldRecurse = true; - recurseDueTime = Scheduler.Normalize(_completeAt.Subtract(now)); - _running = false; - } + timer.Wait(_stop.Token); } - else + catch (OperationCanceledException) { - _running = false; - _active = false; + return; } } - } /* lock (_gate) */ - if (hasValue) - { - base._observer.OnNext(value); - shouldYield = true; - } - else - { - if (hasCompleted) - { - base._observer.OnCompleted(); - base.Dispose(); - } - else if (hasFailed) + if (hasValue) { - base._observer.OnError(error); - base.Dispose(); + base._observer.OnNext(value); } - else if (shouldRecurse) + else { - recurse(recurseDueTime); - } + if (hasCompleted) + { + base._observer.OnCompleted(); + base.Dispose(); + } + else if (hasFailed) + { + base._observer.OnError(error); + base.Dispose(); + } - return; + return; + } } - } /* while (true) */ + } } } - class LongRunningImpl : Sink, IObserver + internal sealed class Absolute : Base { - private readonly Delay _parent; + private readonly DateTimeOffset _dueTime; - public LongRunningImpl(Delay parent, IObserver observer, IDisposable cancel) - : base(observer, cancel) + public Absolute(IObservable source, DateTimeOffset dueTime, IScheduler scheduler) + : base(source, scheduler) { - _parent = parent; + _dueTime = dueTime; } - private IDisposable _sourceSubscription; - private SerialDisposable _cancelable; - private TimeSpan _delay; - private IStopwatch _watch; - - private object _gate; - private SemaphoreSlim _evt; - private CancellationTokenSource _stop; - private Queue> _queue; - private bool _hasCompleted; - private TimeSpan _completeAt; - private bool _hasFailed; - private Exception _exception; - - public IDisposable Run() + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) { - _cancelable = new SerialDisposable(); - - _gate = new object(); - _evt = new SemaphoreSlim(0); - _queue = new Queue>(); - _hasCompleted = false; - _completeAt = default(TimeSpan); - _hasFailed = false; - _exception = default(Exception); - - _watch = _parent._scheduler.StartStopwatch(); - - if (_parent._dueTimeA.HasValue) + if (_scheduler.AsLongRunning() != null) { - var dueTimeA = _parent._dueTimeA.Value; - _cancelable.Disposable = _parent._scheduler.Schedule(dueTimeA, Start); + var sink = new L(this, observer, cancel); + setSink(sink); + return sink.Run(this); } else { - var dueTimeR = _parent._dueTimeR.Value; - _delay = Scheduler.Normalize(dueTimeR); - ScheduleDrain(); + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(this); } - - var sourceSubscription = new SingleAssignmentDisposable(); - _sourceSubscription = sourceSubscription; - sourceSubscription.Disposable = _parent._source.SubscribeSafe(this); - - return StableCompositeDisposable.Create(_sourceSubscription, _cancelable); } - private void Start() + private sealed class _ : _ { - lock (_gate) + public _(Absolute parent, IObserver observer, IDisposable cancel) + : base(parent, observer, cancel) { - _delay = _watch.Elapsed; - - var oldQueue = _queue; - _queue = new Queue>(); - - while (oldQueue.Count > 0) - { - var item = oldQueue.Dequeue(); - _queue.Enqueue(new Reactive.TimeInterval(item.Value, item.Interval.Add(_delay))); - } } - ScheduleDrain(); - } + protected override void RunCore(Absolute parent) + { + _ready = false; - private void ScheduleDrain() - { - _stop = new CancellationTokenSource(); - _cancelable.Disposable = Disposable.Create(() => _stop.Cancel()); + _cancelable.Disposable = parent._scheduler.Schedule(parent._dueTime, Start); + } - _parent._scheduler.AsLongRunning().ScheduleLongRunning(DrainQueue); - } + private void Start() + { + var next = default(TimeSpan); + var shouldRun = false; - public void OnNext(TSource value) - { - var next = _watch.Elapsed.Add(_delay); + lock (_gate) + { + _delay = _watch.Elapsed; - lock (_gate) - { - _queue.Enqueue(new System.Reactive.TimeInterval(value, next)); + var oldQueue = _queue; + _queue = new Queue>(); - _evt.Release(); - } - } + if (oldQueue.Count > 0) + { + next = oldQueue.Peek().Interval; - public void OnError(Exception error) - { - _sourceSubscription.Dispose(); + while (oldQueue.Count > 0) + { + var item = oldQueue.Dequeue(); + _queue.Enqueue(new Reactive.TimeInterval(item.Value, item.Interval.Add(_delay))); + } - lock (_gate) - { - _queue.Clear(); + shouldRun = true; + _active = true; + } - _exception = error; - _hasFailed = true; + _ready = true; + } - _evt.Release(); + if (shouldRun) + { + _cancelable.Disposable = _scheduler.Schedule(next, DrainQueue); + } } } - public void OnCompleted() + private sealed class L : L { - _sourceSubscription.Dispose(); - - var next = _watch.Elapsed.Add(_delay); - - lock (_gate) + public L(Absolute parent, IObserver observer, IDisposable cancel) + : base(parent, observer, cancel) { - _completeAt = next; - _hasCompleted = true; + } - _evt.Release(); + protected override void RunCore(Absolute parent) + { + _cancelable.Disposable = parent._scheduler.Schedule(parent._dueTime, Start); } - } - private void DrainQueue(ICancelable cancel) - { - while (true) + private void Start() { - try - { - _evt.Wait(_stop.Token); - } - catch (OperationCanceledException) + lock (_gate) { - return; - } - - var hasFailed = false; - var error = default(Exception); + _delay = _watch.Elapsed; - var hasValue = false; - var value = default(TSource); - var hasCompleted = false; + var oldQueue = _queue; + _queue = new Queue>(); - var shouldWait = false; - var waitTime = default(TimeSpan); - - lock (_gate) - { - if (_hasFailed) + while (oldQueue.Count > 0) { - error = _exception; - hasFailed = true; + var item = oldQueue.Dequeue(); + _queue.Enqueue(new Reactive.TimeInterval(item.Value, item.Interval.Add(_delay))); } - else - { - var now = _watch.Elapsed; + } - if (_queue.Count > 0) - { - var next = _queue.Dequeue(); + ScheduleDrain(); + } + } + } - hasValue = true; - value = next.Value; + internal sealed class Relative : Base + { + private readonly TimeSpan _dueTime; - var nextDue = next.Interval; - if (nextDue.CompareTo(now) > 0) - { - shouldWait = true; - waitTime = Scheduler.Normalize(nextDue.Subtract(now)); - } - } - else if (_hasCompleted) - { - hasCompleted = true; + public Relative(IObservable source, TimeSpan dueTime, IScheduler scheduler) + : base(source, scheduler) + { + _dueTime = dueTime; + } - if (_completeAt.CompareTo(now) > 0) - { - shouldWait = true; - waitTime = Scheduler.Normalize(_completeAt.Subtract(now)); - } - } - } - } /* lock (_gate) */ + protected override IDisposable Run(IObserver observer, IDisposable cancel, Action setSink) + { + if (_scheduler.AsLongRunning() != null) + { + var sink = new L(this, observer, cancel); + setSink(sink); + return sink.Run(this); + } + else + { + var sink = new _(this, observer, cancel); + setSink(sink); + return sink.Run(this); + } + } - if (shouldWait) - { - var timer = new ManualResetEventSlim(); - _parent._scheduler.Schedule(waitTime, () => { timer.Set(); }); + private sealed class _ : _ + { + public _(Relative parent, IObserver observer, IDisposable cancel) + : base(parent, observer, cancel) + { + } - try - { - timer.Wait(_stop.Token); - } - catch (OperationCanceledException) - { - return; - } - } + protected override void RunCore(Relative parent) + { + _ready = true; - if (hasValue) - { - base._observer.OnNext(value); - } - else - { - if (hasCompleted) - { - base._observer.OnCompleted(); - base.Dispose(); - } - else if (hasFailed) - { - base._observer.OnError(error); - base.Dispose(); - } + _delay = Scheduler.Normalize(parent._dueTime); + } + } - return; - } + private sealed class L : L + { + public L(Relative parent, IObserver observer, IDisposable cancel) + : base(parent, observer, cancel) + { + } + + protected override void RunCore(Relative parent) + { + _delay = Scheduler.Normalize(parent._dueTime); + ScheduleDrain(); } } } diff --git a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs index 34ede5bfa..d0c674519 100644 --- a/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs +++ b/Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Time.cs @@ -86,7 +86,7 @@ public virtual IObservable Delay(IObservable source, private static IObservable Delay_(IObservable source, TimeSpan dueTime, IScheduler scheduler) { - return new Delay(source, dueTime, scheduler); + return new Delay.Relative(source, dueTime, scheduler); } #endregion @@ -105,7 +105,7 @@ public virtual IObservable Delay(IObservable source, private static IObservable Delay_(IObservable source, DateTimeOffset dueTime, IScheduler scheduler) { - return new Delay(source, dueTime, scheduler); + return new Delay.Absolute(source, dueTime, scheduler); } #endregion