Пример #1
0
                private void SetFinal(Exception error)
                {
                    Debug.Assert(error is not null);

                    var state = Atomic.Lock(ref _state);

                    switch (state)
                    {
                    case _sInitial:
                        _tsDelay.Reset();
                        _state = _sFinal;
                        _ctr.Dispose();
                        _tsDelay.SetException(error);
                        break;

                    case _sWaiting:
                        _state = _sFinal;
                        _ctr.Dispose();
                        _tsDelay.SetException(error);
                        break;

                    case _sFinal:
                        _state = _sFinal;
                        break;

                    default:
                        _state = state;
                        throw new Exception(_state + "???");
                    }
                }
Пример #2
0
        /// <inheritdoc />
        public ValueTask <bool> MoveNextAsync()
        {
            var state = Atomic.Lock(ref _state);

            switch (state)
            {
            case _sInitial:
                _state = _sInitial;
                throw new InvalidOperationException("GetAsyncEnumerator was not called.");

            case _sEmitting:
                _tsAccepting.Reset();
                _state = _sAccepting;
                _tsEmitting.SetResult(true);
                return(_tsAccepting.Task);

            case _sAccepting:
                _state = _sAccepting;
                throw new InvalidOperationException("MoveNextAsync is not reentrant.");

            case _sFinal:
                Current = default;
                _state  = _sFinal;
                return(new(_atmbFinal.Task));

            default:
                _state = state;
                throw new Exception(state + "???");
            }
        }
Пример #3
0
        private void SetFinal(Exception error)
        {
            var state = Atomic.Lock(ref _state);

            switch (state)
            {
            case _sInitial:
                _state = _sInitial;
                throw new InvalidOperationException();

            case _sEmitting:
                _state = _sFinal;
                _ctr.Dispose();
                _atmbFinal.SetExceptionOrResult(error, false);
                _tsEmitting.SetResult(false);
                break;

            case _sAccepting:
                Current = default;
                _state  = _sFinal;
                _ctr.Dispose();
                _atmbFinal.SetExceptionOrResult(error, false);
                _tsAccepting.SetExceptionOrResult(error, false);
                break;

            default:     // _sFinal
                _state = state;
                break;
            }
        }
Пример #4
0
            public ValueTuple <T1, T2>?OnNext2(T2 value)
            {
                var missing = Atomic.Lock(ref _missing) & ~(1 << 1);

                _value2 = value;
                var result = missing == 0 ? new ValueTuple <T1, T2>(_value1, _value2): default;

                _missing = missing;
                return(result);
            }
Пример #5
0
            private async void MoveNextAsync(Func <ConfiguredValueTaskAwaitable <bool> > moveNext)
            {
                bool      completed;
                Exception error;

                if (_completed)
                {
                    completed = false;
                    error     = null;
                }
                else
                {
                    try
                    {
                        completed = !await moveNext();

                        error = null;
                    }
                    catch (Exception ex)
                    {
                        completed = true;
                        error     = ex;
                    }
                }

                var a = Atomic.Lock(ref _active) - 1;

                if (completed)
                {
                    if (_completed)        // someone was faster, ignore result
                    {
                        completed = false; // prevent cancellation below
                    }
                    else
                    {
                        _completed = true;
                        _error     = error;
                    }
                }
                _active = a;

                if (completed)
                {
                    _cts.TryCancel();
                }
                if (a == 0)
                {
                    _ts.SetExceptionOrResult(_error, !_completed);
                }
            }
Пример #6
0
            public void SetError(Exception error)
            {
                var a = Atomic.Lock(ref _active);

                if (_completed)
                {
                    _active = a;
                    return;
                }

                _completed = true;
                _error     = error;
                _active    = a;
                _cts.TryCancel();
            }
Пример #7
0
        public IAsyncEnumerator <T> GetAsyncEnumerator(CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                return(new LinxAsyncEnumerable.ThrowIterator <T>(new OperationCanceledException(token)));
            }

            var state = Atomic.Lock(ref _state);

            if (state != _sInitial)
            {
                _state = state;
                return(new CoroutineIterator <T>(this).GetAsyncEnumerator(token));
            }

            try
            {
                _tsAccepting = new();
                _tsEmitting  = new();
                _tsEmitting.Reset();
                _state = _sEmitting;
                Produce(token);
                if (token.CanBeCanceled)
                {
                    _ctr = token.Register(() => SetFinal(new OperationCanceledException(token)));
                }
                return(this);
            }
            catch (Exception ex)
            {
                _state        = Atomic.LockBit;
                Current       = default;
                _tsAccepting  = default;
                _tsEmitting   = default;
                _atmbFinal    = default;
                _atmbDisposed = default;
                _ctr          = default;
                _state        = _sFinal;
                _atmbFinal.SetException(ex);
                _atmbDisposed.SetResult();
                return(new LinxAsyncEnumerable.ThrowIterator <T>(ex));
            }
        }
Пример #8
0
                public ValueTask Delay(TimeSpan due)
                {
                    var state = Atomic.Lock(ref _state);

                    switch (state)
                    {
                    case _sInitial:
                        _tsDelay.Reset();
                        if (due > TimeSpan.Zero)
                        {
                            _state = _sWaiting;
                            try { _timer.Change(due, Timeout.InfiniteTimeSpan); }
                            catch (Exception ex)
                            {
                                if (Atomic.CompareExchange(ref _state, _sInitial, _sWaiting) == _sWaiting)
                                {
                                    _tsDelay.SetException(ex);
                                }
                            }
                        }
                        else
                        {
                            _state = _sInitial;
                            _tsDelay.SetResult();
                        }
                        return(_tsDelay.Task);

                    case _sFinal:
                        _state = _sFinal;
                        return(_tsDelay.Task);

                    case _sWaiting:
                        _state = _sWaiting;
                        throw new InvalidOperationException(Strings.MethodIsNotReentrant);

                    default:
                        _state = state;
                        throw new Exception(state + "???");
                    }
                }
Пример #9
0
        private ValueTask <bool> YieldAsync(T item)
        {
            var state = Atomic.Lock(ref _state);

            switch (state)
            {
            case _sAccepting:
                Current = item;
                _tsEmitting.Reset();
                _state = _sEmitting;
                _tsAccepting.SetResult(true);
                return(_tsEmitting.Task);

            case _sFinal:
                _state = _sFinal;
                return(new(false));

            default:
                _state = state;
                throw new InvalidOperationException(state + "???");
            }
        }
Пример #10
0
        /// <summary>
        /// Prune cache.
        /// </summary>
        void Prune(object _discard, System.Timers.ElapsedEventArgs _2)
        {
            if (disposed)
            {
                return;                       // dumbness with timers
            }
            if (!Atomic.Lock(ref prune_in_progress))
            {
                return;                                                  // only one instance.
            }
            try
            {
                if (Items.Count <= MinCache)
                {
                    return;                                          // just don't bother
                }
                if (Items.Count <= AbsoluteCapacity && CacheEvictStrategy == EvictStrategy.LeastUsed)
                {
                    return;
                }

                var list = Items.Values.ToList();                 // would be nice to cache this list

                list.Sort((CacheItem <TKey, TValue> x, CacheItem <TKey, TValue> y) =>
                {
                    if (CacheEvictStrategy == EvictStrategy.LeastRecent)
                    {
                        if (x.Access < y.Access)
                        {
                            return(-1);
                        }
                        if (x.Access > y.Access)
                        {
                            return(1);
                        }
                        // Both have equal at this point
                        if (x.Desirability < y.Desirability)
                        {
                            return(-1);
                        }
                        if (x.Desirability > y.Desirability)
                        {
                            return(1);
                        }
                    }
                    else                     // EvictStrategy.LeastUsed
                    {
                        if (x.Desirability < y.Desirability)
                        {
                            return(-1);
                        }
                        if (x.Desirability > y.Desirability)
                        {
                            return(1);
                        }
                        // Both have equal at this point
                        if (x.Access < y.Access)
                        {
                            return(-1);
                        }
                        if (x.Access > y.Access)
                        {
                            return(1);
                        }
                    }

                    return(0);
                });

                while (Items.Count > AbsoluteCapacity)
                {
                    var bu  = list[0];
                    var key = bu.AccessKey;
                    Items.TryRemove(key, out _);
                    list.Remove(bu);
                }

                var deleteItem = new Action <TKey>(
                    (TKey key) =>
                {
                    //Debug.WriteLine($"MKAh.SimpleCache removing {bi:N1} min old item.");
                    if (Items.TryRemove(key, out var item))
                    {
                        list.Remove(item);
                    }
                }
                    );

                var now = DateTimeOffset.UtcNow;
                while (list.Count > 0)
                {
                    var    bu = list[0];
                    double bi = now.Since(bu.Access).TotalMinutes;

                    if (CacheEvictStrategy == EvictStrategy.LeastRecent)
                    {
                        if (bi > MaxAge)
                        {
                            deleteItem(bu.AccessKey);
                        }
                        else
                        {
                            break;
                        }
                    }
                    else                     // .LeastUsed
                    {
                        if (bi > MinAge)
                        {
                            deleteItem(bu.AccessKey);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            finally
            {
                Atomic.Unlock(ref prune_in_progress);
            }
        }