| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872 | // 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.Collections.Generic;using System.Reactive.Concurrency;using System.Reactive.Disposables;namespace System.Reactive.Linq.ObservableImpl{    internal static class Buffer<TSource>    {        internal sealed class CountExact : Producer<IList<TSource>, CountExact.ExactSink>        {            private readonly IObservable<TSource> _source;            private readonly int _count;            public CountExact(IObservable<TSource> source, int count)            {                _source = source;                _count = count;            }            protected override ExactSink CreateSink(IObserver<IList<TSource>> observer) => new ExactSink(observer, _count);            protected override void Run(ExactSink sink) => sink.Run(_source);            internal sealed class ExactSink : Sink<TSource, IList<TSource>>            {                private readonly int _count;                private int _index;                private IList<TSource> _buffer;                internal ExactSink(IObserver<IList<TSource>> observer, int count) : base(observer)                {                    _count = count;                }                public override void OnNext(TSource value)                {                    var buffer = _buffer;                    if (buffer == null)                    {                        buffer = new List<TSource>();                        _buffer = buffer;                    }                    buffer.Add(value);                    var idx = _index + 1;                    if (idx == _count)                    {                        _buffer = null;                        _index = 0;                        ForwardOnNext(buffer);                    }                    else                    {                        _index = idx;                    }                }                public override void OnError(Exception error)                {                    _buffer = null;                    ForwardOnError(error);                }                public override void OnCompleted()                {                    var buffer = _buffer;                    _buffer = null;                    if (buffer != null)                    {                        ForwardOnNext(buffer);                    }                    ForwardOnCompleted();                }            }        }        internal sealed class CountSkip : Producer<IList<TSource>, CountSkip.SkipSink>        {            private readonly IObservable<TSource> _source;            private readonly int _count;            private readonly int _skip;            public CountSkip(IObservable<TSource> source, int count, int skip)            {                _source = source;                _count = count;                _skip = skip;            }            protected override SkipSink CreateSink(IObserver<IList<TSource>> observer) => new SkipSink(observer, _count, _skip);            protected override void Run(SkipSink sink) => sink.Run(_source);            internal sealed class SkipSink : Sink<TSource, IList<TSource>>            {                private readonly int _count;                private readonly int _skip;                private int _index;                private IList<TSource> _buffer;                internal SkipSink(IObserver<IList<TSource>> observer, int count, int skip) : base(observer)                {                    _count = count;                    _skip = skip;                }                public override void OnNext(TSource value)                {                    var idx = _index;                    var buffer = _buffer;                    if (idx == 0)                    {                        buffer = new List<TSource>();                        _buffer = buffer;                    }                    buffer?.Add(value);                    if (++idx == _count)                    {                        _buffer = null;                        ForwardOnNext(buffer);                    }                    if (idx == _skip)                    {                        _index = 0;                    }                    else                    {                        _index = idx;                    }                }                public override void OnError(Exception error)                {                    _buffer = null;                    ForwardOnError(error);                }                public override void OnCompleted()                {                    var buffer = _buffer;                    _buffer = null;                    if (buffer != null)                    {                        ForwardOnNext(buffer);                    }                    ForwardOnCompleted();                }            }        }        internal sealed class CountOverlap : Producer<IList<TSource>, CountOverlap.OverlapSink>        {            private readonly IObservable<TSource> _source;            private readonly int _count;            private readonly int _skip;            public CountOverlap(IObservable<TSource> source, int count, int skip)            {                _source = source;                _count = count;                _skip = skip;            }            protected override OverlapSink CreateSink(IObserver<IList<TSource>> observer) => new OverlapSink(observer, _count, _skip);            protected override void Run(OverlapSink sink) => sink.Run(_source);            internal sealed class OverlapSink : Sink<TSource, IList<TSource>>            {                private readonly Queue<IList<TSource>> _queue;                private readonly int _count;                private readonly int _skip;                private int _n;                public OverlapSink(IObserver<IList<TSource>> observer, int count, int skip)                    : base(observer)                {                    _queue = new Queue<IList<TSource>>();                    _count = count;                    _skip = skip;                    CreateWindow();                }                private void CreateWindow()                {                    var s = new List<TSource>();                    _queue.Enqueue(s);                }                public override void OnNext(TSource value)                {                    foreach (var s in _queue)                    {                        s.Add(value);                    }                    var c = _n - _count + 1;                    if (c >= 0 && c % _skip == 0)                    {                        var s = _queue.Dequeue();                        if (s.Count > 0)                        {                            ForwardOnNext(s);                        }                    }                    _n++;                    if (_n % _skip == 0)                    {                        CreateWindow();                    }                }                public override void OnError(Exception error)                {                    // just drop the ILists on the GC floor, no reason to clear them                    _queue.Clear();                    ForwardOnError(error);                }                public override void OnCompleted()                {                    while (_queue.Count > 0)                    {                        var s = _queue.Dequeue();                        if (s.Count > 0)                        {                            ForwardOnNext(s);                        }                    }                    ForwardOnCompleted();                }            }        }        internal sealed class TimeSliding : Producer<IList<TSource>, TimeSliding._>        {            private readonly IObservable<TSource> _source;            private readonly TimeSpan _timeSpan;            private readonly TimeSpan _timeShift;            private readonly IScheduler _scheduler;            public TimeSliding(IObservable<TSource> source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler)            {                _source = source;                _timeSpan = timeSpan;                _timeShift = timeShift;                _scheduler = scheduler;            }            protected override _ CreateSink(IObserver<IList<TSource>> observer) => new _(this, observer);            protected override void Run(_ sink) => sink.Run(this);            internal sealed class _ : Sink<TSource, IList<TSource>>            {                private readonly TimeSpan _timeShift;                private readonly IScheduler _scheduler;                private readonly object _gate = new object();                private readonly Queue<List<TSource>> _q = new Queue<List<TSource>>();                private IDisposable _timerSerial;                public _(TimeSliding parent, IObserver<IList<TSource>> observer)                    : base(observer)                {                    _timeShift = parent._timeShift;                    _scheduler = parent._scheduler;                }                private TimeSpan _totalTime;                private TimeSpan _nextShift;                private TimeSpan _nextSpan;                public void Run(TimeSliding parent)                {                    _totalTime = TimeSpan.Zero;                    _nextShift = parent._timeShift;                    _nextSpan = parent._timeSpan;                    CreateWindow();                    CreateTimer();                    Run(parent._source);                }                protected override void Dispose(bool disposing)                {                    if (disposing)                    {                        Disposable.TryDispose(ref _timerSerial);                    }                    base.Dispose(disposing);                }                private void CreateWindow()                {                    var s = new List<TSource>();                    _q.Enqueue(s);                }                private void CreateTimer()                {                    var m = new SingleAssignmentDisposable();                    Disposable.TrySetSerial(ref _timerSerial, m);                    var isSpan = false;                    var isShift = false;                    if (_nextSpan == _nextShift)                    {                        isSpan = true;                        isShift = true;                    }                    else if (_nextSpan < _nextShift)                    {                        isSpan = true;                    }                    else                    {                        isShift = true;                    }                    var newTotalTime = isSpan ? _nextSpan : _nextShift;                    var ts = newTotalTime - _totalTime;                    _totalTime = newTotalTime;                    if (isSpan)                    {                        _nextSpan += _timeShift;                    }                    if (isShift)                    {                        _nextShift += _timeShift;                    }                    m.Disposable = _scheduler.ScheduleAction((@this: this, isSpan, isShift), ts, tuple => [email protected](tuple.isSpan, tuple.isShift));                }                private void Tick(bool isSpan, bool isShift)                {                    lock (_gate)                    {                        //                        // 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 (isSpan)                        {                            var s = _q.Dequeue();                            ForwardOnNext(s);                        }                        if (isShift)                        {                            CreateWindow();                        }                    }                    CreateTimer();                }                public override void OnNext(TSource value)                {                    lock (_gate)                    {                        foreach (var s in _q)                        {                            s.Add(value);                        }                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        while (_q.Count > 0)                        {                            _q.Dequeue().Clear();                        }                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        while (_q.Count > 0)                        {                            ForwardOnNext(_q.Dequeue());                        }                        ForwardOnCompleted();                    }                }            }        }        internal sealed class TimeHopping : Producer<IList<TSource>, TimeHopping._>        {            private readonly IObservable<TSource> _source;            private readonly TimeSpan _timeSpan;            private readonly IScheduler _scheduler;            public TimeHopping(IObservable<TSource> source, TimeSpan timeSpan, IScheduler scheduler)            {                _source = source;                _timeSpan = timeSpan;                _scheduler = scheduler;            }            protected override _ CreateSink(IObserver<IList<TSource>> observer) => new _(observer);            protected override void Run(_ sink) => sink.Run(this);            internal sealed class _ : Sink<TSource, IList<TSource>>            {                private readonly object _gate = new object();                public _(IObserver<IList<TSource>> observer)                    : base(observer)                {                }                private List<TSource> _list;                private IDisposable _periodicDisposable;                public void Run(TimeHopping parent)                {                    _list = new List<TSource>();                    Disposable.SetSingle(ref _periodicDisposable, parent._scheduler.SchedulePeriodic(this, parent._timeSpan, @this => @this.Tick()));                    Run(parent._source);                }                protected override void Dispose(bool disposing)                {                    if (disposing)                    {                        Disposable.TryDispose(ref _periodicDisposable);                    }                    base.Dispose(disposing);                }                private void Tick()                {                    lock (_gate)                    {                        ForwardOnNext(_list);                        _list = new List<TSource>();                    }                }                public override void OnNext(TSource value)                {                    lock (_gate)                    {                        _list.Add(value);                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        _list.Clear();                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        ForwardOnNext(_list);                        ForwardOnCompleted();                    }                }            }        }        internal sealed class Ferry : Producer<IList<TSource>, Ferry._>        {            private readonly IObservable<TSource> _source;            private readonly int _count;            private readonly TimeSpan _timeSpan;            private readonly IScheduler _scheduler;            public Ferry(IObservable<TSource> source, TimeSpan timeSpan, int count, IScheduler scheduler)            {                _source = source;                _timeSpan = timeSpan;                _count = count;                _scheduler = scheduler;            }            protected override _ CreateSink(IObserver<IList<TSource>> observer) => new _(this, observer);            protected override void Run(_ sink) => sink.Run();            internal sealed class _ : Sink<TSource, IList<TSource>>            {                private readonly Ferry _parent;                private readonly object _gate = new object();                private IDisposable _timerSerial;                public _(Ferry parent, IObserver<IList<TSource>> observer)                    : base(observer)                {                    _parent = parent;                }                private IList<TSource> _s;                private int _n;                private int _windowId;                public void Run()                {                    _s = new List<TSource>();                    _n = 0;                    _windowId = 0;                    CreateTimer(0);                    SetUpstream(_parent._source.SubscribeSafe(this));                }                protected override void Dispose(bool disposing)                {                    if (disposing)                    {                        Disposable.TryDispose(ref _timerSerial);                    }                    base.Dispose(disposing);                }                private void CreateTimer(int id)                {                    var m = new SingleAssignmentDisposable();                    Disposable.TrySetSerial(ref _timerSerial, m);                    m.Disposable = _parent._scheduler.ScheduleAction((@this: this, id), _parent._timeSpan, tuple => [email protected](tuple.id));                }                private void Tick(int id)                {                    lock (_gate)                    {                        if (id != _windowId)                        {                            return;                        }                        _n = 0;                        var newId = ++_windowId;                        var res = _s;                        _s = new List<TSource>();                        ForwardOnNext(res);                        CreateTimer(newId);                    }                }                public override void OnNext(TSource value)                {                    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<TSource>();                            ForwardOnNext(res);                        }                        if (newWindow)                        {                            CreateTimer(newId);                        }                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        _s.Clear();                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        ForwardOnNext(_s);                        ForwardOnCompleted();                    }                }            }        }    }    internal static class Buffer<TSource, TBufferClosing>    {        internal sealed class Selector : Producer<IList<TSource>, Selector._>        {            private readonly IObservable<TSource> _source;            private readonly Func<IObservable<TBufferClosing>> _bufferClosingSelector;            public Selector(IObservable<TSource> source, Func<IObservable<TBufferClosing>> bufferClosingSelector)            {                _source = source;                _bufferClosingSelector = bufferClosingSelector;            }            protected override _ CreateSink(IObserver<IList<TSource>> observer) => new _(this, observer);            protected override void Run(_ sink) => sink.Run(_source);            internal sealed class _ : Sink<TSource, IList<TSource>>            {                private readonly object _gate = new object();                private readonly AsyncLock _bufferGate = new AsyncLock();                private IDisposable _bufferClosingSerialDisposable;                private readonly Func<IObservable<TBufferClosing>> _bufferClosingSelector;                public _(Selector parent, IObserver<IList<TSource>> observer)                    : base(observer)                {                    _bufferClosingSelector = parent._bufferClosingSelector;                }                private IList<TSource> _buffer;                public override void Run(IObservable<TSource> source)                {                    _buffer = new List<TSource>();                    base.Run(source);                    _bufferGate.Wait(this, @this => @this.CreateBufferClose());                }                protected override void Dispose(bool disposing)                {                    if (disposing)                    {                        Disposable.TryDispose(ref _bufferClosingSerialDisposable);                    }                    base.Dispose(disposing);                }                private void CreateBufferClose()                {                    var bufferClose = default(IObservable<TBufferClosing>);                    try                    {                        bufferClose = _bufferClosingSelector();                    }                    catch (Exception exception)                    {                        lock (_gate)                        {                            ForwardOnError(exception);                        }                        return;                    }                    var closingObserver = new BufferClosingObserver(this);                    Disposable.TrySetSerial(ref _bufferClosingSerialDisposable, closingObserver);                    closingObserver.SetResource(bufferClose.SubscribeSafe(closingObserver));                }                private void CloseBuffer(IDisposable closingSubscription)                {                    closingSubscription.Dispose();                    lock (_gate)                    {                        var res = _buffer;                        _buffer = new List<TSource>();                        ForwardOnNext(res);                    }                    _bufferGate.Wait(this, @this => @this.CreateBufferClose());                }                private sealed class BufferClosingObserver : SafeObserver<TBufferClosing>                {                    private readonly _ _parent;                    public BufferClosingObserver(_ parent)                    {                        _parent = parent;                    }                    public override void OnNext(TBufferClosing value)                    {                        _parent.CloseBuffer(this);                    }                    public override void OnError(Exception error)                    {                        _parent.OnError(error);                    }                    public override void OnCompleted()                    {                        _parent.CloseBuffer(this);                    }                }                public override void OnNext(TSource value)                {                    lock (_gate)                    {                        _buffer.Add(value);                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        _buffer.Clear();                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        ForwardOnNext(_buffer);                        ForwardOnCompleted();                    }                }            }        }        internal sealed class Boundaries : Producer<IList<TSource>, Boundaries._>        {            private readonly IObservable<TSource> _source;            private readonly IObservable<TBufferClosing> _bufferBoundaries;            public Boundaries(IObservable<TSource> source, IObservable<TBufferClosing> bufferBoundaries)            {                _source = source;                _bufferBoundaries = bufferBoundaries;            }            protected override _ CreateSink(IObserver<IList<TSource>> observer) => new _(observer);            protected override void Run(_ sink) => sink.Run(this);            internal sealed class _ : Sink<TSource, IList<TSource>>            {                private readonly object _gate = new object();                public _(IObserver<IList<TSource>> observer)                    : base(observer)                {                }                private IList<TSource> _buffer;                private IDisposable _boundariesDisposable;                public void Run(Boundaries parent)                {                    _buffer = new List<TSource>();                    Run(parent._source);                    Disposable.SetSingle(ref _boundariesDisposable, parent._bufferBoundaries.SubscribeSafe(new BufferClosingObserver(this)));                }                protected override void Dispose(bool disposing)                {                    if (disposing)                    {                        Disposable.TryDispose(ref _boundariesDisposable);                    }                    base.Dispose(disposing);                }                private sealed class BufferClosingObserver : IObserver<TBufferClosing>                {                    private readonly _ _parent;                    public BufferClosingObserver(_ parent)                    {                        _parent = parent;                    }                    public void OnNext(TBufferClosing value)                    {                        lock (_parent._gate)                        {                            var res = _parent._buffer;                            _parent._buffer = new List<TSource>();                            _parent.ForwardOnNext(res);                        }                    }                    public void OnError(Exception error)                    {                        _parent.OnError(error);                    }                    public void OnCompleted()                    {                        _parent.OnCompleted();                    }                }                public override void OnNext(TSource value)                {                    lock (_gate)                    {                        _buffer.Add(value);                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        _buffer.Clear();                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        ForwardOnNext(_buffer);                        ForwardOnCompleted();                    }                }            }        }    }}
 |