Пример #1
0
        public static Progressor <T> CreateFromArray(T[] array)
        {
            if (array == null)
            {
                throw new ArgumentNullException(nameof(array));
            }

            var index = -1;
            var proxy = new ProxyObservable <T>();

            return(new Progressor <T>(proxy, (out T value) => Take(out value)));

            bool Take(out T value)
            {
                value = default !;
Пример #2
0
        public Progressor(Progressor <T> wrapped)
        {
            if (wrapped == null)
            {
                throw new ArgumentNullException("wrapped");
            }

            var control = 0;

            Predicate <T> newFilter = item => Thread.VolatileRead(ref control) == 0;
            var           buffer    = new SafeQueue <T>();

            wrapped.SubscribeAction
            (
                item =>
            {
                if (newFilter(item))
                {
                    buffer.Add(item);
                }
            }
            );
            _proxy = new ProxyObservable <T>();

            _tryTake = (out T value) =>
            {
                Interlocked.Increment(ref control);
                try
                {
                    if (buffer.TryTake(out value) || wrapped.TryTake(out value))
                    {
                        _proxy.OnNext(value);
                        return(true);
                    }
                    else
                    {
                        _done = wrapped._done;
                        return(false);
                    }
                }
                finally
                {
                    Interlocked.Decrement(ref control);
                }
            };
        }
Пример #3
0
 public Progressor(TryTake <T> tryTake, Func <bool> isDone)
 {
     if (tryTake == null)
     {
         throw new ArgumentNullException("tryTake");
     }
     _proxy   = new ProxyObservable <T>();
     _tryTake = (out T value) =>
     {
         // This is not an overridable method, and it is not being called on the constructor.
         if (tryTake(out value))
         {
             _proxy.OnNext(value);
             return(true);
         }
         _done = isDone();
         return(false);
     };
 }
Пример #4
0
        public Progressor(T[] wrapped)
        {
            if (wrapped == null)
            {
                throw new ArgumentNullException("wrapped");
            }

            var guard = 0;
            var index = -1;

            _proxy = new ProxyObservable <T>();

            TryTake <T> tryTakeReplacement = (out T value) =>
            {
                value = default(T);
                return(false);
            };

            _tryTake = (out T value) =>
            {
                value = default(T);
                if (Thread.VolatileRead(ref guard) == 0)
                {
                    var currentIndex = Interlocked.Increment(ref index);
                    if (currentIndex < wrapped.Length)
                    {
                        value = wrapped[currentIndex];
                        _proxy.OnNext(value);
                        return(true);
                    }
                    Interlocked.CompareExchange(ref guard, 1, 0);
                }
                if (Interlocked.CompareExchange(ref guard, 2, 1) == 1)
                {
                    _tryTake = tryTakeReplacement;
                }
                return(false);
            };
        }
Пример #5
0
 public void Close()
 {
     _tryTake = null;
     _proxy.OnCompleted();
     _proxy = null;
 }
Пример #6
0
        public Progressor(IEnumerable <T> preface, Progressor <T> wrapped)
        {
            if (wrapped == null)
            {
                throw new ArgumentNullException("wrapped");
            }
            if (preface == null)
            {
                throw new ArgumentNullException("preface");
            }
            var enumerator = preface.GetEnumerator();

            if (enumerator == null)
            {
                throw new ArgumentException("preface.GetEnumerator()");
            }

            var control = 0;
            var guard   = 0;

            Predicate <T> newFilter = item => Thread.VolatileRead(ref control) == 0;
            var           buffer    = new SafeQueue <T>();

            wrapped.SubscribeAction
            (
                item =>
            {
                if (newFilter(item))
                {
                    buffer.Add(item);
                }
            }
            );
            _proxy = new ProxyObservable <T>();

            TryTake <T> tryTakeReplacement = (out T value) =>
            {
                Interlocked.Increment(ref control);
                try
                {
                    if (buffer.TryTake(out value) || wrapped.TryTake(out value))
                    {
                        _proxy.OnNext(value);
                        return(true);
                    }
                    else
                    {
                        _done = wrapped._done;
                        return(false);
                    }
                }
                finally
                {
                    Interlocked.Decrement(ref control);
                }
            };

            _tryTake = (out T value) =>
            {
                value = default(T);
                if (Thread.VolatileRead(ref guard) == 0)
                {
                    bool result;
                    // We need a lock, there is no way around it. IEnumerator is just awful. Use another overload if possible.
                    lock (enumerator)
                    {
                        result = enumerator.MoveNext();
                        if (result)
                        {
                            value = enumerator.Current;
                        }
                    }
                    if (result)
                    {
                        _proxy.OnNext(value);
                        return(true);
                    }
                    enumerator.Dispose();
                    Interlocked.CompareExchange(ref guard, 1, 0);
                }
                if (Interlocked.CompareExchange(ref guard, 2, 1) == 1)
                {
                    _tryTake = tryTakeReplacement;
                    Thread.VolatileWrite(ref guard, 3);
                }
                else
                {
                    ThreadingHelper.SpinWaitUntil(ref guard, 3);
                }
                var tryTake = _tryTake;
                return(tryTake(out value));
            };
        }
Пример #7
0
        public static Progressor <T> CreateDistinct(Progressor <T> wrapped)
        {
            if (wrapped == null)
            {
                throw new ArgumentNullException("wrapped");
            }

            var control = 0;

            SafeDictionary <T, bool> buffer    = new SafeDictionary <T, bool>();
            Predicate <T>            newFilter = item => Thread.VolatileRead(ref control) == 0;
            var proxy = new ProxyObservable <T>();

            Progressor <T> result = new Progressor <T>(
                (out T value) =>
            {
                Interlocked.Increment(ref control);
                try
                {
                    again:
                    foreach (KeyValuePair <T, bool> item in buffer)
                    {
                        if (!item.Value)
                        {
                            value = item.Key;
                            buffer.Set(value, true);
                            proxy.OnNext(value);
                            return(true);
                        }
                    }
                    if (wrapped.TryTake(out value))
                    {
                        bool seen;
                        if (!buffer.TryGetValue(value, out seen) || !seen)
                        {
                            buffer.Set(value, true);
                            proxy.OnNext(value);
                            return(true);
                        }
                        else
                        {
                            goto again;
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
                finally
                {
                    Interlocked.Decrement(ref control);
                }
            },
                proxy
                );

            wrapped.Subscribe
            (
                new CustomObserver <T>
                (
                    () => result._done        = true,
                    exception => result._done = true,
                    item =>
            {
                if (newFilter(item))
                {
                    buffer.TryAdd(item, false);
                }
            }
                )
            );
            return(result);
        }
Пример #8
0
        public static Progressor <T> CreatedFilteredConverted <TInput>(Progressor <TInput> wrapped, Predicate <TInput> filter, Converter <TInput, T> converter)
        {
            if (wrapped == null)
            {
                throw new ArgumentNullException("wrapped");
            }
            if (filter == null)
            {
                throw new ArgumentNullException("filter");
            }
            if (converter == null)
            {
                throw new ArgumentNullException("converter");
            }

            var control = 0;

            Predicate <TInput> newFilter = item => Thread.VolatileRead(ref control) == 0 && filter(item);
            var buffer = new SafeQueue <T>();
            var proxy  = new ProxyObservable <T>();

            var result = new Progressor <T>(
                (out T value) =>
            {
                Interlocked.Increment(ref control);
                try
                {
                    TInput item;
                    again:
                    if (buffer.TryTake(out value))
                    {
                        proxy.OnNext(value);
                        return(true);
                    }
                    else if (wrapped.TryTake(out item))
                    {
                        if (filter(item))
                        {
                            value = converter(item);
                            proxy.OnNext(value);
                            return(true);
                        }
                        else
                        {
                            goto again;
                        }
                    }
                    value = default(T);
                    return(false);
                }
                finally
                {
                    Interlocked.Decrement(ref control);
                }
            },
                proxy
                );

            wrapped.Subscribe
            (
                new CustomObserver <TInput>
                (
                    () => result._done        = true,
                    exception => result._done = true,
                    item =>
            {
                if (newFilter(item))
                {
                    buffer.Add(converter(item));
                }
            }
                )
            );
            return(result);
        }
Пример #9
0
 private Progressor(TryTake <T> tryTake, ProxyObservable <T> proxy)
 {
     _proxy   = proxy;
     _tryTake = tryTake;
 }
Пример #10
0
        public Progressor(T[] preface, Progressor <T> wrapped)
        {
            if (wrapped == null)
            {
                throw new ArgumentNullException("wrapped");
            }
            if (preface == null)
            {
                throw new ArgumentNullException("preface");
            }

            var control = 0;
            var guard   = 0;
            var index   = -1;

            Predicate <T> newFilter = item => Thread.VolatileRead(ref control) == 0;
            var           buffer    = new SafeQueue <T>();

            wrapped.SubscribeAction
            (
                item =>
            {
                if (newFilter(item))
                {
                    buffer.Add(item);
                }
            }
            );
            _proxy = new ProxyObservable <T>();

            TryTake <T> tryTakeReplacement = (out T value) =>
            {
                Interlocked.Increment(ref control);
                try
                {
                    if (buffer.TryTake(out value) || wrapped.TryTake(out value))
                    {
                        _proxy.OnNext(value);
                        return(true);
                    }
                    else
                    {
                        _done = wrapped._done;
                        return(false);
                    }
                }
                finally
                {
                    Interlocked.Decrement(ref control);
                }
            };

            _tryTake = (out T value) =>
            {
                if (Thread.VolatileRead(ref guard) == 0)
                {
                    var currentIndex = Interlocked.Increment(ref index);
                    if (currentIndex < preface.Length)
                    {
                        value = preface[currentIndex];
                        _proxy.OnNext(value);
                        return(true);
                    }
                    Interlocked.CompareExchange(ref guard, 1, 0);
                }
                if (Interlocked.CompareExchange(ref guard, 2, 1) == 1)
                {
                    _tryTake = tryTakeReplacement;
                    Thread.VolatileWrite(ref guard, 3);
                }
                else
                {
                    ThreadingHelper.SpinWaitUntil(ref guard, 3);
                }
                var tryTake = _tryTake;
                return(tryTake(out value));
            };
        }
Пример #11
0
        public static Progressor <T> CreateFromIObservable(IObservable <T> observable, Action exhaustedCallback = null, CancellationToken token = default)
        {
            if (observable == null)
            {
                throw new ArgumentNullException(nameof(observable));
            }

            if (exhaustedCallback == null)
            {
                exhaustedCallback = ActionHelper.GetNoopAction();
            }

            var buffer       = new ThreadSafeQueue <T>();
            var semaphore    = new SemaphoreSlim(0);
            var source       = new CancellationTokenSource();
            var subscription = observable.Subscribe
                               (
                new CustomObserver <T>
                (
                    source.Cancel,
                    _ => source.Cancel(),
                    OnNext
                )
                               );
            var proxy   = new ProxyObservable <T>();
            var tryTake = new TryTake <T>[] { null };

            tryTake[0] = TakeInitial;

            void OnNext(T item)
            {
                buffer.Add(item);
                semaphore.Release();
            }

            bool TakeInitial(out T value)
            {
                if (source.IsCancellationRequested || token.IsCancellationRequested)
                {
                    if (Interlocked.CompareExchange(ref tryTake[0], TakeReplacement, tryTake[0]) == tryTake[0])
                    {
                        Interlocked.Exchange(ref subscription, null)?.Dispose();
                        semaphore.Dispose();
                        source.Dispose();
                    }
                }
                else
                {
                    if (exhaustedCallback != null)
                    {
                        var spinWait = new SpinWait();
                        while
                        (
                            semaphore.CurrentCount == 0 &&
                            !source.IsCancellationRequested &&
                            !token.IsCancellationRequested
                        )
                        {
                            exhaustedCallback();
                            spinWait.SpinOnce();
                        }
                    }
                }

                if (source.IsCancellationRequested || token.IsCancellationRequested)
                {
                    return(TakeReplacement(out value));
                }

                try
                {
                    semaphore.Wait(source.Token);
                }
                catch (OperationCanceledException exception)
                {
                    No.Op(exception);
                }

                return(TakeReplacement(out value));
            }

            bool TakeReplacement(out T value)
            {
                if (buffer.TryTake(out value))
                {
                    return(true);
                }

                value = default;
                return(false);
            }

            bool Take(out T value)
            {
                return(tryTake[0](out value));
            }

            return(new Progressor <T>(proxy, Take));
        }