public void SetShadowSources(double k) { var sArray = new TSource[2 * ParallelBeams.Length]; for (int i1 = 0; i1 < ParallelBeams.Length; ++i1) { int i = 2 * i1; sArray[i] = ParallelBeams[i1]; sArray[i + 1].O = -sArray[i].O; sArray[i + 1].C = -k * sArray[i].C; } ParallelBeams = sArray; }
public DelayObserver(_ parent, TSource value) { _parent = parent; _value = value; }
public void Map(TSource source, TTarget target) { _action(target, _property(source)); }
//--------------------------------------------------------------------------------------- // Straightforward IEnumerator<T> methods. // internal override bool MoveNext([MaybeNullWhen(false), AllowNull] ref TSource currentElement, ref int currentKey) { Debug.Assert(_source != null); if (_alreadySearched) { return(false); } // Look for the greatest element. TSource candidate = default(TSource) !; TKey candidateKey = default(TKey) !; bool candidateFound = false; try { int loopCount = 0; //counter to help with cancellation TSource value = default(TSource) !; TKey key = default(TKey) !; while (_source.MoveNext(ref value !, ref key)) { if ((loopCount & CancellationState.POLL_INTERVAL) == 0) { _cancellationToken.ThrowIfCancellationRequested(); } ; // If the predicate is null or the current element satisfies it, we will remember // it as the current partition's candidate for the last element, and move on. if (_predicate == null || _predicate(value)) { candidate = value; candidateKey = key; candidateFound = true; } loopCount++; } // If we found a candidate element, try to publish it, so long as it's greater. if (candidateFound) { lock (_operatorState) { if (_operatorState._partitionId == -1 || _keyComparer.Compare(candidateKey, _operatorState._key) > 0) { _operatorState._partitionId = _partitionId; _operatorState._key = candidateKey; } } } } finally { // No matter whether we exit due to an exception or normal completion, we must ensure // that we signal other partitions that we have completed. Otherwise, we can cause deadlocks. _sharedBarrier.Signal(); } _alreadySearched = true; // Only if we have a candidate do we wait. if (_partitionId == _operatorState._partitionId) { _sharedBarrier.Wait(_cancellationToken); // Now re-read the shared index. If it's the same as ours, we won and return true. if (_operatorState._partitionId == _partitionId) { currentElement = candidate; currentKey = 0; // 1st (and only) element, so we hardcode the output index to 0. return(true); } } // If we got here, we didn't win. Return false. return(false); }
public TransformedItemContainer(TSource source, TDestination destination) { Source = source; Destination = destination; }
public SingleImmediate(IObservable <TSource> source, TSource value, bool append) : base(source, value, append) { }
public static IAsyncEnumerable <TSource> Merge <TSource>(params IAsyncEnumerable <TSource>[] sources) { if (sources == null) { throw Error.ArgumentNull(nameof(sources)); } #if USE_FAIR_AND_CHEAPER_MERGE // // This new implementation of Merge differs from the original one in a few ways: // // - It's cheaper because: // - no conversion from ValueTask<bool> to Task<bool> takes place using AsTask, // - we don't instantiate Task.WhenAny tasks for each iteration. // - It's fairer because: // - the MoveNextAsync tasks are awaited concurently, but completions are queued, // instead of awaiting a new WhenAny task where "left" sources have preferential // treatment over "right" sources. // return(AsyncEnumerable.Create(Core)); async IAsyncEnumerator <TSource> Core(CancellationToken cancellationToken) { var count = sources.Length; var enumerators = new IAsyncEnumerator <TSource> [count]; var moveNextTasks = new ValueTask <bool> [count]; try { for (var i = 0; i < count; i++) { IAsyncEnumerator <TSource> enumerator = sources[i].GetAsyncEnumerator(cancellationToken); enumerators[i] = enumerator; // REVIEW: This follows the lead of the original implementation where we kick off MoveNextAsync // operations immediately. An alternative would be to do this in a separate stage, thus // preventing concurrency across MoveNextAsync and GetAsyncEnumerator calls and avoiding // any MoveNextAsync calls before all enumerators are acquired (or an exception has // occurred doing so). moveNextTasks[i] = enumerator.MoveNextAsync(); } var whenAny = TaskExt.WhenAny(moveNextTasks); int active = count; while (active > 0) { int index = await whenAny; IAsyncEnumerator <TSource> enumerator = enumerators[index]; ValueTask <bool> moveNextTask = moveNextTasks[index]; if (!await moveNextTask.ConfigureAwait(false)) { // // Replace the task in our array by a completed task to make finally logic easier. Note that // the WhenAnyValueTask object has a reference to our array (i.e. no copy is made), so this // gets rid of any resources the original task may have held onto. However, we *don't* call // whenAny.Replace to set this value, because it'd attach an awaiter to the already completed // task, causing spurious wake-ups when awaiting whenAny. // moveNextTasks[index] = new ValueTask <bool>(); // REVIEW: The original implementation did not dispose eagerly, which could lead to resource // leaks when merged with other long-running sequences. enumerators[index] = null; // NB: Avoids attempt at double dispose in finally if disposing fails. await enumerator.DisposeAsync().ConfigureAwait(false); active--; } else { TSource item = enumerator.Current; // // Replace the task using whenAny.Replace, which will write it to the moveNextTasks array, and // will start awaiting the task. Note we don't have to write to moveNextTasks ourselves because // the whenAny object has a reference to it (i.e. no copy is made). // whenAny.Replace(index, enumerator.MoveNextAsync()); yield return(item); } } } finally { // REVIEW: The original implementation performs a concurrent dispose, which seems undesirable given the // additional uncontrollable source of concurrency and the sequential resource acquisition. In // this modern implementation, we release resources in opposite order as we acquired them, thus // guaranteeing determinism (and mimicking a series of nested `await using` statements). // REVIEW: If we decide to phase GetAsyncEnumerator and the initial MoveNextAsync calls at the start of // the operator implementation, we should make this symmetric and first await all in flight // MoveNextAsync operations, prior to disposing the enumerators. var errors = default(List <Exception>); for (var i = count - 1; i >= 0; i--) { ValueTask <bool> moveNextTask = moveNextTasks[i]; IAsyncEnumerator <TSource> enumerator = enumerators[i]; try { try { // // Await the task to ensure outstanding work is completed prior to performing a dispose // operation. Note that we don't have to do anything special for tasks belonging to // enumerators that have finished; we swapped in a placeholder completed task. // // REVIEW: This adds an additional continuation to all of the pending tasks (note that // whenAny also has registered one). The whenAny object will be collectible // after all of these complete. Alternatively, we could drain via whenAny, by // awaiting it until the active count drops to 0. This saves on attaching the // additional continuations, but we need to decide on order of dispose. Right // now, we dispose in opposite order of acquiring the enumerators, with the // exception of enumerators that were disposed eagerly upon early completion. // Should we care about the dispose order at all? _ = await moveNextTask.ConfigureAwait(false); } finally { if (enumerator != null) { await enumerator.DisposeAsync().ConfigureAwait(false); } } } catch (Exception ex) { if (errors == null) { errors = new List <Exception>(); } errors.Add(ex); } } // NB: If we had any errors during cleaning (and awaiting pending operations), we throw these exceptions // instead of the original exception that may have led to running the finally block. This is similar // to throwing from any finally block (except that we catch all exceptions to ensure cleanup of all // concurrent sequences being merged). if (errors != null) { throw new AggregateException(errors); } } } #else return(AsyncEnumerable.Create(Core)); async IAsyncEnumerator <TSource> Core(CancellationToken cancellationToken) { var count = sources.Length; var enumerators = new IAsyncEnumerator <TSource>?[count]; var moveNextTasks = new Task <bool> [count]; try { for (var i = 0; i < count; i++) { var enumerator = sources[i].GetAsyncEnumerator(cancellationToken); enumerators[i] = enumerator; // REVIEW: This follows the lead of the original implementation where we kick off MoveNextAsync // operations immediately. An alternative would be to do this in a separate stage, thus // preventing concurrency across MoveNextAsync and GetAsyncEnumerator calls and avoiding // any MoveNextAsync calls before all enumerators are acquired (or an exception has // occurred doing so). moveNextTasks[i] = enumerator.MoveNextAsync().AsTask(); } var active = count; while (active > 0) { // REVIEW: Performance of WhenAny may be an issue when called repeatedly like this. We should // measure and could consider operating directly on the ValueTask<bool> objects, thus // also preventing the Task<bool> allocations from AsTask. var moveNextTask = await Task.WhenAny(moveNextTasks).ConfigureAwait(false); // REVIEW: This seems wrong. AsTask can return the original Task<bool> (if the ValueTask<bool> // is wrapping one) or return a singleton instance for true and false, at which point // the use of IndexOf may pick an element closer to the start of the array because of // reference equality checks and aliasing effects. See GetTaskForResult in the BCL. var index = Array.IndexOf(moveNextTasks, moveNextTask); var enumerator = enumerators[index] !; // NB: Only gets set to null after setting task to Never. if (!await moveNextTask.ConfigureAwait(false)) { moveNextTasks[index] = TaskExt.Never; // REVIEW: The original implementation did not dispose eagerly, which could lead to resource // leaks when merged with other long-running sequences. enumerators[index] = null; // NB: Avoids attempt at double dispose in finally if disposing fails. await enumerator.DisposeAsync().ConfigureAwait(false); active--; } else { var item = enumerator.Current; moveNextTasks[index] = enumerator.MoveNextAsync().AsTask(); yield return(item); } } } finally { // REVIEW: The original implementation performs a concurrent dispose, which seems undesirable given the // additional uncontrollable source of concurrency and the sequential resource acquisition. In // this modern implementation, we release resources in opposite order as we acquired them, thus // guaranteeing determinism (and mimicking a series of nested `await using` statements). // REVIEW: If we decide to phase GetAsyncEnumerator and the initial MoveNextAsync calls at the start of // the operator implementation, we should make this symmetric and first await all in flight // MoveNextAsync operations, prior to disposing the enumerators. var errors = default(List <Exception>); for (var i = count - 1; i >= 0; i--) { var moveNextTask = moveNextTasks[i]; var enumerator = enumerators[i]; try { try { if (moveNextTask != null && moveNextTask != TaskExt.Never) { _ = await moveNextTask.ConfigureAwait(false); } } finally { if (enumerator != null) { await enumerator.DisposeAsync().ConfigureAwait(false); } } } catch (Exception ex) { if (errors == null) { errors = new List <Exception>(); } errors.Add(ex); } } // NB: If we had any errors during cleaning (and awaiting pending operations), we throw these exceptions // instead of the original exception that may have led to running the finally block. This is similar // to throwing from any finally block (except that we catch all exceptions to ensure cleanup of all // concurrent sequences being merged). if (errors != null) { throw new AggregateException(errors); } } } #endif }
public ThrottleObserver(_ parent, TSource value, ulong currentid) { _parent = parent; _value = value; _currentid = currentid; }
public Delta(_ parent, TSource value, IDisposable self) { _parent = parent; _value = value; _self = self; }
internal DefaultIfEmptyQueryOperatorEnumerator(QueryOperatorEnumerator <TSource, TKey> source, TSource defaultValue, int partitionIndex, int partitionCount, Shared <int> sharedEmptyCount, CountdownEvent sharedLatch, CancellationToken cancelToken) { this.m_source = source; this.m_defaultValue = defaultValue; this.m_partitionIndex = partitionIndex; this.m_partitionCount = partitionCount; this.m_sharedEmptyCount = sharedEmptyCount; this.m_sharedLatch = sharedLatch; this.m_cancelToken = cancelToken; }
public void Update(TSource v, long i, bool t) { Value = v; Index = i; IsValid = t; }
private void RestartState() { _stage._close(_blockingStream); _blockingStream = _stage._create(); _open = true; }
public override void PreStart() { _blockingStream = _stage._create(); _open = true; }
public void OnNext(TSource value) { var key = default(TKey); try { key = _keySelector(value); } catch (Exception exception) { Error(exception); return; } var fireNewMapEntry = false; var writer = default(ISubject <TElement>); try { // // Note: The box instruction in the IL will be erased by the JIT in case T is // a value type. In fact, the whole if block will go away and we'll end // up with nothing but the GetOrAdd call below. // // See GroupBy for more information and confirmation of this fact using // the SOS debugger extension. // if (key == null) { lock (_nullGate) { if (_null == null) { _null = NewSubject(); fireNewMapEntry = true; } writer = _null; } } else { writer = _map.GetOrAdd(key, NewSubject, out fireNewMapEntry); } } catch (Exception exception) { Error(exception); return; } if (fireNewMapEntry) { var group = new GroupedObservable <TKey, TElement>(key, writer, _refCountDisposable); var duration = default(IObservable <TDuration>); var durationGroup = new GroupedObservable <TKey, TElement>(key, writer); try { duration = _durationSelector(durationGroup); } catch (Exception exception) { Error(exception); return; } lock (base._observer) base._observer.OnNext(group); var md = new SingleAssignmentDisposable(); _groupDisposable.Add(md); md.Disposable = duration.SubscribeSafe(new DurationObserver(this, key, writer, md)); } var element = default(TElement); try { element = _elementSelector(value); } catch (Exception exception) { Error(exception); return; } // // ISSUE: Rx v1.x shipped without proper handling of the case where the duration // sequence fires concurrently with the OnNext code path here. In such a // case, the subject can be completed before we get a chance to send out // a new element. However, a resurrected group for the same key won't get // to see the element either. To guard against this case, we'd have to // check whether the OnNext call below lost the race, and resurrect a new // group if needed. Unfortunately, this complicates matters when the // duration selector triggers synchronously (e.g. Return or Empty), which // causes the group to terminate immediately. We should not get stuck in // this case, repeatedly trying to resurrect a group that always ends // before we can send the element into it. Also, users may expect this // base case to mean no elements will ever be produced, so sending the // element into the group before starting the duration sequence may not // be a good idea either. For the time being, we'll leave this as-is and // revisit the behavior for vNext. Nonetheless, we'll add synchronization // to ensure no concurrent calls to the subject are made. // writer.OnNext(element); }
protected override TTarget SafeOnNext(TSource value) => this.mapping(value);
public SubSourcePair(INotifyValue <IEnumerable <TIntermediate> > subSource, TSource item, ObservableSelectMany <TSource, TIntermediate, TResult> parent) { SubSource = subSource; Item = item; Parent = parent; }
public ValueTask <TResult> InvokeAsync(TSource item, CancellationToken cancellationToken) => selector.InvokeAsync(item, 0, cancellationToken);
//--------------------------------------------------------------------------------------- // Straightforward IEnumerator<T> methods. // internal override bool MoveNext([MaybeNullWhen(false), AllowNull] ref TSource currentElement, ref int currentKey) { Debug.Assert(_source != null); if (_alreadySearched) { return(false); } // Look for the lowest element. TSource candidate = default(TSource) !; TKey candidateKey = default(TKey) !; try { TSource value = default(TSource) !; TKey key = default(TKey) !; int i = 0; while (_source.MoveNext(ref value !, ref key)) { if ((i++ & CancellationState.POLL_INTERVAL) == 0) { _cancellationToken.ThrowIfCancellationRequested(); } // If the predicate is null or the current element satisfies it, we have found the // current partition's "candidate" for the first element. Note it. if (_predicate == null || _predicate(value)) { candidate = value; candidateKey = key; lock (_operatorState) { if (_operatorState._partitionId == -1 || _keyComparer.Compare(candidateKey, _operatorState._key) < 0) { _operatorState._key = candidateKey; _operatorState._partitionId = _partitionId; } } break; } } } finally { if (!ParallelEnumerable.SinglePartitionMode) { // No matter whether we exit due to an exception or normal completion, we must ensure // that we signal other partitions that we have completed. Otherwise, we can cause deadlocks. _sharedBarrier.Signal(); } } _alreadySearched = true; // Wait only if we may have the result if (_partitionId == _operatorState._partitionId) { if (!ParallelEnumerable.SinglePartitionMode) { _sharedBarrier.Wait(_cancellationToken); } // Now re-read the shared index. If it's the same as ours, we won and return true. if (_partitionId == _operatorState._partitionId) { currentElement = candidate; currentKey = 0; // 1st (and only) element, so we hardcode the output index to 0. return(true); } } // If we got here, we didn't win. Return false. return(false); }
protected override TSource SafeOnNext(TSource value) { this.action(value); return(value); }
public SingleBase(IObservable <TSource> source, TSource value, bool append) { _source = source; _value = value; _append = append; }
public SourceResultPair(TSource source, TResult result) { Source = source; Result = result; }
public SingleValue(IObservable <TSource> source, TSource value, IScheduler scheduler, bool append) : base(source, value, append) { Scheduler = scheduler; }
public TransformedItemContainer(TKey key, TSource source, TDestination destination) { Key = key; Source = source; Destination = destination; }
public SourceInfo(TSource source, Range <DateTimeOffset> range) { Source = source; Range = range; }
public abstract void OnNext(TSource value);
public ChunkItem(TSource value) { Value = value; }
public void OnNext(TSource value) { var key = default(TKey); try { key = _parent._keySelector(value); } catch (Exception exception) { Error(exception); return; } var fireNewMapEntry = false; var writer = default(ISubject <TElement>); try { // // Note: The box instruction in the IL will be erased by the JIT in case T is // a value type. In fact, the whole if block will go away and we'll end // up with nothing but the TryGetValue check below. // // // var fireNewMapEntry = false; // C:\Projects\Rx\Rx\Experimental\Main\Source\Rx\System.Reactive.Linq\Reactive\Linq\Observable\GroupBy.cs @ 67: // 000007fb`6d544b80 48c7452800000000 mov qword ptr [rbp+28h],0 // // // var writer = default(ISubject<TElement>); // C:\Projects\Rx\Rx\Experimental\Main\Source\Rx\System.Reactive.Linq\Reactive\Linq\Observable\GroupBy.cs @ 66: // 000007fb`6d544b88 c6453400 mov byte ptr [rbp+34h],0 // // // if (!_map.TryGetValue(key, out writer)) // C:\Projects\Rx\Rx\Experimental\Main\Source\Rx\System.Reactive.Linq\Reactive\Linq\Observable\GroupBy.cs @ 86: // 000007fb`6d544b8c 488b4560 mov rax,qword ptr [rbp+60h] // ... // if (key == null) { if (_null == null) { _null = new Subject <TElement>(); fireNewMapEntry = true; } writer = _null; } else { if (!_map.TryGetValue(key, out writer)) { writer = new Subject <TElement>(); _map.Add(key, writer); fireNewMapEntry = true; } } } catch (Exception exception) { Error(exception); return; } if (fireNewMapEntry) { var group = new GroupedObservable <TKey, TElement>(key, writer, _parent._refCountDisposable); _observer.OnNext(group); } var element = default(TElement); try { element = _parent._elementSelector(value); } catch (Exception exception) { Error(exception); return; } writer.OnNext(element); }
public ManySelectorFunc(TSource source, Func <TSource, IEnumerable <TDestination> > selector) { _source = source; _selector = selector ?? throw new ArgumentNullException(nameof(selector)); }
public override void OnNext(TSource value) { var key = default(TKey); try { key = parent.keySelector(value); } catch (Exception exception) { Error(exception); return; } var fireNewMapEntry = false; var writer = default(ISubject <TElement>); try { if (key == null) { if (nullKeySubject == null) { nullKeySubject = new Subject <TElement>(); fireNewMapEntry = true; } writer = nullKeySubject; } else { if (!map.TryGetValue(key, out writer)) { writer = new Subject <TElement>(); map.Add(key, writer); fireNewMapEntry = true; } } } catch (Exception exception) { Error(exception); return; } if (fireNewMapEntry) { var group = new GroupedObservable <TKey, TElement>(key, writer, refCountDisposable); observer.OnNext(group); } var element = default(TElement); try { element = parent.elementSelector(value); } catch (Exception exception) { Error(exception); return; } writer.OnNext(element); }
public void OnItem(TSource item) { Downstream.OnItem(Func(item)); }
private void AddChildrenRecursively(KeyedTreeNode <TKey, IElementsProvider <TSource, TData> > pattern, TSource element) { foreach (var child in pattern.Children) { AddValuesRecursively(child, element); } }