14
14
* See the License for the specific language governing permissions and
15
15
* limitations under the License.
16
16
*/
17
+ /*
18
+ * PLEASE NOTE that implementation of "insert" function was refactored to consume less stack memory
19
+ */
17
20
using System ;
18
21
using System . Collections ;
19
22
@@ -153,7 +156,7 @@ public virtual void Insert(String key, char val) {
153
156
char [ ] strkey = new char [ len -- ] ;
154
157
key . JGetChars ( 0 , len , strkey , 0 ) ;
155
158
strkey [ len ] = ( char ) 0 ;
156
- root = Insert ( root , strkey , 0 , val ) ;
159
+ root = Insert ( new TernaryTree . TreeInsertionParams ( root , strkey , 0 , val ) ) ;
157
160
}
158
161
159
162
/// <summary>Insert key.</summary>
@@ -165,11 +168,17 @@ public virtual void Insert(char[] key, int start, char val) {
165
168
if ( freenode + len > eq . Length ) {
166
169
RedimNodeArrays ( eq . Length + BLOCK_SIZE ) ;
167
170
}
168
- root = Insert ( root , key , start , val ) ;
171
+ root = Insert ( new TernaryTree . TreeInsertionParams ( root , key , start , val ) ) ;
169
172
}
170
173
171
- /// <summary>The actual insertion function, recursive version.</summary>
172
- private char Insert ( char p , char [ ] key , int start , char val ) {
174
+ // PLEASE NOTE that this function is a result of refactoring "insert" method which
175
+ // is a modification of the original work
176
+ // Returns null if insertion is not needed and the id of the new node if insertion was performed
177
+ private char ? InsertNewBranchIfNeeded ( TernaryTree . TreeInsertionParams @params ) {
178
+ char p = @params . p ;
179
+ char [ ] key = @params . key ;
180
+ int start = @params . start ;
181
+ char val = @params . val ;
173
182
int len = Strlen ( key , start ) ;
174
183
if ( p == 0 ) {
175
184
// this means there is no branch, this node will start a new branch.
@@ -193,61 +202,118 @@ private char Insert(char p, char[] key, int start, char val) {
193
202
}
194
203
return p ;
195
204
}
196
- if ( sc [ p ] == 0xFFFF ) {
197
- // branch is compressed: need to decompress
198
- // this will generate garbage in the external key array
199
- // but we can do some garbage collection later
200
- char pp = freenode ++ ;
201
- lo [ pp ] = lo [ p ] ;
202
- // previous pointer to key
203
- eq [ pp ] = eq [ p ] ;
204
- // previous pointer to data
205
- lo [ p ] = ( char ) 0 ;
206
- if ( len > 0 ) {
207
- sc [ p ] = kv . Get ( lo [ pp ] ) ;
208
- eq [ p ] = pp ;
209
- lo [ pp ] ++ ;
210
- if ( kv . Get ( lo [ pp ] ) == 0 ) {
211
- // key completly decompressed leaving garbage in key array
212
- lo [ pp ] = ( char ) 0 ;
213
- sc [ pp ] = ( char ) 0 ;
214
- hi [ pp ] = ( char ) 0 ;
205
+ else {
206
+ return null ;
207
+ }
208
+ }
209
+
210
+ // PLEASE NOTE that this function is a result of refactoring "insert" method which
211
+ // is a modification of the original work
212
+ private char InsertIntoExistingBranch ( TernaryTree . TreeInsertionParams @params ) {
213
+ char initialP = @params . p ;
214
+ TernaryTree . TreeInsertionParams paramsToInsertNext = @params ;
215
+ while ( paramsToInsertNext != null ) {
216
+ char p = paramsToInsertNext . p ;
217
+ // We are inserting into an existing branch hence the id must be non-zero
218
+ System . Diagnostics . Debug . Assert ( p != 0 ) ;
219
+ char [ ] key = paramsToInsertNext . key ;
220
+ int start = paramsToInsertNext . start ;
221
+ char val = paramsToInsertNext . val ;
222
+ int len = Strlen ( key , start ) ;
223
+ paramsToInsertNext = null ;
224
+ if ( sc [ p ] == 0xFFFF ) {
225
+ // branch is compressed: need to decompress
226
+ // this will generate garbage in the external key array
227
+ // but we can do some garbage collection later
228
+ char pp = freenode ++ ;
229
+ lo [ pp ] = lo [ p ] ;
230
+ // previous pointer to key
231
+ eq [ pp ] = eq [ p ] ;
232
+ // previous pointer to data
233
+ lo [ p ] = ( char ) 0 ;
234
+ if ( len > 0 ) {
235
+ sc [ p ] = kv . Get ( lo [ pp ] ) ;
236
+ eq [ p ] = pp ;
237
+ lo [ pp ] ++ ;
238
+ if ( kv . Get ( lo [ pp ] ) == 0 ) {
239
+ // key completly decompressed leaving garbage in key array
240
+ lo [ pp ] = ( char ) 0 ;
241
+ sc [ pp ] = ( char ) 0 ;
242
+ hi [ pp ] = ( char ) 0 ;
243
+ }
244
+ else {
245
+ // we only got first char of key, rest is still there
246
+ sc [ pp ] = ( char ) 0xFFFF ;
247
+ }
215
248
}
216
249
else {
217
- // we only got first char of key, rest is still there
250
+ // In this case we can save a node by swapping the new node
251
+ // with the compressed node
218
252
sc [ pp ] = ( char ) 0xFFFF ;
253
+ hi [ p ] = pp ;
254
+ sc [ p ] = ( char ) 0 ;
255
+ eq [ p ] = val ;
256
+ length ++ ;
257
+ break ;
219
258
}
220
259
}
221
- else {
222
- // In this case we can save a node by swapping the new node
223
- // with the compressed node
224
- sc [ pp ] = ( char ) 0xFFFF ;
225
- hi [ p ] = pp ;
226
- sc [ p ] = ( char ) 0 ;
227
- eq [ p ] = val ;
228
- length ++ ;
229
- return p ;
230
- }
231
- }
232
- char s = key [ start ] ;
233
- if ( s < sc [ p ] ) {
234
- lo [ p ] = Insert ( lo [ p ] , key , start , val ) ;
235
- }
236
- else {
237
- if ( s == sc [ p ] ) {
238
- if ( s != 0 ) {
239
- eq [ p ] = Insert ( eq [ p ] , key , start + 1 , val ) ;
260
+ char s = key [ start ] ;
261
+ if ( s < sc [ p ] ) {
262
+ TernaryTree . TreeInsertionParams branchParams = new TernaryTree . TreeInsertionParams ( lo [ p ] , key , start , val ) ;
263
+ char ? insertNew = InsertNewBranchIfNeeded ( branchParams ) ;
264
+ if ( insertNew == null ) {
265
+ paramsToInsertNext = branchParams ;
240
266
}
241
267
else {
242
- // key already in tree, overwrite data
243
- eq [ p ] = val ;
268
+ lo [ p ] = ( char ) insertNew ;
244
269
}
245
270
}
246
271
else {
247
- hi [ p ] = Insert ( hi [ p ] , key , start , val ) ;
272
+ if ( s == sc [ p ] ) {
273
+ if ( s != 0 ) {
274
+ TernaryTree . TreeInsertionParams branchParams = new TernaryTree . TreeInsertionParams ( eq [ p ] , key , start + 1 ,
275
+ val ) ;
276
+ char ? insertNew = InsertNewBranchIfNeeded ( branchParams ) ;
277
+ if ( insertNew == null ) {
278
+ paramsToInsertNext = branchParams ;
279
+ }
280
+ else {
281
+ eq [ p ] = ( char ) insertNew ;
282
+ }
283
+ }
284
+ else {
285
+ // key already in tree, overwrite data
286
+ eq [ p ] = val ;
287
+ }
288
+ }
289
+ else {
290
+ TernaryTree . TreeInsertionParams branchParams = new TernaryTree . TreeInsertionParams ( hi [ p ] , key , start , val ) ;
291
+ char ? insertNew = InsertNewBranchIfNeeded ( branchParams ) ;
292
+ if ( insertNew == null ) {
293
+ paramsToInsertNext = branchParams ;
294
+ }
295
+ else {
296
+ hi [ p ] = ( char ) insertNew ;
297
+ }
298
+ }
248
299
}
249
300
}
250
- return p ;
301
+ return initialP ;
302
+ }
303
+
304
+ /// <summary>The actual insertion function, recursive version.</summary>
305
+ /// <remarks>
306
+ /// The actual insertion function, recursive version.
307
+ /// PLEASE NOTE that the implementation has been adapted to consume less stack memory
308
+ /// </remarks>
309
+ private char Insert ( TernaryTree . TreeInsertionParams @params ) {
310
+ char ? newBranch = InsertNewBranchIfNeeded ( @params ) ;
311
+ if ( newBranch == null ) {
312
+ return InsertIntoExistingBranch ( @params ) ;
313
+ }
314
+ else {
315
+ return ( char ) newBranch ;
316
+ }
251
317
}
252
318
253
319
/// <summary>Compares 2 null terminated char arrays</summary>
@@ -496,5 +562,24 @@ private void Compact(CharVector kx, iText.Layout.Hyphenation.TernaryTree map, ch
496
562
public virtual IEnumerator Keys ( ) {
497
563
return new TernaryTreeIterator ( this ) ;
498
564
}
565
+
566
+ private class TreeInsertionParams {
567
+ internal char p ;
568
+
569
+ internal char [ ] key ;
570
+
571
+ internal int start ;
572
+
573
+ internal char val ;
574
+
575
+ public TreeInsertionParams ( char p , char [ ] key , int start , char val ) {
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
+ this . p = p ;
579
+ this . key = key ;
580
+ this . start = start ;
581
+ this . val = val ;
582
+ }
583
+ }
499
584
}
500
585
}
0 commit comments