21
21
22
22
import rx .*;
23
23
import rx .Observable .*;
24
+ import rx .exceptions .Exceptions ;
24
25
import rx .functions .*;
25
26
import rx .internal .producers .ProducerArbiter ;
26
27
import rx .internal .util .*;
27
28
import rx .observables .GroupedObservable ;
29
+ import rx .observers .Subscribers ;
28
30
import rx .plugins .RxJavaPlugins ;
29
31
import rx .subscriptions .Subscriptions ;
30
32
@@ -46,35 +48,50 @@ public final class OperatorGroupBy<T, K, V> implements Operator<GroupedObservabl
46
48
final Func1 <? super T , ? extends V > valueSelector ;
47
49
final int bufferSize ;
48
50
final boolean delayError ;
51
+ final Func1 <Action1 <K >, Map <K , Object >> mapFactory ; //nullable
49
52
50
53
@ SuppressWarnings ({ "unchecked" , "rawtypes" })
51
54
public OperatorGroupBy (Func1 <? super T , ? extends K > keySelector ) {
52
- this (keySelector , (Func1 )UtilityFunctions .<T >identity (), RxRingBuffer .SIZE , false );
55
+ this (keySelector , (Func1 )UtilityFunctions .<T >identity (), RxRingBuffer .SIZE , false , null );
53
56
}
54
57
55
58
public OperatorGroupBy (Func1 <? super T , ? extends K > keySelector , Func1 <? super T , ? extends V > valueSelector ) {
56
- this (keySelector , valueSelector , RxRingBuffer .SIZE , false );
59
+ this (keySelector , valueSelector , RxRingBuffer .SIZE , false , null );
60
+ }
61
+
62
+ public OperatorGroupBy (Func1 <? super T , ? extends K > keySelector , Func1 <? super T , ? extends V > valueSelector , Func1 <Action1 <K >, Map <K , Object >> mapFactory ) {
63
+ this (keySelector , valueSelector , RxRingBuffer .SIZE , false , mapFactory );
57
64
}
58
65
59
- public OperatorGroupBy (Func1 <? super T , ? extends K > keySelector , Func1 <? super T , ? extends V > valueSelector , int bufferSize , boolean delayError ) {
66
+ public OperatorGroupBy (Func1 <? super T , ? extends K > keySelector , Func1 <? super T , ? extends V > valueSelector , int bufferSize , boolean delayError , Func1 < Action1 < K >, Map < K , Object >> mapFactory ) {
60
67
this .keySelector = keySelector ;
61
68
this .valueSelector = valueSelector ;
62
69
this .bufferSize = bufferSize ;
63
70
this .delayError = delayError ;
71
+ this .mapFactory = mapFactory ;
64
72
}
65
73
66
74
@ Override
67
- public Subscriber <? super T > call (Subscriber <? super GroupedObservable <K , V >> t ) {
68
- final GroupBySubscriber <T , K , V > parent = new GroupBySubscriber <T , K , V >(t , keySelector , valueSelector , bufferSize , delayError );
75
+ public Subscriber <? super T > call (Subscriber <? super GroupedObservable <K , V >> child ) {
76
+ final GroupBySubscriber <T , K , V > parent ;
77
+ try {
78
+ parent = new GroupBySubscriber <T , K , V >(child , keySelector , valueSelector , bufferSize , delayError , mapFactory );
79
+ } catch (Throwable ex ) {
80
+ //Can reach here because mapFactory.call() may throw in constructor of GroupBySubscriber
81
+ Exceptions .throwOrReport (ex , child );
82
+ Subscriber <? super T > parent2 = Subscribers .empty ();
83
+ parent2 .unsubscribe ();
84
+ return parent2 ;
85
+ }
69
86
70
- t .add (Subscriptions .create (new Action0 () {
87
+ child .add (Subscriptions .create (new Action0 () {
71
88
@ Override
72
89
public void call () {
73
90
parent .cancel ();
74
91
}
75
92
}));
76
93
77
- t .setProducer (parent .producer );
94
+ child .setProducer (parent .producer );
78
95
79
96
return parent ;
80
97
}
@@ -101,6 +118,7 @@ public static final class GroupBySubscriber<T, K, V>
101
118
final Map <Object , GroupedUnicast <K , V >> groups ;
102
119
final Queue <GroupedObservable <K , V >> queue ;
103
120
final GroupByProducer producer ;
121
+ final Queue <K > evictedKeys ;
104
122
105
123
static final Object NULL_KEY = new Object ();
106
124
@@ -129,18 +147,47 @@ public static final class GroupBySubscriber<T, K, V>
129
147
static final AtomicIntegerFieldUpdater <GroupBySubscriber > WIP =
130
148
AtomicIntegerFieldUpdater .newUpdater (GroupBySubscriber .class , "wip" );
131
149
132
- public GroupBySubscriber (Subscriber <? super GroupedObservable <K , V >> actual , Func1 <? super T , ? extends K > keySelector , Func1 <? super T , ? extends V > valueSelector , int bufferSize , boolean delayError ) {
150
+ public GroupBySubscriber (Subscriber <? super GroupedObservable <K , V >> actual , Func1 <? super T , ? extends K > keySelector ,
151
+ Func1 <? super T , ? extends V > valueSelector , int bufferSize , boolean delayError ,
152
+ Func1 <Action1 <K >, Map <K , Object >> mapFactory ) {
133
153
this .actual = actual ;
134
154
this .keySelector = keySelector ;
135
155
this .valueSelector = valueSelector ;
136
156
this .bufferSize = bufferSize ;
137
157
this .delayError = delayError ;
138
- this .groups = new ConcurrentHashMap <Object , GroupedUnicast <K , V >>();
139
158
this .queue = new ConcurrentLinkedQueue <GroupedObservable <K , V >>();
140
159
GROUP_COUNT .lazySet (this , 1 );
141
160
this .s = new ProducerArbiter ();
142
161
this .s .request (bufferSize );
143
162
this .producer = new GroupByProducer (this );
163
+ if (mapFactory == null ) {
164
+ this .groups = new ConcurrentHashMap <Object , GroupedUnicast <K , V >>();
165
+ this .evictedKeys = null ;
166
+ } else {
167
+ this .evictedKeys = new ConcurrentLinkedQueue <K >();
168
+ this .groups = createMap (mapFactory , new EvictionAction <K >(evictedKeys ));
169
+ }
170
+ }
171
+
172
+ //declare a class instead of using anonymous class to
173
+ //limit enclosing scope. Is this of value?
174
+ static class EvictionAction <K > implements Action1 <K > {
175
+
176
+ final Queue <K > evictedKeys ;
177
+
178
+ EvictionAction (Queue <K > evictedKeys ) {
179
+ this .evictedKeys = evictedKeys ;
180
+ }
181
+
182
+ @ Override
183
+ public void call (K key ) {
184
+ evictedKeys .offer (key );
185
+ }
186
+ }
187
+
188
+ @ SuppressWarnings ("unchecked" )
189
+ private Map <Object , GroupedUnicast <K , V >> createMap (Func1 <Action1 <K >, Map <K , Object >> mapFactory , Action1 <K > evictionAction ) {
190
+ return (Map <Object , GroupedUnicast <K ,V >>)(Map <Object , ?>) mapFactory .call (evictionAction );
144
191
}
145
192
146
193
@ Override
@@ -196,6 +243,16 @@ public void onNext(T t) {
196
243
}
197
244
198
245
group .onNext (v );
246
+
247
+ if (evictedKeys != null ) {
248
+ K evictedKey ;
249
+ while ((evictedKey = evictedKeys .poll ()) != null ) {
250
+ GroupedUnicast <K , V > g = groups .get (evictedKey );
251
+ if (g != null ) {
252
+ g .onComplete ();
253
+ }
254
+ }
255
+ }
199
256
200
257
if (notNew ) {
201
258
s .request (1 );
@@ -224,6 +281,9 @@ public void onCompleted() {
224
281
e .onComplete ();
225
282
}
226
283
groups .clear ();
284
+ if (evictedKeys != null ) {
285
+ evictedKeys .clear ();
286
+ }
227
287
228
288
done = true ;
229
289
GROUP_COUNT .decrementAndGet (this );
@@ -317,6 +377,9 @@ void errorAll(Subscriber<? super GroupedObservable<K, V>> a, Queue<?> q, Throwab
317
377
q .clear ();
318
378
List <GroupedUnicast <K , V >> list = new ArrayList <GroupedUnicast <K , V >>(groups .values ());
319
379
groups .clear ();
380
+ if (evictedKeys != null ) {
381
+ evictedKeys .clear ();
382
+ }
320
383
321
384
for (GroupedUnicast <K , V > e : list ) {
322
385
e .onError (ex );
0 commit comments