void InnerNext(InnerSubscriber inner, T item) { if (Volatile.Read(ref wip) == 0 && Interlocked.CompareExchange(ref wip, 1, 0) == 0) { long r = Volatile.Read(ref requested); long e = emitted; if (e != r) { actual.OnNext(item); emitted = e + 1; inner.Produced(limit); } else { var q = inner.GetOrCreateQueue(limit); q.Offer(item); } int w = Interlocked.Decrement(ref wip); if (w == 0) { return; } DrainLoop(w); } else { var q = inner.GetOrCreateQueue(limit); q.Offer(item); if (Interlocked.Increment(ref wip) != 1) { return; } DrainLoop(1); } }
public void OnNext(T element) { if (done) { return; } IPublisher <R> p; try { p = mapper(element); if (p == null) { throw new NullReferenceException("The mapper returned a null IPublisher"); } } catch (Exception ex) { upstream.Cancel(); OnError(ex); return; } InnerSubscriber inner = new InnerSubscriber(this, prefetch); if (Add(inner)) { p.Subscribe(inner); } }
void InnerError(InnerSubscriber inner, Exception cause) { ExceptionHelper.AddException(ref error, cause); Volatile.Write(ref inner.done, true); Interlocked.Decrement(ref done); Drain(); }
public PublisherConcatMap(ISubscriber <R> actual, Func <T, IPublisher <R> > mapper, int prefetch) { this.actual.Init(actual); this.prefetch = prefetch; this.mapper = mapper; this.inner = new InnerSubscriber(actual, this); }
public void Clear() { current = null; var s = subscribers; var n = s.Length; int ci = consumerIndex; for (;;) { var inner = Volatile.Read(ref s[ci]); if (inner == null || inner == CancelledInner) { break; } if (Interlocked.CompareExchange(ref s[ci], null, inner) == inner) { ci++; if (ci == n) { ci = 0; } } } consumerIndex = ci; }
internal ConcatMapSubscriber(IFlowableSubscriber<R> actual, Func<T, IPublisher<R>> mapper, int prefetch) { this.actual = actual; this.mapper = mapper; this.prefetch = prefetch; this.limit = prefetch - (prefetch >> 2); this.inner = new InnerSubscriber(actual, this); }
public IDisposable Subscribe(IObserver <T> observer) { InnerSubscriber inner = new InnerSubscriber(observer, second); first.Subscribe(inner); return(inner); }
public void Cancel() { upstream.Cancel(); CancelAll(); if (Interlocked.Increment(ref wip) != 1) { current = null; } }
void DrainLoopFused() { int missed = 1; var s = subscribers; var n = s.Length; var curr = current; var a = actual; for (;;) { if (Volatile.Read(ref cancelled)) { current = null; return; } bool d = Volatile.Read(ref done); int ci = consumerIndex; curr = Volatile.Read(ref s[ci]); if (curr != null) { a.OnNext(default(R)); } if (d) { var ex = ExceptionHelper.Terminate(ref error); if (ex == null) { a.OnComplete(); } else { a.OnError(ex); } return; } int w = Volatile.Read(ref wip); if (w == missed) { missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } else { missed = w; } } }
public ReduceFullCoordinator(ISubscriber <T> actual, int n, Func <T, T, T> reducer) : base(actual) { var a = new InnerSubscriber[n]; for (int i = 0; i < n; i++) { a[i] = new InnerSubscriber(this, reducer); } this.subscribers = a; this.reducer = reducer; Volatile.Write(ref remaining, n); }
internal OrderedJoin(ISubscriber <T> actual, int n, int prefetch) { this.actual = actual; var a = new InnerSubscriber[n]; for (int i = 0; i < n; i++) { a[i] = new InnerSubscriber(this, prefetch); } this.subscribers = a; this.peek = new IOrderedItem <T> [n]; }
internal BaseWithLatestFomrSubscriber(int n, Func <T[], R> combiner) { var s = new IDisposable[n]; for (int i = 0; i < n; i++) { s[i] = new InnerSubscriber(this, i); } this.subscribers = s; this.values = new Node[n]; this.n = n; this.combiner = combiner; }
internal JoinSubscription(IFlowableSubscriber <T> actual, int n, int bufferSize) { this.actual = actual; this.bufferSize = bufferSize; this.done = n; this.limit = bufferSize - (bufferSize >> 2); var subs = new InnerSubscriber[n]; for (int i = 0; i < n; i++) { subs[i] = new InnerSubscriber(this); } this.subscribers = subs; }
bool Remove(InnerSubscriber inner) { var s = subscribers; var n = s.Length; int ci = consumerIndex; if (Interlocked.CompareExchange(ref s[ci], null, inner) == inner) { ci++; consumerIndex = ci == n ? 0 : ci; return(true); } return(false); }
bool Add(InnerSubscriber inner) { var s = subscribers; var n = s.Length; int pi = producerIndex; if (Interlocked.CompareExchange(ref s[pi], inner, null) == null) { pi++; producerIndex = pi == n ? 0 : pi; return(true); } return(false); }
internal SortedJoinSubscription(ISubscriber <T> actual, int n, IComparer <T> comparer) { this.actual = actual; this.values = new IList <T> [n]; this.indexes = new int[n]; var a = new InnerSubscriber[n]; for (int i = 0; i < n; i++) { a[i] = new InnerSubscriber(this, i); } this.subscribers = a; this.remaining = n; this.comparer = comparer; }
bool SetInner(InnerSubscriber b) { for (;;) { var a = Volatile.Read(ref inner); if (a == Cancelled) { return(false); } if (Interlocked.CompareExchange(ref inner, b, a) == a) { return(true); } } }
void InnerNext(InnerSubscriber inner, R item) { if (Volatile.Read(ref wip) == 0 && Interlocked.CompareExchange(ref wip, 1, 0) == 0) { var q = Volatile.Read(ref inner.queue); bool offer = true; if (current == inner) { if (q == null || q.IsEmpty()) { var e = emitted; if (e != Volatile.Read(ref requested)) { actual.OnNext(item); emitted = e + 1; inner.RequestOne(); offer = false; } } } if (offer) { if (q == null) { q = inner.GetOrCreateQueue(); } q.Offer(item); } if (Interlocked.Decrement(ref wip) == 0) { return; } } else { var q = inner.GetOrCreateQueue(); q.Offer(item); if (Interlocked.Increment(ref wip) != 1) { return; } } DrainLoop(); }
public void OnNext(T element) { var curr = Volatile.Read(ref current); if (curr != Terminated) { curr?.Cancel(); IPublisher <R> p; try { p = mapper(element); if (p == null) { throw new NullReferenceException("The mapper returned a null IPublisher"); } } catch (Exception ex) { upstream.Cancel(); OnError(ex); return; } var inner = new InnerSubscriber(this, prefetch); for (;;) { curr = Volatile.Read(ref current); if (curr == Terminated) { break; } if (Interlocked.CompareExchange(ref current, inner, curr) == curr) { p.Subscribe(inner); break; } } } }
public bool Poll(out R item) { var curr = current; var s = subscribers; var n = s.Length; for (;;) { if (curr == null) { int ci = consumerIndex; curr = Volatile.Read(ref s[ci]); if (curr == null) { item = default(R); return(false); } current = curr; } if (curr != null) { bool d = Volatile.Read(ref curr.done); var q = Volatile.Read(ref curr.queue); if (q != null && q.Poll(out item)) { return(true); } if (d) { Remove(curr); int ci = consumerIndex + 1; consumerIndex = ci == n ? 0 : ci; current = null; curr = null; upstream.Request(1); continue; } } item = default(R); return(false); } }
public void Subscribe(IPublisher <T>[] sources, int n) { values = new T[n]; nonempty = new ulong[1 + ((n - 1) >> 4)]; InnerSubscriber[] a = new InnerSubscriber[n]; for (int i = 0; i < n; i++) { a[i] = new InnerSubscriber(this, i); } subscribers = a; actual.OnSubscribe(this); for (int i = 0; i < n; i++) { if (bp.IsCancelled() || LvDone()) { break; } sources[i].Subscribe(a[i]); } }
void InnerComplete(InnerSubscriber inner) { Volatile.Write(ref inner.done, true); Interlocked.Decrement(ref done); Drain(); }
void Drain() { if (Interlocked.Increment(ref wip) != 1) { return; } int missed = 1; var a = actual; var q = queue; var m = q.Length - 1; var e = emitted; var c = consumed; var ci = consumerIndex; var lim = limit; for (;;) { long r = Volatile.Read(ref requested); while (e != r) { if (Volatile.Read(ref cancelled)) { ClearQueue(q, m + 1); return; } bool d = Volatile.Read(ref done); int offset = (int)ci & m; bool empty = Volatile.Read(ref q[offset].state) == 0; if (d && empty) { Exception ex = ExceptionHelper.Terminate(ref error); if (ex != null) { a.OnError(ex); } else { a.OnComplete(); } return; } if (empty) { break; } T t = q[offset].item; int s = Volatile.Read(ref state); if (s == STATE_FRESH) { IPublisher <bool> pub; try { pub = predicate(t); } catch (Exception ex) { upstream.Cancel(); a.OnError(ex); return; } if (pub is IVariableSource <bool> vu) { q[offset].item = default(T); q[offset].state = 0; if (vu.Value(out bool u)) { if (u) { a.OnNext(t); e++; } } ci++; if (++c == lim) { c = 0; upstream.Request(lim); } } else { InnerSubscriber sub = new InnerSubscriber(this); if (SetInner(sub)) { Volatile.Write(ref state, STATE_RUNNING); pub.Subscribe(sub); } } } else if (s == STATE_RESULT_EMPTY) { q[offset].item = default(T); q[offset].state = 0; ci++; Volatile.Write(ref state, STATE_FRESH); if (++c == lim) { c = 0; upstream.Request(lim); } } else if (s == STATE_RESULT_VALUE) { q[offset].item = default(T); q[offset].state = 0; a.OnNext(t); e++; ci++; Volatile.Write(ref state, STATE_FRESH); if (++c == lim) { c = 0; upstream.Request(lim); } } } if (e == r) { if (Volatile.Read(ref cancelled)) { ClearQueue(q, m + 1); return; } bool d = Volatile.Read(ref done); int offset = (int)ci & m; bool empty = Volatile.Read(ref q[offset].state) == 0; if (d && empty) { Exception ex = ExceptionHelper.Terminate(ref error); if (ex != null) { a.OnError(ex); } else { a.OnComplete(); } return; } } int w = Volatile.Read(ref wip); if (w == missed) { consumed = c; emitted = e; consumerIndex = ci; missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } else { missed = w; } } }
void DrainLoopAsync() { int missed = 1; var s = subscribers; var n = s.Length; var curr = current; var e = emitted; var a = actual; for (;;) { if (curr == null) { if (Volatile.Read(ref cancelled)) { return; } bool d = Volatile.Read(ref done); int ci = consumerIndex; curr = Volatile.Read(ref s[ci]); if (d && curr == null) { current = null; var ex = ExceptionHelper.Terminate(ref error); if (ex == null) { a.OnComplete(); } else { a.OnError(ex); } return; } if (curr == CancelledInner) { current = null; return; } } if (curr != null) { long r = Volatile.Read(ref requested); if (Volatile.Read(ref cancelled)) { current = null; return; } bool d = Volatile.Read(ref curr.done); var q = Volatile.Read(ref curr.queue); if (d && q == null) { Remove(curr); curr = null; } else if (q != null) { while (e != r) { if (Volatile.Read(ref cancelled)) { current = null; return; } d = Volatile.Read(ref curr.done); bool empty = !q.Poll(out R v); if (d && empty) { Remove(curr); curr = null; break; } if (empty) { break; } a.OnNext(v); e++; curr.RequestOne(); } if (e == r) { if (Volatile.Read(ref cancelled)) { current = null; return; } if (Volatile.Read(ref curr.done) && q.IsEmpty()) { Remove(curr); curr = null; } } } if (curr == null) { upstream.Request(1); continue; } } int w = Volatile.Read(ref wip); if (w == missed) { emitted = e; current = curr; missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } else { missed = w; } } }
void DrainLoop() { int missed = 1; var e = emitted; var a = actual; for (;;) { if (Volatile.Read(ref cancelled)) { current = null; return; } bool d = Volatile.Read(ref done); var curr = Volatile.Read(ref current); if (d && curr == null) { Exception ex = ExceptionHelper.Terminate(ref error); if (ex == null) { a.OnComplete(); } else { a.OnError(ex); } return; } if (curr != null) { d = Volatile.Read(ref curr.done); var q = Volatile.Read(ref curr.queue); if (q != null) { if (e != Volatile.Read(ref requested)) { bool empty = !q.Poll(out R v); if (d && empty) { Interlocked.CompareExchange(ref current, null, curr); continue; } if (!empty) { a.OnNext(v); e++; curr.RequestOne(); continue; } } else { if (d && q.IsEmpty()) { Interlocked.CompareExchange(ref current, null, curr); continue; } } } else if (d) { Interlocked.CompareExchange(ref current, null, curr); continue; } } int w = Volatile.Read(ref wip); if (w == missed) { emitted = e; missed = Interlocked.Add(ref wip, -missed); if (missed == 0) { break; } } else { missed = w; } } }
void InnerComplete(InnerSubscriber inner) { Volatile.Write(ref inner.done, true); Drain(); }
void InnerError(InnerSubscriber inner, Exception error) { ExceptionHelper.AddException(ref this.error, error); Volatile.Write(ref inner.done, true); Drain(); }