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 ;
28
29
import rx .plugins .RxJavaHooks ;
30
+ import rx .observers .Subscribers ;
29
31
import rx .subscriptions .Subscriptions ;
30
32
31
33
/**
@@ -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
@@ -117,13 +135,14 @@ public static final class GroupBySubscriber<T, K, V>
117
135
118
136
final AtomicInteger wip ;
119
137
120
- public GroupBySubscriber (Subscriber <? super GroupedObservable <K , V >> actual , Func1 <? super T , ? extends K > keySelector , Func1 <? super T , ? extends V > valueSelector , int bufferSize , boolean delayError ) {
138
+ public GroupBySubscriber (Subscriber <? super GroupedObservable <K , V >> actual , Func1 <? super T , ? extends K > keySelector ,
139
+ Func1 <? super T , ? extends V > valueSelector , int bufferSize , boolean delayError ,
140
+ Func1 <Action1 <K >, Map <K , Object >> mapFactory ) {
121
141
this .actual = actual ;
122
142
this .keySelector = keySelector ;
123
143
this .valueSelector = valueSelector ;
124
144
this .bufferSize = bufferSize ;
125
145
this .delayError = delayError ;
126
- this .groups = new ConcurrentHashMap <Object , GroupedUnicast <K , V >>();
127
146
this .queue = new ConcurrentLinkedQueue <GroupedObservable <K , V >>();
128
147
this .s = new ProducerArbiter ();
129
148
this .s .request (bufferSize );
@@ -132,6 +151,32 @@ public GroupBySubscriber(Subscriber<? super GroupedObservable<K, V>> actual, Fun
132
151
this .requested = new AtomicLong ();
133
152
this .groupCount = new AtomicInteger (1 );
134
153
this .wip = new AtomicInteger ();
154
+ if (mapFactory == null ) {
155
+ this .groups = new ConcurrentHashMap <Object , GroupedUnicast <K , V >>();
156
+ this .evictedKeys = null ;
157
+ } else {
158
+ this .evictedKeys = new ConcurrentLinkedQueue <K >();
159
+ this .groups = createMap (mapFactory , new EvictionAction <K >(evictedKeys ));
160
+ }
161
+ }
162
+
163
+ static class EvictionAction <K > implements Action1 <K > {
164
+
165
+ final Queue <K > evictedKeys ;
166
+
167
+ EvictionAction (Queue <K > evictedKeys ) {
168
+ this .evictedKeys = evictedKeys ;
169
+ }
170
+
171
+ @ Override
172
+ public void call (K key ) {
173
+ evictedKeys .offer (key );
174
+ }
175
+ }
176
+
177
+ @ SuppressWarnings ("unchecked" )
178
+ private Map <Object , GroupedUnicast <K , V >> createMap (Func1 <Action1 <K >, Map <K , Object >> mapFactory , Action1 <K > evictionAction ) {
179
+ return (Map <Object , GroupedUnicast <K ,V >>)(Map <Object , ?>) mapFactory .call (evictionAction );
135
180
}
136
181
137
182
@ Override
@@ -187,6 +232,16 @@ public void onNext(T t) {
187
232
}
188
233
189
234
group .onNext (v );
235
+
236
+ if (evictedKeys != null ) {
237
+ K evictedKey ;
238
+ while ((evictedKey = evictedKeys .poll ()) != null ) {
239
+ GroupedUnicast <K , V > g = groups .get (evictedKey );
240
+ if (g != null ) {
241
+ g .onComplete ();
242
+ }
243
+ }
244
+ }
190
245
191
246
if (notNew ) {
192
247
s .request (1 );
@@ -215,6 +270,9 @@ public void onCompleted() {
215
270
e .onComplete ();
216
271
}
217
272
groups .clear ();
273
+ if (evictedKeys != null ) {
274
+ evictedKeys .clear ();
275
+ }
218
276
219
277
done = true ;
220
278
groupCount .decrementAndGet ();
@@ -306,6 +364,9 @@ void errorAll(Subscriber<? super GroupedObservable<K, V>> a, Queue<?> q, Throwab
306
364
q .clear ();
307
365
List <GroupedUnicast <K , V >> list = new ArrayList <GroupedUnicast <K , V >>(groups .values ());
308
366
groups .clear ();
367
+ if (evictedKeys != null ) {
368
+ evictedKeys .clear ();
369
+ }
309
370
310
371
for (GroupedUnicast <K , V > e : list ) {
311
372
e .onError (ex );
0 commit comments