13
13
14
14
package io .reactivex .internal .operators .observable ;
15
15
16
- import java .util .Arrays ;
17
16
import java .util .concurrent .atomic .*;
18
17
19
18
import io .reactivex .*;
@@ -79,8 +78,8 @@ static final class LatestCoordinator<T, R> extends AtomicInteger implements Disp
79
78
final Observer <? super R > actual ;
80
79
final Function <? super Object [], ? extends R > combiner ;
81
80
final CombinerObserver <T , R >[] observers ;
82
- final T [] latest ;
83
- final SpscLinkedArrayQueue <Object > queue ;
81
+ Object [] latest ;
82
+ final SpscLinkedArrayQueue <Object [] > queue ;
84
83
final boolean delayError ;
85
84
86
85
volatile boolean cancelled ;
@@ -99,18 +98,18 @@ static final class LatestCoordinator<T, R> extends AtomicInteger implements Disp
99
98
this .actual = actual ;
100
99
this .combiner = combiner ;
101
100
this .delayError = delayError ;
102
- this .latest = (T [])new Object [count ];
103
- this .observers = new CombinerObserver [count ];
104
- this .queue = new SpscLinkedArrayQueue <Object >(bufferSize );
101
+ this .latest = new Object [count ];
102
+ CombinerObserver <T , R >[] as = new CombinerObserver [count ];
103
+ for (int i = 0 ; i < count ; i ++) {
104
+ as [i ] = new CombinerObserver <T , R >(this , i );
105
+ }
106
+ this .observers = as ;
107
+ this .queue = new SpscLinkedArrayQueue <Object []>(bufferSize );
105
108
}
106
109
107
110
public void subscribe (ObservableSource <? extends T >[] sources ) {
108
111
Observer <T >[] as = observers ;
109
112
int len = as .length ;
110
- for (int i = 0 ; i < len ; i ++) {
111
- as [i ] = new CombinerObserver <T , R >(this , i );
112
- }
113
- lazySet (0 ); // release array contents
114
113
actual .onSubscribe (this );
115
114
for (int i = 0 ; i < len ; i ++) {
116
115
if (done || cancelled ) {
@@ -136,11 +135,6 @@ public boolean isDisposed() {
136
135
return cancelled ;
137
136
}
138
137
139
- void cancel (SpscLinkedArrayQueue <?> q ) {
140
- clear (q );
141
- cancelSources ();
142
- }
143
-
144
138
void cancelSources () {
145
139
for (CombinerObserver <T , R > s : observers ) {
146
140
s .dispose ();
@@ -149,96 +143,65 @@ void cancelSources() {
149
143
150
144
void clear (SpscLinkedArrayQueue <?> q ) {
151
145
synchronized (this ) {
152
- Arrays . fill ( latest , null ) ;
146
+ latest = null ;
153
147
}
154
148
q .clear ();
155
149
}
156
150
157
- void combine (T value , int index ) {
158
- CombinerObserver <T , R > cs = observers [index ];
159
-
160
- int a ;
161
- int c ;
162
- int len ;
163
- boolean empty ;
164
- boolean f ;
165
- synchronized (this ) {
166
- if (cancelled ) {
167
- return ;
168
- }
169
- len = latest .length ;
170
- T o = latest [index ];
171
- a = active ;
172
- if (o == null ) {
173
- active = ++a ;
174
- }
175
- c = complete ;
176
- if (value == null ) {
177
- complete = ++c ;
178
- } else {
179
- latest [index ] = value ;
180
- }
181
- f = a == len ;
182
- // see if either all sources completed
183
- empty = c == len
184
- || (value == null && o == null ); // or this source completed without any value
185
- if (!empty ) {
186
- if (value != null && f ) {
187
- queue .offer (cs , latest .clone ());
188
- } else
189
- if (value == null && errors .get () != null ) {
190
- done = true ; // if this source completed without a value
191
- }
192
- } else {
193
- done = true ;
194
- }
195
- }
196
- if (!f && value != null ) {
197
- return ;
198
- }
199
- drain ();
200
- }
201
151
void drain () {
202
152
if (getAndIncrement () != 0 ) {
203
153
return ;
204
154
}
205
155
206
- final SpscLinkedArrayQueue <Object > q = queue ;
156
+ final SpscLinkedArrayQueue <Object [] > q = queue ;
207
157
final Observer <? super R > a = actual ;
208
158
final boolean delayError = this .delayError ;
209
159
210
160
int missed = 1 ;
211
161
for (;;) {
212
162
213
- if (checkTerminated (done , q .isEmpty (), a , q , delayError )) {
214
- return ;
215
- }
216
-
217
163
for (;;) {
164
+ if (cancelled ) {
165
+ clear (q );
166
+ return ;
167
+ }
168
+
169
+ if (!delayError && errors .get () != null ) {
170
+ cancelSources ();
171
+ clear (q );
172
+ a .onError (errors .terminate ());
173
+ return ;
174
+ }
218
175
219
176
boolean d = done ;
220
- @ SuppressWarnings ("unchecked" )
221
- CombinerObserver <T , R > cs = (CombinerObserver <T , R >)q .poll ();
222
- boolean empty = cs == null ;
177
+ Object [] s = q .poll ();
178
+ boolean empty = s == null ;
223
179
224
- if (checkTerminated (d , empty , a , q , delayError )) {
180
+ if (d && empty ) {
181
+ clear (q );
182
+ Throwable ex = errors .terminate ();
183
+ if (ex == null ) {
184
+ a .onComplete ();
185
+ } else {
186
+ a .onError (ex );
187
+ }
225
188
return ;
226
189
}
227
190
228
191
if (empty ) {
229
192
break ;
230
193
}
231
194
232
- @ SuppressWarnings ("unchecked" )
233
- T [] array = (T [])q .poll ();
234
-
235
195
R v ;
196
+
236
197
try {
237
- v = ObjectHelper .requireNonNull (combiner .apply (array ), "The combiner returned a null" );
198
+ v = ObjectHelper .requireNonNull (combiner .apply (s ), "The combiner returned a null value " );
238
199
} catch (Throwable ex ) {
239
200
Exceptions .throwIfFatal (ex );
240
- cancelled = true ;
241
- cancel (q );
201
+ errors .addThrowable (ex );
202
+ cancelSources ();
203
+ clear (q );
204
+ ex = errors .terminate ();
242
205
a .onError (ex );
243
206
return ;
244
207
}
@@ -253,53 +216,81 @@ void drain() {
253
216
}
254
217
}
255
218
256
-
257
- boolean checkTerminated (boolean d , boolean empty , Observer <?> a , SpscLinkedArrayQueue <?> q , boolean delayError ) {
258
- if (cancelled ) {
259
- cancel (q );
260
- return true ;
219
+ void innerNext (int index , T item ) {
220
+ boolean shouldDrain = false ;
221
+ synchronized (this ) {
222
+ Object [] latest = this .latest ;
223
+ if (latest == null ) {
224
+ return ;
225
+ }
226
+ Object o = latest [index ];
227
+ int a = active ;
228
+ if (o == null ) {
229
+ active = ++a ;
230
+ }
231
+ latest [index ] = item ;
232
+ if (a == latest .length ) {
233
+ queue .offer (latest .clone ());
234
+ shouldDrain = true ;
235
+ }
236
+ }
237
+ if (shouldDrain ) {
238
+ drain ();
261
239
}
262
- if (d ) {
240
+ }
241
+
242
+ void innerError (int index , Throwable ex ) {
243
+ if (errors .addThrowable (ex )) {
244
+ boolean cancelOthers = true ;
263
245
if (delayError ) {
264
- if (empty ) {
265
- cancel (q );
266
- Throwable e = errors .terminate ();
267
- if (e != null ) {
268
- a .onError (e );
269
- } else {
270
- a .onComplete ();
246
+ synchronized (this ) {
247
+ Object [] latest = this .latest ;
248
+ if (latest == null ) {
249
+ return ;
250
+ }
251
+
252
+ cancelOthers = latest [index ] == null ;
253
+ if (cancelOthers || ++complete == latest .length ) {
254
+ done = true ;
271
255
}
272
- return true ;
273
- }
274
- } else {
275
- Throwable e = errors .get ();
276
- if (e != null ) {
277
- cancel (q );
278
- a .onError (errors .terminate ());
279
- return true ;
280
- } else
281
- if (empty ) {
282
- clear (queue );
283
- a .onComplete ();
284
- return true ;
285
256
}
286
257
}
258
+ if (cancelOthers ) {
259
+ cancelSources ();
260
+ }
261
+ drain ();
262
+ } else {
263
+ RxJavaPlugins .onError (ex );
287
264
}
288
- return false ;
289
265
}
290
266
291
- void onError (Throwable e ) {
292
- if (!errors .addThrowable (e )) {
293
- RxJavaPlugins .onError (e );
267
+ void innerComplete (int index ) {
268
+ boolean cancelOthers = false ;
269
+ synchronized (this ) {
270
+ Object [] latest = this .latest ;
271
+ if (latest == null ) {
272
+ return ;
273
+ }
274
+
275
+ cancelOthers = latest [index ] == null ;
276
+ if (cancelOthers || ++complete == latest .length ) {
277
+ done = true ;
278
+ }
279
+ }
280
+ if (cancelOthers ) {
281
+ cancelSources ();
294
282
}
283
+ drain ();
295
284
}
285
+
296
286
}
297
287
298
- static final class CombinerObserver <T , R > implements Observer <T > {
288
+ static final class CombinerObserver <T , R > extends AtomicReference <Disposable > implements Observer <T > {
289
+ private static final long serialVersionUID = -4823716997131257941L ;
290
+
299
291
final LatestCoordinator <T , R > parent ;
300
- final int index ;
301
292
302
- final AtomicReference < Disposable > s = new AtomicReference < Disposable >() ;
293
+ final int index ;
303
294
304
295
CombinerObserver (LatestCoordinator <T , R > parent , int index ) {
305
296
this .parent = parent ;
@@ -308,27 +299,26 @@ static final class CombinerObserver<T, R> implements Observer<T> {
308
299
309
300
@ Override
310
301
public void onSubscribe (Disposable s ) {
311
- DisposableHelper .setOnce (this . s , s );
302
+ DisposableHelper .setOnce (this , s );
312
303
}
313
304
314
305
@ Override
315
306
public void onNext (T t ) {
316
- parent .combine ( t , index );
307
+ parent .innerNext ( index , t );
317
308
}
318
309
319
310
@ Override
320
311
public void onError (Throwable t ) {
321
- parent .onError (t );
322
- parent .combine (null , index );
312
+ parent .innerError (index , t );
323
313
}
324
314
325
315
@ Override
326
316
public void onComplete () {
327
- parent .combine ( null , index );
317
+ parent .innerComplete ( index );
328
318
}
329
319
330
320
public void dispose () {
331
- DisposableHelper .dispose (s );
321
+ DisposableHelper .dispose (this );
332
322
}
333
323
}
334
324
}
0 commit comments