15
15
*/
16
16
package rx .internal .operators ;
17
17
18
- import java .util .concurrent .atomic .AtomicLongFieldUpdater ;
18
+ import java .util .concurrent .atomic .AtomicLong ;
19
19
20
+ import rx .*;
20
21
import rx .Observable .OnSubscribe ;
21
- import rx .Producer ;
22
- import rx .Subscriber ;
23
22
24
23
/**
25
24
* Emit ints from start to end inclusive.
@@ -39,13 +38,13 @@ public void call(final Subscriber<? super Integer> o) {
39
38
o .setProducer (new RangeProducer (o , start , end ));
40
39
}
41
40
42
- private static final class RangeProducer implements Producer {
41
+ private static final class RangeProducer extends AtomicLong implements Producer {
42
+ /** */
43
+ private static final long serialVersionUID = 4114392207069098388L ;
44
+
43
45
private final Subscriber <? super Integer > o ;
44
- // accessed by REQUESTED_UPDATER
45
- private volatile long requested ;
46
- private static final AtomicLongFieldUpdater <RangeProducer > REQUESTED_UPDATER = AtomicLongFieldUpdater .newUpdater (RangeProducer .class , "requested" );
47
- private long index ;
48
46
private final int end ;
47
+ private long index ;
49
48
50
49
private RangeProducer (Subscriber <? super Integer > o , int start , int end ) {
51
50
this .o = o ;
@@ -55,54 +54,79 @@ private RangeProducer(Subscriber<? super Integer> o, int start, int end) {
55
54
56
55
@ Override
57
56
public void request (long n ) {
58
- if (requested == Long .MAX_VALUE ) {
57
+ if (get () == Long .MAX_VALUE ) {
59
58
// already started with fast-path
60
59
return ;
61
60
}
62
- if (n == Long .MAX_VALUE && REQUESTED_UPDATER . compareAndSet (this , 0 , Long .MAX_VALUE )) {
61
+ if (n == Long .MAX_VALUE && compareAndSet (0L , Long .MAX_VALUE )) {
63
62
// fast-path without backpressure
64
- for (long i = index ; i <= end ; i ++) {
63
+ fastpath ();
64
+ } else if (n > 0L ) {
65
+ long c = BackpressureUtils .getAndAddRequest (this , n );
66
+ if (c == 0L ) {
67
+ // backpressure is requested
68
+ slowpath (n );
69
+ }
70
+ }
71
+ }
72
+
73
+ /**
74
+ *
75
+ */
76
+ void slowpath (long r ) {
77
+ long idx = index ;
78
+ while (true ) {
79
+ /*
80
+ * This complicated logic is done to avoid touching the volatile `index` and `requested` values
81
+ * during the loop itself. If they are touched during the loop the performance is impacted significantly.
82
+ */
83
+ long fs = end - idx + 1 ;
84
+ long e = Math .min (fs , r );
85
+ final boolean complete = fs <= r ;
86
+
87
+ fs = e + idx ;
88
+ final Subscriber <? super Integer > o = this .o ;
89
+
90
+ for (long i = idx ; i != fs ; i ++) {
65
91
if (o .isUnsubscribed ()) {
66
92
return ;
67
93
}
68
94
o .onNext ((int ) i );
69
95
}
70
- if (!o .isUnsubscribed ()) {
96
+
97
+ if (complete ) {
98
+ if (o .isUnsubscribed ()) {
99
+ return ;
100
+ }
71
101
o .onCompleted ();
102
+ return ;
72
103
}
73
- } else if (n > 0 ) {
74
- // backpressure is requested
75
- long _c = BackpressureUtils .getAndAddRequest (REQUESTED_UPDATER ,this , n );
76
- if (_c == 0 ) {
77
- while (true ) {
78
- /*
79
- * This complicated logic is done to avoid touching the volatile `index` and `requested` values
80
- * during the loop itself. If they are touched during the loop the performance is impacted significantly.
81
- */
82
- long r = requested ;
83
- long idx = index ;
84
- long numLeft = end - idx + 1 ;
85
- long e = Math .min (numLeft , r );
86
- boolean completeOnFinish = numLeft <= r ;
87
- long stopAt = e + idx ;
88
- for (long i = idx ; i < stopAt ; i ++) {
89
- if (o .isUnsubscribed ()) {
90
- return ;
91
- }
92
- o .onNext ((int ) i );
93
- }
94
- index = stopAt ;
95
-
96
- if (completeOnFinish ) {
97
- o .onCompleted ();
98
- return ;
99
- }
100
- if (REQUESTED_UPDATER .addAndGet (this , -e ) == 0 ) {
101
- // we're done emitting the number requested so return
102
- return ;
103
- }
104
- }
104
+
105
+ idx = fs ;
106
+ index = fs ;
107
+
108
+ r = addAndGet (-e );
109
+ if (r == 0L ) {
110
+ // we're done emitting the number requested so return
111
+ return ;
112
+ }
113
+ }
114
+ }
115
+
116
+ /**
117
+ *
118
+ */
119
+ void fastpath () {
120
+ final long end = this .end + 1L ;
121
+ final Subscriber <? super Integer > o = this .o ;
122
+ for (long i = index ; i != end ; i ++) {
123
+ if (o .isUnsubscribed ()) {
124
+ return ;
105
125
}
126
+ o .onNext ((int ) i );
127
+ }
128
+ if (!o .isUnsubscribed ()) {
129
+ o .onCompleted ();
106
130
}
107
131
}
108
132
}
0 commit comments