private void TryUnstackQueues(Side <TInLeft> lSide, Side <TInRight> rSide, LeftJoinParams <TInLeft, TInRight, TOut> leftJoinParams) { bool somethingChanged; do { somethingChanged = false; while (!rSide.IsEmpty && !lSide.IsEmpty && leftJoinParams.comparer.Compare(lSide.CurrentValue, rSide.CurrentValue) > 0) { rSide.Dequeue(); somethingChanged = true; } int comparison; while (!lSide.IsEmpty && !rSide.IsEmpty && (comparison = leftJoinParams.comparer.Compare(lSide.CurrentValue, rSide.CurrentValue)) <= 0) { TOut ret; try { ret = leftJoinParams.selector(lSide.Dequeue(), comparison == 0 ? rSide.CurrentValue : default(TInRight)); this.PushValue(ret); } catch (Exception ex) { PushException(ex); } somethingChanged = true; } if (rSide.IsEmpty && rSide.IsComplete) { while (!lSide.IsEmpty) { TOut ret; try { ret = leftJoinParams.selector(lSide.Dequeue(), default(TInRight)); this.PushValue(ret); } catch (Exception ex) { PushException(ex); } somethingChanged = true; } } } while (somethingChanged); if (lSide.IsComplete && (lSide.IsEmpty || rSide.IsComplete)) { this.Complete(); } }
private void TryUnstackQueues(Side <TInLeft> lSide, Side <TInRight> rSide, LeftJoinParams <TInLeft, TInRight, TOut> leftJoinParams) { bool somethingChanged; do { if (CancellationToken.IsCancellationRequested) { break; } somethingChanged = false; while (!rSide.IsEmpty && !lSide.IsEmpty && leftJoinParams.comparer.Compare(lSide.CurrentValue, rSide.CurrentValue) > 0) { if (CancellationToken.IsCancellationRequested) { break; } rSide.Dequeue(); somethingChanged = true; } int comparison; while (!lSide.IsEmpty && !rSide.IsEmpty && (comparison = leftJoinParams.comparer.Compare(lSide.CurrentValue, rSide.CurrentValue)) <= 0) { if (CancellationToken.IsCancellationRequested) { break; } this.TryPushValue(() => leftJoinParams.selector(lSide.Dequeue(), comparison == 0 ? rSide.CurrentValue : default(TInRight))); somethingChanged = true; } if (rSide.IsEmpty && rSide.IsComplete) { while (!lSide.IsEmpty) { if (CancellationToken.IsCancellationRequested) { break; } this.TryPushValue(() => leftJoinParams.selector(lSide.Dequeue(), default(TInRight))); somethingChanged = true; } } } while (somethingChanged); if (lSide.IsComplete && (lSide.IsEmpty || rSide.IsComplete)) { this.Complete(); } }
public LeftJoinSubject(IPushObservable <TInLeft> leftS, IPushObservable <TInRight> rightS, IComparer <TInLeft, TInRight> comparer, Func <TInLeft, TInRight, TOut> selector) { var leftSide = new Side <TInLeft>(); var rightSide = new Side <TInRight>(); object gate = new object(); Action TryUnstackQueues = () => { bool somethingChanged; do { somethingChanged = false; while (!rightSide.IsEmpty && !leftSide.IsEmpty && comparer.Compare(leftSide.CurrentValue, rightSide.CurrentValue) > 0) { rightSide.Dequeue(); somethingChanged = true; } int comparison; while (!leftSide.IsEmpty && !rightSide.IsEmpty && (comparison = comparer.Compare(leftSide.CurrentValue, rightSide.CurrentValue)) <= 0) { TOut ret; try { ret = selector(leftSide.Dequeue(), comparison == 0 ? rightSide.CurrentValue : default(TInRight)); this.PushValue(ret); } catch (Exception ex) { PushException(ex); } somethingChanged = true; } if (rightSide.IsEmpty && rightSide.IsComplete) { while (!leftSide.IsEmpty) { TOut ret; try { ret = selector(leftSide.Dequeue(), default(TInRight)); this.PushValue(ret); } catch (Exception ex) { PushException(ex); } somethingChanged = true; } } } while (somethingChanged); if (leftSide.IsComplete && (leftSide.IsEmpty || rightSide.IsComplete)) { this.Complete(); } }; _leftSubscription = leftS.Subscribe( (leftValue) => { lock (gate) { leftSide.Enqueue(leftValue); TryUnstackQueues(); } }, () => { lock (gate) { leftSide.IsComplete = true; TryUnstackQueues(); } } ); _rightSubscription = rightS.Subscribe( (rightValue) => { lock (gate) { rightSide.Enqueue(rightValue); TryUnstackQueues(); } }, () => { lock (gate) { rightSide.IsComplete = true; TryUnstackQueues(); } } ); }