15
15
* limitations under the License.
16
16
*/
17
17
18
+ /*
19
+ * PLEASE NOTE that implementation of "insert" function was refactored to consume less stack memory
20
+ */
21
+
18
22
package com .itextpdf .layout .hyphenation ;
19
23
20
24
import java .io .Serializable ;
@@ -164,7 +168,7 @@ public void insert(String key, char val) {
164
168
char [] strkey = new char [len --];
165
169
key .getChars (0 , len , strkey , 0 );
166
170
strkey [len ] = 0 ;
167
- root = insert (root , strkey , 0 , val );
171
+ root = insert (new TreeInsertionParams ( root , strkey , 0 , val ) );
168
172
}
169
173
170
174
/**
@@ -178,13 +182,17 @@ public void insert(char[] key, int start, char val) {
178
182
if (freenode + len > eq .length ) {
179
183
redimNodeArrays (eq .length + BLOCK_SIZE );
180
184
}
181
- root = insert (root , key , start , val );
185
+ root = insert (new TreeInsertionParams ( root , key , start , val ) );
182
186
}
183
187
184
- /**
185
- * The actual insertion function, recursive version.
186
- */
187
- private char insert (char p , char [] key , int start , char val ) {
188
+ // PLEASE NOTE that this function is a result of refactoring "insert" method which
189
+ // is a modification of the original work
190
+ // Returns null if insertion is not needed and the id of the new node if insertion was performed
191
+ private Character insertNewBranchIfNeeded (TreeInsertionParams params ) {
192
+ char p = params .p ;
193
+ char [] key = params .key ;
194
+ int start = params .start ;
195
+ char val = params .val ;
188
196
int len = strlen (key , start );
189
197
if (p == 0 ) {
190
198
// this means there is no branch, this node will start a new branch.
@@ -204,54 +212,104 @@ private char insert(char p, char[] key, int start, char val) {
204
212
lo [p ] = 0 ;
205
213
}
206
214
return p ;
215
+ } else {
216
+ return null ;
207
217
}
218
+ }
208
219
209
- if (sc [p ] == 0xFFFF ) {
210
- // branch is compressed: need to decompress
211
- // this will generate garbage in the external key array
212
- // but we can do some garbage collection later
213
- char pp = freenode ++;
214
- lo [pp ] = lo [p ]; // previous pointer to key
215
- eq [pp ] = eq [p ]; // previous pointer to data
216
- lo [p ] = 0 ;
217
- if (len > 0 ) {
218
- sc [p ] = kv .get (lo [pp ]);
219
- eq [p ] = pp ;
220
- lo [pp ]++;
221
- if (kv .get (lo [pp ]) == 0 ) {
222
- // key completly decompressed leaving garbage in key array
223
- lo [pp ] = 0 ;
224
- sc [pp ] = 0 ;
225
- hi [pp ] = 0 ;
220
+ // PLEASE NOTE that this function is a result of refactoring "insert" method which
221
+ // is a modification of the original work
222
+ private char insertIntoExistingBranch (TreeInsertionParams params ) {
223
+ char initialP = params .p ;
224
+ TreeInsertionParams paramsToInsertNext = params ;
225
+ while (paramsToInsertNext != null ) {
226
+ char p = paramsToInsertNext .p ;
227
+ // We are inserting into an existing branch hence the id must be non-zero
228
+ assert p != 0 ;
229
+ char [] key = paramsToInsertNext .key ;
230
+ int start = paramsToInsertNext .start ;
231
+ char val = paramsToInsertNext .val ;
232
+ int len = strlen (key , start );
233
+ paramsToInsertNext = null ;
234
+
235
+ if (sc [p ] == 0xFFFF ) {
236
+ // branch is compressed: need to decompress
237
+ // this will generate garbage in the external key array
238
+ // but we can do some garbage collection later
239
+ char pp = freenode ++;
240
+ lo [pp ] = lo [p ]; // previous pointer to key
241
+ eq [pp ] = eq [p ]; // previous pointer to data
242
+ lo [p ] = 0 ;
243
+ if (len > 0 ) {
244
+ sc [p ] = kv .get (lo [pp ]);
245
+ eq [p ] = pp ;
246
+ lo [pp ]++;
247
+ if (kv .get (lo [pp ]) == 0 ) {
248
+ // key completly decompressed leaving garbage in key array
249
+ lo [pp ] = 0 ;
250
+ sc [pp ] = 0 ;
251
+ hi [pp ] = 0 ;
252
+ } else {
253
+ // we only got first char of key, rest is still there
254
+ sc [pp ] = 0xFFFF ;
255
+ }
226
256
} else {
227
- // we only got first char of key, rest is still there
257
+ // In this case we can save a node by swapping the new node
258
+ // with the compressed node
228
259
sc [pp ] = 0xFFFF ;
260
+ hi [p ] = pp ;
261
+ sc [p ] = 0 ;
262
+ eq [p ] = val ;
263
+ length ++;
264
+ break ;
229
265
}
230
- } else {
231
- // In this case we can save a node by swapping the new node
232
- // with the compressed node
233
- sc [pp ] = 0xFFFF ;
234
- hi [p ] = pp ;
235
- sc [p ] = 0 ;
236
- eq [p ] = val ;
237
- length ++;
238
- return p ;
239
266
}
240
- }
241
- char s = key [start ];
242
- if (s < sc [p ]) {
243
- lo [p ] = insert (lo [p ], key , start , val );
244
- } else if (s == sc [p ]) {
245
- if (s != 0 ) {
246
- eq [p ] = insert (eq [p ], key , start + 1 , val );
267
+ char s = key [start ];
268
+ if (s < sc [p ]) {
269
+ TreeInsertionParams branchParams = new TreeInsertionParams (lo [p ], key , start , val );
270
+ Character insertNew = insertNewBranchIfNeeded (branchParams );
271
+ if (insertNew == null ) {
272
+ paramsToInsertNext = branchParams ;
273
+ } else {
274
+ lo [p ] = insertNew ;
275
+ }
276
+ } else if (s == sc [p ]) {
277
+ if (s != 0 ) {
278
+ TreeInsertionParams branchParams = new TreeInsertionParams (eq [p ], key , start + 1 , val );
279
+ Character insertNew = insertNewBranchIfNeeded (branchParams );
280
+ if (insertNew == null ) {
281
+ paramsToInsertNext = branchParams ;
282
+ } else {
283
+ eq [p ] = insertNew ;
284
+ }
285
+ } else {
286
+ // key already in tree, overwrite data
287
+ eq [p ] = val ;
288
+ }
247
289
} else {
248
- // key already in tree, overwrite data
249
- eq [p ] = val ;
290
+ TreeInsertionParams branchParams = new TreeInsertionParams (hi [p ], key , start , val );
291
+ Character insertNew = insertNewBranchIfNeeded (branchParams );
292
+ if (insertNew == null ) {
293
+ paramsToInsertNext = branchParams ;
294
+ } else {
295
+ hi [p ] = insertNew ;
296
+ }
250
297
}
298
+ }
299
+ return initialP ;
300
+ }
301
+
302
+ /**
303
+ * The actual insertion function, recursive version.
304
+ * PLEASE NOTE that the implementation has been adapted to consume less stack memory
305
+ */
306
+ private char insert (TreeInsertionParams params ) {
307
+ Character newBranch = insertNewBranchIfNeeded (params );
308
+ if (newBranch == null ) {
309
+ return insertIntoExistingBranch (params );
251
310
} else {
252
- hi [ p ] = insert ( hi [ p ], key , start , val ) ;
311
+ return ( char ) newBranch ;
253
312
}
254
- return p ;
255
313
}
256
314
257
315
/**
@@ -514,5 +572,21 @@ private void compact(CharVector kx, TernaryTree map, char p) {
514
572
public Enumeration keys () {
515
573
return new TernaryTreeIterator (this );
516
574
}
575
+
576
+ // PLEASE NOTE that this is a helper class that was added as a result of the file modification
577
+ // and is not a part of the original file
578
+ private static class TreeInsertionParams {
579
+ char p ;
580
+ char [] key ;
581
+ int start ;
582
+ char val ;
583
+
584
+ public TreeInsertionParams (char p , char [] key , int start , char val ) {
585
+ this .p = p ;
586
+ this .key = key ;
587
+ this .start = start ;
588
+ this .val = val ;
589
+ }
590
+ }
517
591
}
518
592
0 commit comments