/// <summary> /// Subscribes the observer to this subject and /// relays the live items or replays the terminal /// event to it. /// </summary> /// <param name="observer">The observer to dispatch signals to.</param> public void Subscribe(ISignalObserver <T> observer) { ValidationHelper.RequireNonNullRef(observer, nameof(observer)); var parent = new PublishDisposable(observer, this); observer.OnSubscribe(parent); if (Add(parent)) { if (parent.IsDisposed()) { Remove(parent); } } else { var ex = error; if (ex != ExceptionHelper.TERMINATED) { parent.OnError(ex); } else { parent.OnCompleted(); } } }
void Remove(PublishDisposable inner) { for (; ;) { var a = Volatile.Read(ref observers); var n = a.Length; if (n == 0) { break; } int j = Array.IndexOf(a, inner); if (j < 0) { break; } var b = default(PublishDisposable[]); if (n == 1) { if (refCount) { if (Interlocked.CompareExchange(ref observers, Terminated, a) == a) { DisposableHelper.Dispose(ref upstream); break; } continue; } b = Empty; } else { b = new PublishDisposable[n - 1]; Array.Copy(a, 0, b, 0, j); Array.Copy(a, j + 1, b, j, n - j - 1); } if (Interlocked.CompareExchange(ref observers, b, a) == a) { break; } } }
bool Add(PublishDisposable inner) { for (; ;) { var a = Volatile.Read(ref observers); if (a == Terminated) { return(false); } var n = a.Length; var b = new PublishDisposable[n + 1]; Array.Copy(a, 0, b, 0, n); b[n] = inner; if (Interlocked.CompareExchange(ref observers, b, a) == a) { return(true); } } }