bool Add(AsyncSubjectDisposable inner) { for (; ;) { var a = Volatile.Read(ref _observers); if (a == DISPOSED) { _value = default(T); _exception = null; ThrowDisposed(); return(true); } if (a == TERMINATED) { return(false); } var n = a.Length; var b = new AsyncSubjectDisposable[n + 1]; Array.Copy(a, 0, b, 0, n); b[n] = inner; if (Interlocked.CompareExchange(ref _observers, b, a) == a) { return(true); } } }
/// <summary> /// Subscribes an observer to the subject. /// </summary> /// <param name="observer">Observer to subscribe to the subject.</param> /// <returns>Disposable object that can be used to unsubscribe the observer from the subject.</returns> /// <exception cref="ArgumentNullException"><paramref name="observer"/> is <c>null</c>.</exception> public override IDisposable Subscribe(IObserver <T> observer) { if (observer == null) { throw new ArgumentNullException(nameof(observer)); } var parent = new AsyncSubjectDisposable(this, observer); if (!Add(parent)) { var ex = _exception; if (ex != null) { observer.OnError(ex); } else { if (_hasValue) { observer.OnNext(_value); } observer.OnCompleted(); } return(Disposable.Empty); } return(parent); }
void Remove(AsyncSubjectDisposable inner) { for (; ;) { var a = Volatile.Read(ref _observers); var n = a.Length; if (n == 0) { break; } var j = -1; for (var i = 0; i < n; i++) { if (a[i] == inner) { j = i; break; } } if (j < 0) { break; } var b = default(AsyncSubjectDisposable[]); if (n == 1) { b = EMPTY; } else { b = new AsyncSubjectDisposable[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; } } }