@@ -120,14 +120,14 @@ static boolean isUserCode(String line) {
120
120
* from the assembly stack trace
121
121
*/
122
122
static String [] extractOperatorAssemblyInformationParts (String source ) {
123
- Iterator <Substring > traces = trimmedNonemptyLines (source );
123
+ Iterator <StackLineView > traces = trimmedNonemptyLines (source );
124
124
125
125
if (!traces .hasNext ()) {
126
126
return new String [0 ];
127
127
}
128
128
129
- Substring prevLine = null ;
130
- Substring currentLine = traces .next ();
129
+ StackLineView prevLine = null ;
130
+ StackLineView currentLine = traces .next ();
131
131
132
132
if (currentLine .isUserCode ()) {
133
133
// No line is a Reactor API line.
@@ -157,20 +157,20 @@ static String[] extractOperatorAssemblyInformationParts(String source) {
157
157
*
158
158
* @implNote This implementation attempts to minimize allocations.
159
159
*/
160
- private static Iterator <Substring > trimmedNonemptyLines (String source ) {
161
- return new Iterator <Substring >() {
162
- private int index = 0 ;
160
+ private static Iterator <StackLineView > trimmedNonemptyLines (String source ) {
161
+ return new Iterator <StackLineView >() {
162
+ private int index = 0 ;
163
163
@ Nullable
164
- private Substring next = getNextLine ();
164
+ private StackLineView next = getNextLine ();
165
165
166
166
@ Override
167
167
public boolean hasNext () {
168
168
return next != null ;
169
169
}
170
170
171
171
@ Override
172
- public Substring next () {
173
- Substring current = next ;
172
+ public StackLineView next () {
173
+ StackLineView current = next ;
174
174
if (current == null ) {
175
175
throw new NoSuchElementException ();
176
176
}
@@ -179,13 +179,13 @@ public Substring next() {
179
179
}
180
180
181
181
@ Nullable
182
- private Substring getNextLine () {
182
+ private StackLineView getNextLine () {
183
183
while (index < source .length ()) {
184
184
int end = source .indexOf ('\n' , index );
185
185
if (end == -1 ) {
186
186
end = source .length ();
187
187
}
188
- Substring line = new Substring (source , index , end ).trim ();
188
+ StackLineView line = new StackLineView (source , index , end ).trim ();
189
189
index = end + 1 ;
190
190
if (!line .isEmpty ()) {
191
191
return line ;
@@ -196,63 +196,70 @@ private Substring getNextLine() {
196
196
};
197
197
}
198
198
199
- // XXX: Explain.
200
- private static final class Substring {
201
- private final String str ;
202
- private final int start ;
203
- private final int end ;
199
+ /**
200
+ * Provides optimized access to underlying {@link String} with common operations to
201
+ * view the stack trace line without unnecessary allocation of temporary
202
+ * {@code String} objects.
203
+ */
204
+ static final class StackLineView {
205
+
206
+ private final String underlying ;
207
+ private final int start ;
208
+ private final int end ;
204
209
205
- Substring (String str , int start , int end ) {
206
- this .str = str ;
210
+ StackLineView (String underlying , int start , int end ) {
211
+ this .underlying = underlying ;
207
212
this .start = start ;
208
213
this .end = end ;
209
214
}
210
215
211
- Substring trim () {
216
+ StackLineView trim () {
212
217
int newStart = start ;
213
- while (newStart < end && str .charAt (newStart ) <= ' ' ) {
218
+ while (newStart < end && underlying .charAt (newStart ) <= ' ' ) {
214
219
newStart ++;
215
220
}
216
221
int newEnd = end ;
217
- while (newEnd > newStart && str .charAt (newEnd - 1 ) <= ' ' ) {
222
+ while (newEnd > newStart && underlying .charAt (newEnd - 1 ) <= ' ' ) {
218
223
newEnd --;
219
224
}
220
- return newStart == start && newEnd == end ? this : new Substring (str , newStart , newEnd );
225
+ return newStart == start && newEnd == end ? this : new StackLineView (
226
+ underlying , newStart , newEnd );
221
227
}
222
228
223
229
boolean isEmpty () {
224
230
return start == end ;
225
231
}
226
232
227
233
boolean startsWith (String prefix ) {
228
- return str .startsWith (prefix , start );
234
+ boolean canFit = end - start >= prefix .length ();
235
+ return canFit && underlying .startsWith (prefix , start );
229
236
}
230
237
231
238
boolean contains (String substring ) {
232
- int index = str .indexOf (substring , start );
233
- return index >= 0 && index < end ;
239
+ int index = underlying .indexOf (substring , start );
240
+ return index >= start && ( index + ( substring . length () - 1 ) < end ) ;
234
241
}
235
242
236
243
boolean isUserCode () {
237
244
return !startsWith (PUBLISHER_PACKAGE_PREFIX ) || contains ("Test" );
238
245
}
239
246
240
- Substring withoutLocationSuffix () {
241
- int linePartIndex = str .indexOf ('(' , start );
247
+ StackLineView withoutLocationSuffix () {
248
+ int linePartIndex = underlying .indexOf ('(' , start );
242
249
return linePartIndex > 0 && linePartIndex < end
243
- ? new Substring ( str , start , linePartIndex )
250
+ ? new StackLineView ( underlying , start , linePartIndex )
244
251
: this ;
245
252
}
246
253
247
- Substring withoutPublisherPackagePrefix () {
254
+ StackLineView withoutPublisherPackagePrefix () {
248
255
return startsWith (PUBLISHER_PACKAGE_PREFIX )
249
- ? new Substring ( str , start + PUBLISHER_PACKAGE_PREFIX .length (), end )
256
+ ? new StackLineView ( underlying , start + PUBLISHER_PACKAGE_PREFIX .length (), end )
250
257
: this ;
251
258
}
252
259
253
260
@ Override
254
261
public String toString () {
255
- return str .substring (start , end );
262
+ return underlying .substring (start , end );
256
263
}
257
264
}
258
265
}
0 commit comments