Skip to content

Commit b794705

Browse files
Merge pull request #1138 from akarnokd/OperatorWindow430
Operator Window and other changes
2 parents 1af3674 + b1effc7 commit b794705

10 files changed

+1256
-1305
lines changed

rxjava-core/src/main/java/rx/Observable.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7235,7 +7235,7 @@ public final Observable<T> unsubscribeOn(Scheduler scheduler) {
72357235
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
72367236
*/
72377237
public final <TClosing> Observable<Observable<T>> window(Func0<? extends Observable<? extends TClosing>> closingSelector) {
7238-
return create(OperationWindow.window(this, closingSelector));
7238+
return lift(new OperatorWindowWithObservable<T, TClosing>(closingSelector));
72397239
}
72407240

72417241
/**
@@ -7252,7 +7252,7 @@ public final <TClosing> Observable<Observable<T>> window(Func0<? extends Observa
72527252
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
72537253
*/
72547254
public final Observable<Observable<T>> window(int count) {
7255-
return create(OperationWindow.window(this, count));
7255+
return lift(new OperatorWindowWithSize<T>(count, count));
72567256
}
72577257

72587258
/**
@@ -7272,7 +7272,7 @@ public final Observable<Observable<T>> window(int count) {
72727272
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
72737273
*/
72747274
public final Observable<Observable<T>> window(int count, int skip) {
7275-
return create(OperationWindow.window(this, count, skip));
7275+
return lift(new OperatorWindowWithSize<T>(count, skip));
72767276
}
72777277

72787278
/**
@@ -7294,7 +7294,7 @@ public final Observable<Observable<T>> window(int count, int skip) {
72947294
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
72957295
*/
72967296
public final Observable<Observable<T>> window(long timespan, long timeshift, TimeUnit unit) {
7297-
return create(OperationWindow.window(this, timespan, timeshift, unit));
7297+
return lift(new OperatorWindowWithTime<T>(timespan, timeshift, unit, Integer.MAX_VALUE, Schedulers.computation()));
72987298
}
72997299

73007300
/**
@@ -7318,7 +7318,7 @@ public final Observable<Observable<T>> window(long timespan, long timeshift, Tim
73187318
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
73197319
*/
73207320
public final Observable<Observable<T>> window(long timespan, long timeshift, TimeUnit unit, Scheduler scheduler) {
7321-
return create(OperationWindow.window(this, timespan, timeshift, unit, scheduler));
7321+
return lift(new OperatorWindowWithTime<T>(timespan, timeshift, unit, Integer.MAX_VALUE, scheduler));
73227322
}
73237323

73247324
/**
@@ -7339,7 +7339,7 @@ public final Observable<Observable<T>> window(long timespan, long timeshift, Tim
73397339
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
73407340
*/
73417341
public final Observable<Observable<T>> window(long timespan, TimeUnit unit) {
7342-
return create(OperationWindow.window(this, timespan, unit));
7342+
return lift(new OperatorWindowWithTime<T>(timespan, timespan, unit, Integer.MAX_VALUE, Schedulers.computation()));
73437343
}
73447344

73457345
/**
@@ -7364,7 +7364,7 @@ public final Observable<Observable<T>> window(long timespan, TimeUnit unit) {
73647364
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
73657365
*/
73667366
public final Observable<Observable<T>> window(long timespan, TimeUnit unit, int count) {
7367-
return create(OperationWindow.window(this, timespan, unit, count));
7367+
return lift(new OperatorWindowWithTime<T>(timespan, timespan, unit, count, Schedulers.computation()));
73687368
}
73697369

73707370
/**
@@ -7391,7 +7391,7 @@ public final Observable<Observable<T>> window(long timespan, TimeUnit unit, int
73917391
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
73927392
*/
73937393
public final Observable<Observable<T>> window(long timespan, TimeUnit unit, int count, Scheduler scheduler) {
7394-
return create(OperationWindow.window(this, timespan, unit, count, scheduler));
7394+
return lift(new OperatorWindowWithTime<T>(timespan, timespan, unit, count, scheduler));
73957395
}
73967396

73977397
/**
@@ -7414,7 +7414,7 @@ public final Observable<Observable<T>> window(long timespan, TimeUnit unit, int
74147414
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
74157415
*/
74167416
public final Observable<Observable<T>> window(long timespan, TimeUnit unit, Scheduler scheduler) {
7417-
return create(OperationWindow.window(this, timespan, unit, scheduler));
7417+
return lift(new OperatorWindowWithTime<T>(timespan, timespan, unit, Integer.MAX_VALUE, scheduler));
74187418
}
74197419

74207420
/**
@@ -7434,7 +7434,7 @@ public final Observable<Observable<T>> window(long timespan, TimeUnit unit, Sche
74347434
* @see <a href="https://github.com/Netflix/RxJava/wiki/Transforming-Observables#wiki-window">RxJava Wiki: window()</a>
74357435
*/
74367436
public final <TOpening, TClosing> Observable<Observable<T>> window(Observable<? extends TOpening> windowOpenings, Func1<? super TOpening, ? extends Observable<? extends TClosing>> closingSelector) {
7437-
return create(OperationWindow.window(this, windowOpenings, closingSelector));
7437+
return lift(new OperatorWindowWithStartEndObservable<T, TOpening, TClosing>(windowOpenings, closingSelector));
74387438
}
74397439

74407440
/**
@@ -7452,7 +7452,7 @@ public final <TOpening, TClosing> Observable<Observable<T>> window(Observable<?
74527452
* where the boundary of each window is determined by the items emitted from the {@code boundary} Observable
74537453
*/
74547454
public final <U> Observable<Observable<T>> window(Observable<U> boundary) {
7455-
return create(OperationWindow.window(this, boundary));
7455+
return lift(new OperatorWindowWithObservable<T, U>(boundary));
74567456
}
74577457

74587458
/**

rxjava-core/src/main/java/rx/operators/BufferUntilSubscriber.java

Lines changed: 57 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616
package rx.operators;
1717

1818
import java.util.concurrent.ConcurrentLinkedQueue;
19+
import java.util.concurrent.atomic.AtomicBoolean;
1920
import java.util.concurrent.atomic.AtomicReference;
2021

2122
import rx.Observable;
2223
import rx.Observer;
2324
import rx.Subscriber;
25+
import rx.functions.Action0;
26+
import rx.observers.Subscribers;
27+
import rx.subscriptions.Subscriptions;
2428

2529
/**
2630
* A solution to the "time gap" problem that occurs with `groupBy` and `pivot` => https://github.com/Netflix/RxJava/issues/844
@@ -43,44 +47,72 @@
4347
public class BufferUntilSubscriber<T> extends Observable<T> implements Observer<T> {
4448

4549
public static <T> BufferUntilSubscriber<T> create() {
46-
return new BufferUntilSubscriber<T>(new AtomicReference<Observer<? super T>>(new BufferedObserver<T>()));
50+
State<T> state = new State<T>();
51+
return new BufferUntilSubscriber<T>(state);
4752
}
4853

49-
private final AtomicReference<Observer<? super T>> observerRef;
54+
/** The common state. */
55+
static final class State<T> {
56+
/** Lite notifications of type T. */
57+
final NotificationLite<T> nl = NotificationLite.instance();
58+
/** The first observer or the one which buffers until the first arrives. */
59+
final AtomicReference<Observer<? super T>> observerRef = new AtomicReference<Observer<? super T>>(new BufferedObserver<T>());
60+
/** Allow a single subscriber only. */
61+
final AtomicBoolean first = new AtomicBoolean();
62+
}
63+
64+
static final class OnSubscribeAction<T> implements OnSubscribe<T> {
65+
final State<T> state;
5066

51-
private BufferUntilSubscriber(final AtomicReference<Observer<? super T>> observerRef) {
52-
super(new OnSubscribe<T>() {
67+
public OnSubscribeAction(State<T> state) {
68+
this.state = state;
69+
}
5370

54-
@Override
55-
public void call(Subscriber<? super T> s) {
71+
@Override
72+
public void call(final Subscriber<? super T> s) {
73+
if (state.first.compareAndSet(false, true)) {
5674
// drain queued notifications before subscription
5775
// we do this here before PassThruObserver so the consuming thread can do this before putting itself in the line of the producer
58-
BufferedObserver<T> buffered = (BufferedObserver<T>) observerRef.get();
59-
Object o = null;
76+
BufferedObserver<? super T> buffered = (BufferedObserver<? super T>)state.observerRef.get();
77+
Object o;
6078
while ((o = buffered.buffer.poll()) != null) {
61-
emit(s, o);
79+
state.nl.accept(s, o);
6280
}
6381
// register real observer for pass-thru ... and drain any further events received on first notification
64-
observerRef.set(new PassThruObserver<T>(s, buffered.buffer, observerRef));
82+
state.observerRef.set(new PassThruObserver<T>(s, buffered.buffer, state.observerRef));
83+
s.add(Subscriptions.create(new Action0() {
84+
@Override
85+
public void call() {
86+
state.observerRef.set(Subscribers.empty());
87+
}
88+
}));
89+
} else {
90+
s.onError(new IllegalStateException("Only one subscriber allowed!"));
6591
}
66-
67-
});
68-
this.observerRef = observerRef;
92+
}
93+
94+
}
95+
final State<T> state;
96+
97+
private BufferUntilSubscriber(State<T> state) {
98+
super(new OnSubscribeAction<T>(state));
99+
this.state = state;
69100
}
70101

71102
@Override
72103
public void onCompleted() {
73-
observerRef.get().onCompleted();
104+
state.observerRef.get().onCompleted();
74105
}
75106

76107
@Override
77108
public void onError(Throwable e) {
78-
observerRef.get().onError(e);
109+
state.observerRef.get().onError(e);
79110
}
80111

81112
@Override
113+
@SuppressWarnings({ "unchecked", "rawtypes" })
82114
public void onNext(T t) {
83-
observerRef.get().onNext(t);
115+
state.observerRef.get().onNext(t);
84116
}
85117

86118
/**
@@ -97,6 +129,7 @@ private static class PassThruObserver<T> extends Subscriber<T> {
97129
// this assumes single threaded synchronous notifications (the Rx contract for a single Observer)
98130
private final ConcurrentLinkedQueue<Object> buffer;
99131
private final AtomicReference<Observer<? super T>> observerRef;
132+
private final NotificationLite<T> nl = NotificationLite.instance();
100133

101134
PassThruObserver(Observer<? super T> actual, ConcurrentLinkedQueue<Object> buffer, AtomicReference<Observer<? super T>> observerRef) {
102135
this.actual = actual;
@@ -123,67 +156,35 @@ public void onNext(T t) {
123156
}
124157

125158
private void drainIfNeededAndSwitchToActual() {
126-
Object o = null;
159+
Object o;
127160
while ((o = buffer.poll()) != null) {
128-
emit(this, o);
161+
nl.accept(this, o);
129162
}
130163
// now we can safely change over to the actual and get rid of the pass-thru
131-
observerRef.set(actual);
164+
// but only if not unsubscribed
165+
observerRef.compareAndSet(this, actual);
132166
}
133167

134168
}
135169

136170
private static class BufferedObserver<T> extends Subscriber<T> {
137171
private final ConcurrentLinkedQueue<Object> buffer = new ConcurrentLinkedQueue<Object>();
172+
private final NotificationLite<T> nl = NotificationLite.instance();
138173

139174
@Override
140175
public void onCompleted() {
141-
buffer.add(COMPLETE_SENTINEL);
176+
buffer.add(nl.completed());
142177
}
143178

144179
@Override
145180
public void onError(Throwable e) {
146-
buffer.add(new ErrorSentinel(e));
181+
buffer.add(nl.error(e));
147182
}
148183

149184
@Override
150185
public void onNext(T t) {
151-
if (t == null) {
152-
buffer.add(NULL_SENTINEL);
153-
} else {
154-
buffer.add(t);
155-
}
156-
}
157-
158-
}
159-
160-
private final static <T> void emit(Observer<T> s, Object v) {
161-
if (v instanceof Sentinel) {
162-
if (v == NULL_SENTINEL) {
163-
s.onNext(null);
164-
} else if (v == COMPLETE_SENTINEL) {
165-
s.onCompleted();
166-
} else if (v instanceof ErrorSentinel) {
167-
s.onError(((ErrorSentinel) v).e);
168-
}
169-
} else {
170-
s.onNext((T) v);
186+
buffer.add(nl.next(t));
171187
}
172-
}
173-
174-
private static class Sentinel {
175188

176189
}
177-
178-
private static Sentinel NULL_SENTINEL = new Sentinel();
179-
private static Sentinel COMPLETE_SENTINEL = new Sentinel();
180-
181-
private static class ErrorSentinel extends Sentinel {
182-
final Throwable e;
183-
184-
ErrorSentinel(Throwable e) {
185-
this.e = e;
186-
}
187-
}
188-
189190
}

0 commit comments

Comments
 (0)