Skip to content

Commit 0fc6e2c

Browse files
committed
Reimplement the "SkipLast" operator with time
1 parent 632ca76 commit 0fc6e2c

File tree

5 files changed

+235
-176
lines changed

5 files changed

+235
-176
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
import rx.operators.OperatorSerialize;
118118
import rx.operators.OperatorSkip;
119119
import rx.operators.OperatorSkipLast;
120+
import rx.operators.OperatorSkipLastTimed;
120121
import rx.operators.OperatorSkipWhile;
121122
import rx.operators.OperatorSubscribeOn;
122123
import rx.operators.OperatorSynchronize;
@@ -6083,7 +6084,7 @@ public final Observable<T> skipLast(long time, TimeUnit unit) {
60836084
* @see <a href="http://msdn.microsoft.com/en-us/library/hh211750.aspx">MSDN: Observable.SkipLast</a>
60846085
*/
60856086
public final Observable<T> skipLast(long time, TimeUnit unit, Scheduler scheduler) {
6086-
return create(new OperatorSkipLast.SkipLastTimed<T>(this, time, unit, scheduler));
6087+
return lift(new OperatorSkipLastTimed<T>(time, unit, scheduler));
60876088
}
60886089

60896090
/**

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

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,11 @@
1515
*/
1616
package rx.operators;
1717

18-
import java.util.ArrayList;
19-
import java.util.Collections;
2018
import java.util.Deque;
2119
import java.util.LinkedList;
22-
import java.util.List;
23-
import java.util.concurrent.TimeUnit;
2420

25-
import rx.Observable;
26-
import rx.Observable.OnSubscribeFunc;
2721
import rx.Observable.Operator;
28-
import rx.Observer;
29-
import rx.Scheduler;
3022
import rx.Subscriber;
31-
import rx.Subscription;
32-
import rx.schedulers.Timestamped;
3323

3424
/**
3525
* Bypasses a specified number of elements at the end of an observable sequence.
@@ -85,75 +75,4 @@ public void onNext(T value) {
8575
};
8676
}
8777

88-
/**
89-
* Skip delivering values in the time window before the values.
90-
*
91-
* @param <T>
92-
* the result value type
93-
*/
94-
public static final class SkipLastTimed<T> implements OnSubscribeFunc<T> {
95-
final Observable<? extends T> source;
96-
final long timeInMillis;
97-
final Scheduler scheduler;
98-
99-
public SkipLastTimed(Observable<? extends T> source, long time, TimeUnit unit, Scheduler scheduler) {
100-
this.source = source;
101-
this.timeInMillis = unit.toMillis(time);
102-
this.scheduler = scheduler;
103-
}
104-
105-
@Override
106-
public Subscription onSubscribe(Observer<? super T> t1) {
107-
return source.unsafeSubscribe(new SourceObserver<T>(t1, timeInMillis, scheduler));
108-
}
109-
110-
/** Observes the source. */
111-
private static final class SourceObserver<T> extends Subscriber<T> {
112-
final Observer<? super T> observer;
113-
final long timeInMillis;
114-
final Scheduler scheduler;
115-
List<Timestamped<T>> buffer = new ArrayList<Timestamped<T>>();
116-
117-
public SourceObserver(Observer<? super T> observer,
118-
long timeInMillis, Scheduler scheduler) {
119-
this.observer = observer;
120-
this.timeInMillis = timeInMillis;
121-
this.scheduler = scheduler;
122-
}
123-
124-
@Override
125-
public void onNext(T args) {
126-
buffer.add(new Timestamped<T>(scheduler.now(), args));
127-
}
128-
129-
@Override
130-
public void onError(Throwable e) {
131-
buffer = Collections.emptyList();
132-
observer.onError(e);
133-
}
134-
135-
@Override
136-
public void onCompleted() {
137-
long limit = scheduler.now() - timeInMillis;
138-
try {
139-
for (Timestamped<T> v : buffer) {
140-
if (v.getTimestampMillis() < limit) {
141-
try {
142-
observer.onNext(v.getValue());
143-
} catch (Throwable t) {
144-
observer.onError(t);
145-
return;
146-
}
147-
} else {
148-
observer.onCompleted();
149-
break;
150-
}
151-
}
152-
} finally {
153-
buffer = Collections.emptyList();
154-
}
155-
}
156-
157-
}
158-
}
15978
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package rx.operators;
17+
18+
import rx.Observable.Operator;
19+
import rx.Scheduler;
20+
import rx.Subscriber;
21+
import rx.schedulers.Timestamped;
22+
23+
import java.util.ArrayList;
24+
import java.util.Collections;
25+
import java.util.List;
26+
import java.util.concurrent.TimeUnit;
27+
28+
/**
29+
* Skip delivering values in the time window before the values.
30+
*/
31+
public class OperatorSkipLastTimed<T> implements Operator<T, T> {
32+
33+
private final long timeInMillis;
34+
private final Scheduler scheduler;
35+
36+
public OperatorSkipLastTimed(long time, TimeUnit unit, Scheduler scheduler) {
37+
this.timeInMillis = unit.toMillis(time);
38+
this.scheduler = scheduler;
39+
}
40+
41+
@Override
42+
public Subscriber<? super T> call(final Subscriber<? super T> subscriber) {
43+
return new Subscriber<T>(subscriber) {
44+
45+
private List<Timestamped<T>> buffer = new ArrayList<Timestamped<T>>();
46+
47+
@Override
48+
public void onNext(T value) {
49+
buffer.add(new Timestamped<T>(scheduler.now(), value));
50+
}
51+
52+
@Override
53+
public void onError(Throwable e) {
54+
buffer = Collections.emptyList();
55+
subscriber.onError(e);
56+
}
57+
58+
@Override
59+
public void onCompleted() {
60+
long limit = scheduler.now() - timeInMillis;
61+
try {
62+
for (Timestamped<T> v : buffer) {
63+
if (v.getTimestampMillis() < limit) {
64+
try {
65+
subscriber.onNext(v.getValue());
66+
} catch (Throwable t) {
67+
subscriber.onError(t);
68+
return;
69+
}
70+
} else {
71+
break;
72+
}
73+
}
74+
subscriber.onCompleted();
75+
} finally {
76+
buffer = Collections.emptyList();
77+
}
78+
}
79+
80+
};
81+
}
82+
}

rxjava-core/src/test/java/rx/operators/OperatorSkipLastTest.java

Lines changed: 0 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,12 @@
2323
import static org.mockito.Mockito.verify;
2424

2525
import java.util.Arrays;
26-
import java.util.concurrent.TimeUnit;
2726

2827
import org.junit.Test;
2928
import org.mockito.InOrder;
3029

3130
import rx.Observable;
3231
import rx.Observer;
33-
import rx.operators.OperationSkipTest.CustomException;
34-
import rx.schedulers.TestScheduler;
35-
import rx.subjects.PublishSubject;
3632

3733
public class OperatorSkipLastTest {
3834

@@ -108,94 +104,4 @@ public void testSkipLastWithNegativeCount() {
108104
Observable.from("one").skipLast(-1);
109105
}
110106

111-
@Test
112-
public void testSkipLastTimed() {
113-
TestScheduler scheduler = new TestScheduler();
114-
115-
PublishSubject<Integer> source = PublishSubject.create();
116-
117-
Observable<Integer> result = source.skipLast(1, TimeUnit.SECONDS, scheduler);
118-
119-
Observer<Object> o = mock(Observer.class);
120-
121-
result.subscribe(o);
122-
123-
source.onNext(1);
124-
source.onNext(2);
125-
source.onNext(3);
126-
127-
scheduler.advanceTimeBy(500, TimeUnit.MILLISECONDS);
128-
129-
source.onNext(4);
130-
source.onNext(5);
131-
source.onNext(6);
132-
133-
scheduler.advanceTimeBy(950, TimeUnit.MILLISECONDS);
134-
source.onCompleted();
135-
136-
InOrder inOrder = inOrder(o);
137-
inOrder.verify(o).onNext(1);
138-
inOrder.verify(o).onNext(2);
139-
inOrder.verify(o).onNext(3);
140-
inOrder.verify(o, never()).onNext(4);
141-
inOrder.verify(o, never()).onNext(5);
142-
inOrder.verify(o, never()).onNext(6);
143-
inOrder.verify(o).onCompleted();
144-
inOrder.verifyNoMoreInteractions();
145-
146-
verify(o, never()).onError(any(Throwable.class));
147-
}
148-
149-
@Test
150-
public void testSkipLastTimedErrorBeforeTime() {
151-
TestScheduler scheduler = new TestScheduler();
152-
153-
PublishSubject<Integer> source = PublishSubject.create();
154-
155-
Observable<Integer> result = source.skipLast(1, TimeUnit.SECONDS, scheduler);
156-
157-
Observer<Object> o = mock(Observer.class);
158-
159-
result.subscribe(o);
160-
161-
source.onNext(1);
162-
source.onNext(2);
163-
source.onNext(3);
164-
source.onError(new OperationSkipTest.CustomException());
165-
166-
scheduler.advanceTimeBy(1050, TimeUnit.MILLISECONDS);
167-
168-
verify(o).onError(any(CustomException.class));
169-
170-
verify(o, never()).onCompleted();
171-
verify(o, never()).onNext(any());
172-
}
173-
174-
@Test
175-
public void testSkipLastTimedCompleteBeforeTime() {
176-
TestScheduler scheduler = new TestScheduler();
177-
178-
PublishSubject<Integer> source = PublishSubject.create();
179-
180-
Observable<Integer> result = source.skipLast(1, TimeUnit.SECONDS, scheduler);
181-
182-
Observer<Object> o = mock(Observer.class);
183-
184-
result.subscribe(o);
185-
186-
source.onNext(1);
187-
source.onNext(2);
188-
source.onNext(3);
189-
190-
scheduler.advanceTimeBy(500, TimeUnit.MILLISECONDS);
191-
192-
source.onCompleted();
193-
194-
InOrder inOrder = inOrder(o);
195-
inOrder.verify(o).onCompleted();
196-
inOrder.verifyNoMoreInteractions();
197-
198-
verify(o, never()).onNext(any());
199-
verify(o, never()).onError(any(Throwable.class));
200-
}
201107
}

0 commit comments

Comments
 (0)