1515 */
1616package rx .operators ;
1717
18- import static org .mockito .Matchers .*;
19- import static org .mockito .Mockito .*;
18+ import static org .mockito .Matchers .any ;
19+ import static org .mockito .Mockito .inOrder ;
20+ import static org .mockito .Mockito .mock ;
21+ import static org .mockito .Mockito .never ;
22+ import static org .mockito .Mockito .times ;
23+ import static org .mockito .Mockito .verify ;
2024
21- import java .util .Iterator ;
22- import java .util .concurrent .LinkedBlockingDeque ;
25+ import java .util .Deque ;
26+ import java .util .LinkedList ;
27+ import java .util .concurrent .locks .ReentrantLock ;
2328
2429import org .junit .Test ;
2530import org .mockito .InOrder ;
@@ -59,25 +64,36 @@ private static class TakeLast<T> implements OnSubscribeFunc<T> {
5964 }
6065
6166 public Subscription onSubscribe (Observer <? super T > observer ) {
67+ if (count < 0 ) {
68+ throw new IndexOutOfBoundsException (
69+ "count could not be negative" );
70+ }
6271 return subscription .wrap (items .subscribe (new ItemObserver (observer )));
6372 }
6473
6574 private class ItemObserver implements Observer <T > {
6675
67- private LinkedBlockingDeque <T > deque = new LinkedBlockingDeque <T >(count );
76+ /**
77+ * Store the last count elements until now.
78+ */
79+ private Deque <T > deque = new LinkedList <T >();
6880 private final Observer <? super T > observer ;
81+ private final ReentrantLock lock = new ReentrantLock ();
6982
7083 public ItemObserver (Observer <? super T > observer ) {
7184 this .observer = observer ;
7285 }
7386
7487 @ Override
7588 public void onCompleted () {
76- Iterator <T > reverse = deque .descendingIterator ();
77- while (reverse .hasNext ()) {
78- observer .onNext (reverse .next ());
89+ try {
90+ for (T value : deque ) {
91+ observer .onNext (value );
92+ }
93+ observer .onCompleted ();
94+ } catch (Throwable e ) {
95+ observer .onError (e );
7996 }
80- observer .onCompleted ();
8197 }
8298
8399 @ Override
@@ -86,9 +102,27 @@ public void onError(Throwable e) {
86102 }
87103
88104 @ Override
89- public void onNext (T args ) {
90- while (!deque .offerFirst (args )) {
91- deque .removeLast ();
105+ public void onNext (T value ) {
106+ if (count == 0 ) {
107+ // If count == 0, we do not need to put value into deque and
108+ // remove it at once. We can ignore the value directly.
109+ return ;
110+ }
111+ lock .lock ();
112+ try {
113+ deque .offerLast (value );
114+ if (deque .size () > count ) {
115+ // Now deque has count + 1 elements, so the first
116+ // element in the deque definitely does not belong
117+ // to the last count elements of the source
118+ // sequence. We can drop it now.
119+ deque .removeFirst ();
120+ }
121+ } catch (Throwable e ) {
122+ observer .onError (e );
123+ subscription .unsubscribe ();
124+ } finally {
125+ lock .unlock ();
92126 }
93127 }
94128
@@ -140,6 +174,48 @@ public void testTakeLast2() {
140174 verify (aObserver , times (1 )).onCompleted ();
141175 }
142176
177+ @ Test
178+ public void testTakeLastWithZeroCount () {
179+ Observable <String > w = Observable .from ("one" );
180+ Observable <String > take = Observable .create (takeLast (w , 0 ));
181+
182+ @ SuppressWarnings ("unchecked" )
183+ Observer <String > aObserver = mock (Observer .class );
184+ take .subscribe (aObserver );
185+ verify (aObserver , never ()).onNext ("one" );
186+ verify (aObserver , never ()).onError (any (Throwable .class ));
187+ verify (aObserver , times (1 )).onCompleted ();
188+ }
189+
190+ @ Test
191+ public void testTakeLastWithNull () {
192+ Observable <String > w = Observable .from ("one" , null , "three" );
193+ Observable <String > take = Observable .create (takeLast (w , 2 ));
194+
195+ @ SuppressWarnings ("unchecked" )
196+ Observer <String > aObserver = mock (Observer .class );
197+ take .subscribe (aObserver );
198+ verify (aObserver , never ()).onNext ("one" );
199+ verify (aObserver , times (1 )).onNext (null );
200+ verify (aObserver , times (1 )).onNext ("three" );
201+ verify (aObserver , never ()).onError (any (Throwable .class ));
202+ verify (aObserver , times (1 )).onCompleted ();
203+ }
204+
205+ @ Test
206+ public void testTakeLastWithNegativeCount () {
207+ Observable <String > w = Observable .from ("one" );
208+ Observable <String > take = Observable .create (takeLast (w , -1 ));
209+
210+ @ SuppressWarnings ("unchecked" )
211+ Observer <String > aObserver = mock (Observer .class );
212+ take .subscribe (aObserver );
213+ verify (aObserver , never ()).onNext ("one" );
214+ verify (aObserver , times (1 )).onError (
215+ any (IndexOutOfBoundsException .class ));
216+ verify (aObserver , never ()).onCompleted ();
217+ }
218+
143219 }
144220
145221}
0 commit comments