KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > apache > xerces > utils > StringPool


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package org.enhydra.apache.xerces.utils;
59
60 /**
61  *
62  * @version
63  */

64 public final class StringPool {
65     //
66
// Debugging
67
//
68
private static final boolean DEBUG_ADDITIONS = false;
69     /**
70      * Constants
71      */

72     public static final int NULL_STRING = -1; // null
73
public static final int EMPTY_STRING = 0; // ""
74
/**
75      *
76      */

77     public interface StringProducer {
78         /**
79          *
80          */

81         public String JavaDoc toString(int offset, int length);
82         /**
83          *
84          */

85         public void releaseString(int offset, int length);
86         /**
87          *
88          */

89         public boolean equalsString(int offset, int length, char[] strChars, int strOffset, int strLength);
90     };
91     //
92
// Chunk size constants
93
//
94
private static final int INITIAL_CHUNK_SHIFT = 8; // 2^8 = 256
95
private static final int INITIAL_CHUNK_SIZE = (1 << INITIAL_CHUNK_SHIFT);
96     private static final int CHUNK_SHIFT = 13; // 2^13 = 8k
97
private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
98     private static final int CHUNK_MASK = CHUNK_SIZE - 1;
99     private static final int INITIAL_CHUNK_COUNT = (1 << (16 - CHUNK_SHIFT)); // 2^16 = 64k
100
//
101
// Instance variables
102
//
103
//
104
// String and Symbol arrays
105
//
106
private int fStringCount = 0;
107     private int fStringFreeList = -1;
108     private String JavaDoc[][] fString = new String JavaDoc[INITIAL_CHUNK_COUNT][];
109     private StringPool.StringProducer[][] fStringProducer = new StringPool.StringProducer[INITIAL_CHUNK_COUNT][];
110     private int[][] fOffset = new int[INITIAL_CHUNK_COUNT][];
111     private int[][] fLength = new int[INITIAL_CHUNK_COUNT][];
112     private int[][] fCharsOffset = new int[INITIAL_CHUNK_COUNT][];
113     //
114
// String Lists
115
//
116
private int fStringListCount = 0;
117     private int fActiveStringList = -1;
118     private int[][] fStringList = new int[INITIAL_CHUNK_COUNT][];
119     //
120
// Symbol Hashtable
121
//
122
private static final int INITIAL_BUCKET_SIZE = 4;
123     private static final int HASHTABLE_SIZE = 128;
124     private int[][] fSymbolTable = new int[HASHTABLE_SIZE][];
125     //
126
// Symbol Cache
127
//
128
private SymbolCache fSymbolCache = null;
129     //
130
//
131
//
132
public StringPool() {
133         fSymbolCache = new SymbolCache();
134         if (addSymbol("") != EMPTY_STRING)
135             throw new RuntimeException JavaDoc("UTL002 cannot happen");
136     }
137     //
138
//
139
//
140
public void reset() {
141         int chunk = 0;
142         int index = 0;
143         for (int i = 0; i < fStringCount; i++) {
144             fString[chunk][index] = null;
145             if (fStringProducer[chunk][index] != null)
146                 fStringProducer[chunk][index].releaseString(fOffset[chunk][index], fLength[chunk][index]);
147             fStringProducer[chunk][index] = null;
148             if (++index == CHUNK_SIZE) {
149                 chunk++;
150                 index = 0;
151             }
152         }
153         for (int i = 0; i < HASHTABLE_SIZE; i++)
154             fSymbolTable[i] = null;
155         fStringCount = 0;
156         fStringFreeList = -1;
157         fStringListCount = 0;
158         fActiveStringList = -1;
159         fSymbolCache.reset();
160         fShuffleCount = 0;
161         if (addSymbol("") != EMPTY_STRING)
162             throw new RuntimeException JavaDoc("UTL002 cannot happen");
163     }
164     //
165
// String interfaces
166
//
167
private void ensureCapacity(int chunk, int index) {
168
169         if (chunk >= fOffset.length) {
170                 String JavaDoc[][] newString = new String JavaDoc[chunk * 2][];
171                 System.arraycopy(fString, 0, newString, 0, chunk);
172                 fString = newString;
173                 StringPool.StringProducer[][] newProducer = new StringPool.StringProducer[chunk * 2][];
174                 System.arraycopy(fStringProducer, 0, newProducer, 0, chunk);
175                 fStringProducer = newProducer;
176                 int[][] newInt = new int[chunk * 2][];
177                 System.arraycopy(fOffset, 0, newInt, 0, chunk);
178                 fOffset = newInt;
179                 newInt = new int[chunk * 2][];
180                 System.arraycopy(fLength, 0, newInt, 0, chunk);
181                 fLength = newInt;
182                 newInt = new int[chunk * 2][];
183                 System.arraycopy(fCharsOffset, 0, newInt, 0, chunk);
184                 fCharsOffset = newInt;
185         } else if (fOffset[chunk] == null) {
186         }
187         else if (index >= fOffset[chunk].length) {
188                 String JavaDoc[] newString = new String JavaDoc[index * 2];
189                 System.arraycopy(fString[chunk], 0, newString, 0, index);
190                 fString[chunk] = newString;
191                 StringPool.StringProducer[] newProducer = new StringPool.StringProducer[index * 2];
192                 System.arraycopy(fStringProducer[chunk], 0, newProducer, 0, index);
193                 fStringProducer[chunk] = newProducer;
194                 int[] newInt = new int[index * 2];
195                 System.arraycopy(fOffset[chunk], 0, newInt, 0, index);
196                 fOffset[chunk] = newInt;
197                 newInt = new int[index * 2];
198                 System.arraycopy(fLength[chunk], 0, newInt, 0, index);
199                 fLength[chunk] = newInt;
200                 newInt = new int[index * 2];
201                 System.arraycopy(fCharsOffset[chunk], 0, newInt, 0, index);
202                 fCharsOffset[chunk] = newInt;
203                 return;
204         } else {
205                 return;
206         }
207         fString[chunk] = new String JavaDoc[INITIAL_CHUNK_SIZE];
208         fStringProducer[chunk] = new StringPool.StringProducer[INITIAL_CHUNK_SIZE];
209         fOffset[chunk] = new int[INITIAL_CHUNK_SIZE];
210         fLength[chunk] = new int[INITIAL_CHUNK_SIZE];
211         fCharsOffset[chunk] = new int[INITIAL_CHUNK_SIZE];
212         return;
213     }
214     public int addString(String JavaDoc str) {
215         int chunk;
216         int index;
217         int stringIndex;
218         if (fStringFreeList != -1) {
219             stringIndex = fStringFreeList;
220             chunk = stringIndex >> CHUNK_SHIFT;
221             index = stringIndex & CHUNK_MASK;
222             fStringFreeList = fOffset[chunk][index];
223         } else {
224             stringIndex = fStringCount++;
225             chunk = stringIndex >> CHUNK_SHIFT;
226             index = stringIndex & CHUNK_MASK;
227             ensureCapacity(chunk, index);
228         }
229         fString[chunk][index] = str;
230         fStringProducer[chunk][index] = null;
231         fOffset[chunk][index] = 0;
232         fLength[chunk][index] = str.length();
233         fCharsOffset[chunk][index] = -1;
234         if (DEBUG_ADDITIONS)
235             System.err.println("addString(" + str + ") " + stringIndex);
236         return stringIndex;
237     }
238     public int addString(StringPool.StringProducer stringProducer, int offset, int length)
239     {
240         int chunk;
241         int index;
242         int stringIndex;
243         if (fStringFreeList != -1) {
244             stringIndex = fStringFreeList;
245             chunk = stringIndex >> CHUNK_SHIFT;
246             index = stringIndex & CHUNK_MASK;
247             fStringFreeList = fOffset[chunk][index];
248         } else {
249             stringIndex = fStringCount++;
250             chunk = stringIndex >> CHUNK_SHIFT;
251             index = stringIndex & CHUNK_MASK;
252             ensureCapacity(chunk, index);
253         }
254         fString[chunk][index] = null;
255         fStringProducer[chunk][index] = stringProducer;
256         fOffset[chunk][index] = offset;
257         fLength[chunk][index] = length;
258         fCharsOffset[chunk][index] = -1;
259         if (DEBUG_ADDITIONS)
260             System.err.println("addString(" + stringProducer.toString(offset, length) + ") " + stringIndex);
261         return stringIndex;
262     }
263     //
264
// Symbol interfaces
265
//
266
public SymbolCache getSymbolCache() {
267         return fSymbolCache;
268     }
269     //private static int fShuffleCount = 0;
270
private int fShuffleCount = 0;
271     public void resetShuffleCount() {
272         fShuffleCount = 0;
273     }
274     public void updateCacheLine(int symbolIndex, int totalMisses, int length) {
275         if (++fShuffleCount > 200) {
276 // if (fShuffleCount == 201) System.out.println("Stopped shuffling...");
277
return;
278         }
279 // if ((fShuffleCount % 10) == 0) System.out.println("Shuffling pass " + fShuffleCount + " ...");
280
int chunk = symbolIndex >> CHUNK_SHIFT;
281         int index = symbolIndex & CHUNK_MASK;
282         int charsOffset = fCharsOffset[chunk][index];
283         fSymbolCache.updateCacheLine(charsOffset, totalMisses, length);
284     }
285     public int createNonMatchingSymbol(int startOffset,
286                                        int entry,
287                                        int[] entries,
288                                        int offset) throws Exception JavaDoc
289     {
290         int chunk;
291         int index;
292         int stringIndex;
293         if (fStringFreeList != -1) {
294             stringIndex = fStringFreeList;
295             chunk = stringIndex >> CHUNK_SHIFT;
296             index = stringIndex & CHUNK_MASK;
297             fStringFreeList = fOffset[chunk][index];
298         } else {
299             stringIndex = fStringCount++;
300             chunk = stringIndex >> CHUNK_SHIFT;
301             index = stringIndex & CHUNK_MASK;
302             ensureCapacity(chunk, index);
303         }
304         String JavaDoc str = fSymbolCache.createSymbol(stringIndex, startOffset, entry, entries, offset);
305         int slen = str.length();
306         fString[chunk][index] = str;
307         fStringProducer[chunk][index] = null;
308         fOffset[chunk][index] = -1;
309         fLength[chunk][index] = slen;
310         fCharsOffset[chunk][index] = startOffset;
311
312         int hashcode = StringHasher.hashString(str, slen);
313         int hc = hashcode % HASHTABLE_SIZE;
314         int[] bucket = fSymbolTable[hc];
315         hashSymbol(bucket, hashcode, chunk, index);
316         if (DEBUG_ADDITIONS)
317             System.err.println("addSymbolNew(" + str + ") " + stringIndex);
318         return stringIndex;
319     }
320     private void hashSymbol(int[] bucket, int hashcode, int chunk, int index) {
321         if (bucket == null) {
322             bucket = new int[1 + (INITIAL_BUCKET_SIZE * 3)];
323             bucket[0] = 1;
324             bucket[1] = hashcode;
325             bucket[2] = chunk;
326             bucket[3] = index;
327             int hc = hashcode % HASHTABLE_SIZE;
328             fSymbolTable[hc] = bucket;
329         } else {
330             int count = bucket[0];
331             int offset = 1 + (count * 3);
332             if (offset == bucket.length) {
333                 int newSize = count + INITIAL_BUCKET_SIZE;
334                 int[] newBucket = new int[1 + (newSize * 3)];
335                 System.arraycopy(bucket, 0, newBucket, 0, offset);
336                 bucket = newBucket;
337                 int hc = hashcode % HASHTABLE_SIZE;
338                 fSymbolTable[hc] = bucket;
339             }
340             bucket[offset++] = hashcode;
341             bucket[offset++] = chunk;
342             bucket[offset++] = index;
343             bucket[0] = ++count;
344         }
345     }
346     public int addSymbol(String JavaDoc str) {
347         int slen = str.length();
348         int hashcode = StringHasher.hashString(str, slen);
349         int hc = hashcode % HASHTABLE_SIZE;
350         int[] bucket = fSymbolTable[hc];
351         if (bucket != null) {
352             int j = 1;
353             for (int i = 0; i < bucket[0]; i++) {
354                 if (bucket[j] == hashcode) {
355                     int chunk = bucket[j+1];
356                     int index = bucket[j+2];
357                     if (slen == fLength[chunk][index]) {
358                         int symoff = fCharsOffset[chunk][index];
359                         boolean match = true;
360                         char[] symbolChars = fSymbolCache.getSymbolChars();
361                         for (int k = 0; k < slen; k++) {
362                             if (symbolChars[symoff++] != str.charAt(k)) {
363                                 match = false;
364                                 break;
365                             }
366                         }
367                         if (match) {
368                             return (chunk << CHUNK_SHIFT) + index;
369                         }
370                     }
371                 }
372                 j += 3;
373             }
374         }
375         int chunk;
376         int index;
377         int stringIndex;
378         if (fStringFreeList != -1) {
379             stringIndex = fStringFreeList;
380             chunk = stringIndex >> CHUNK_SHIFT;
381             index = stringIndex & CHUNK_MASK;
382             fStringFreeList = fOffset[chunk][index];
383         } else {
384             stringIndex = fStringCount++;
385             chunk = stringIndex >> CHUNK_SHIFT;
386             index = stringIndex & CHUNK_MASK;
387             ensureCapacity(chunk, index);
388         }
389         fString[chunk][index] = str;
390         fStringProducer[chunk][index] = null;
391         fOffset[chunk][index] = -1;
392         fLength[chunk][index] = slen;
393         fCharsOffset[chunk][index] = fSymbolCache.addSymbolToCache(str, slen, stringIndex);
394
395         hashSymbol(bucket, hashcode, chunk, index);
396         if (DEBUG_ADDITIONS)
397             System.err.println("addSymbolNew(" + str + ") " + stringIndex);
398         return stringIndex;
399     }
400     public int addSymbol(StringPool.StringProducer stringProducer, int offset, int length, int hashcode) {
401         int hc = hashcode % HASHTABLE_SIZE;
402         int[] bucket = fSymbolTable[hc];
403         if (bucket != null) {
404             int j = 1;
405             for (int i = 0; i < bucket[0]; i++) {
406                 if (bucket[j] == hashcode) {
407                     int chunk = bucket[j+1];
408                     int index = bucket[j+2];
409                     char[] symbolChars = fSymbolCache.getSymbolChars();
410                     if (stringProducer.equalsString(offset, length, symbolChars, fCharsOffset[chunk][index], fLength[chunk][index])) {
411                         stringProducer.releaseString(offset, length);
412                         return (chunk << CHUNK_SHIFT) + index;
413                     }
414                 }
415                 j += 3;
416             }
417         }
418         int chunk;
419         int index;
420         int stringIndex;
421         if (fStringFreeList != -1) {
422             stringIndex = fStringFreeList;
423             chunk = stringIndex >> CHUNK_SHIFT;
424             index = stringIndex & CHUNK_MASK;
425             fStringFreeList = fOffset[chunk][index];
426         } else {
427             stringIndex = fStringCount++;
428             chunk = stringIndex >> CHUNK_SHIFT;
429             index = stringIndex & CHUNK_MASK;
430             ensureCapacity(chunk, index);
431         }
432         String JavaDoc str = stringProducer.toString(offset, length);
433         stringProducer.releaseString(offset, length);
434         int slen = str.length();
435         fString[chunk][index] = str;
436         fStringProducer[chunk][index] = null;
437         fOffset[chunk][index] = -1;
438         fLength[chunk][index] = slen;
439         fCharsOffset[chunk][index] = fSymbolCache.addSymbolToCache(str, slen, stringIndex);
440
441         hashSymbol(bucket, hashcode, chunk, index);
442         if (DEBUG_ADDITIONS)
443             System.err.println("addSymbol(" + str + ") " + stringIndex);
444         return stringIndex;
445     }
446     public int lookupSymbol(StringPool.StringProducer stringProducer, int offset, int length, int hashcode) {
447         int hc = hashcode % HASHTABLE_SIZE;
448         int[] bucket = fSymbolTable[hc];
449         if (bucket != null) {
450             int j = 1;
451             for (int i = 0; i < bucket[0]; i++) {
452                 if (bucket[j] == hashcode) {
453                     int chunk = bucket[j+1];
454                     int index = bucket[j+2];
455                     char[] symbolChars = fSymbolCache.getSymbolChars();
456                     if (stringProducer.equalsString(offset, length, symbolChars, fCharsOffset[chunk][index], fLength[chunk][index])) {
457                         return (chunk << CHUNK_SHIFT) + index;
458                     }
459                 }
460                 j += 3;
461             }
462         }
463         return -1;
464     }
465     public int addNewSymbol(String JavaDoc str, int hashcode) {
466         int hc = hashcode % HASHTABLE_SIZE;
467         int[] bucket = fSymbolTable[hc];
468         int chunk;
469         int index;
470         int stringIndex;
471         if (fStringFreeList != -1) {
472             stringIndex = fStringFreeList;
473             chunk = stringIndex >> CHUNK_SHIFT;
474             index = stringIndex & CHUNK_MASK;
475             fStringFreeList = fOffset[chunk][index];
476         } else {
477             stringIndex = fStringCount++;
478             chunk = stringIndex >> CHUNK_SHIFT;
479             index = stringIndex & CHUNK_MASK;
480             ensureCapacity(chunk, index);
481         }
482         int slen = str.length();
483         fString[chunk][index] = str;
484         fStringProducer[chunk][index] = null;
485         fOffset[chunk][index] = -1;
486         fLength[chunk][index] = slen;
487         fCharsOffset[chunk][index] = fSymbolCache.addSymbolToCache(str, slen, stringIndex);
488
489         hashSymbol(bucket, hashcode, chunk, index);
490         if (DEBUG_ADDITIONS)
491             System.err.println("addSymbolNew(" + str + ") " + stringIndex);
492         return stringIndex;
493     }
494     public int addSymbol(int stringIndex) {
495         if (stringIndex < 0 || stringIndex >= fStringCount)
496             return -1;
497         int chunk = stringIndex >> CHUNK_SHIFT;
498         int index = stringIndex & CHUNK_MASK;
499         if (fOffset[chunk][index] == -1)
500             return stringIndex;
501         String JavaDoc s = fString[chunk][index];
502         if (s == null) {
503             s = fStringProducer[chunk][index].toString(fOffset[chunk][index], fLength[chunk][index]);
504             fStringProducer[chunk][index].releaseString(fOffset[chunk][index], fLength[chunk][index]);
505             fString[chunk][index] = s;
506             fStringProducer[chunk][index] = null;
507         }
508         return addSymbol(s);
509     }
510     //
511
// Get characters for defined symbols
512
//
513
public class CharArrayRange {
514         public char[] chars;
515         public int offset;
516         public int length;
517     }
518     public CharArrayRange createCharArrayRange() {
519         return new CharArrayRange();
520     }
521     public void getCharArrayRange(int symbolIndex, CharArrayRange r) {
522         if (symbolIndex < 0 || symbolIndex >= fStringCount) {
523             r.chars = null;
524             r.offset = -1;
525             r.length = -1;
526             return;
527         }
528         int chunk = symbolIndex >> CHUNK_SHIFT;
529         int index = symbolIndex & CHUNK_MASK;
530         r.chars = fSymbolCache.getSymbolChars();
531         r.offset = fCharsOffset[chunk][index];
532         r.length = fLength[chunk][index];
533     }
534     public boolean equalNames(int stringIndex1, int stringIndex2) {
535         if (stringIndex1 == stringIndex2)
536             return true;
537         return false;
538     }
539     //
540
// String list support
541
//
542
private void ensureListCapacity(int chunk, int index) {
543         if (chunk >= fStringList.length) {
544             int[][] newInt = new int[chunk * 2][];
545             System.arraycopy(fStringList, 0, newInt, 0, chunk);
546             fStringList = newInt;
547             fStringList[chunk] = new int[INITIAL_CHUNK_SIZE];
548         } else if (fStringList[chunk] == null) {
549             fStringList[chunk] = new int[INITIAL_CHUNK_SIZE];
550         } else if (index >= fStringList[chunk].length) {
551             int[] newInt = new int[index * 2];
552             System.arraycopy(fStringList[chunk], 0, newInt, 0, index);
553             fStringList[chunk] = newInt;
554         }
555     }
556     public int startStringList() {
557         fActiveStringList = fStringListCount;
558         return fStringListCount;
559     }
560     public boolean addStringToList(int stringListIndex, int stringIndex) {
561         if (stringIndex == -1 || stringListIndex != fActiveStringList)
562             return false;
563         int chunk = fStringListCount >> CHUNK_SHIFT;
564         int index = fStringListCount & CHUNK_MASK;
565         ensureListCapacity(chunk, index);
566         fStringList[chunk][index] = stringIndex;
567         fStringListCount++;
568         return true;
569     }
570     public void finishStringList(int stringListIndex) {
571         if (stringListIndex != fActiveStringList)
572             return;
573         int chunk = fStringListCount >> CHUNK_SHIFT;
574         int index = fStringListCount & CHUNK_MASK;
575         ensureListCapacity(chunk, index);
576         fStringList[chunk][index] = -1;
577         fActiveStringList = -1;
578         fStringListCount++;
579     }
580     public int stringListLength(int stringListIndex) {
581         int chunk = stringListIndex >> CHUNK_SHIFT;
582         int index = stringListIndex & CHUNK_MASK;
583         int count = 0;
584         while (true) {
585             if (fStringList[chunk][index] == -1)
586                 return count;
587             count++;
588             if (++index == CHUNK_SIZE) {
589                 chunk++;
590                 index = 0;
591             }
592         }
593     }
594     public boolean stringInList(int stringListIndex, int stringIndex) {
595         int chunk = stringListIndex >> CHUNK_SHIFT;
596         int index = stringListIndex & CHUNK_MASK;
597         while (true) {
598             if (fStringList[chunk][index] == stringIndex)
599                 return true;
600             if (fStringList[chunk][index] == -1)
601                 return false;
602             if (++index == CHUNK_SIZE) {
603                 chunk++;
604                 index = 0;
605             }
606         }
607     }
608     public String JavaDoc stringListAsString(int stringListIndex) {
609         int chunk = stringListIndex >> CHUNK_SHIFT;
610         int index = stringListIndex & CHUNK_MASK;
611         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
612         char sep = '(';
613         while (fStringList[chunk][index] != -1) {
614             sb.append(sep);
615             sep = '|';
616             sb.append(toString(fStringList[chunk][index]));
617             if (++index == CHUNK_SIZE) {
618                 chunk++;
619                 index = 0;
620             }
621         }
622         if (sep == '|')
623             sb.append(')');
624         return sb.toString();
625     }
626     public int[] stringListAsIntArray(int stringListIndex) {
627         int chunk = stringListIndex >> CHUNK_SHIFT;
628         int index = stringListIndex & CHUNK_MASK;
629         int len = stringListLength(stringListIndex);
630
631         int[] ia = new int[len];
632         for (int i=0; i<len; i++) {
633             ia[i] = fStringList[chunk][index];
634             if (++index == CHUNK_SIZE) {
635                 chunk++;
636                 index = 0;
637             }
638         }
639         return ia;
640     }
641     //
642
//
643
//
644
private void releaseStringInternal(int chunk, int index) {
645         fString[chunk][index] = null;
646         fStringProducer[chunk][index] = null;
647         fLength[chunk][index] = 0;
648         //
649
// REVISIT - not synchronized.
650
//
651
fOffset[chunk][index] = fStringFreeList;
652         int offset = (chunk << CHUNK_SHIFT) + index;
653         fStringFreeList = offset;
654     }
655     //
656
//
657
//
658
public void releaseString(int stringIndex) {
659         if (stringIndex < 0 || stringIndex >= fStringCount)
660             return;
661         int chunk = stringIndex >> CHUNK_SHIFT;
662         int index = stringIndex & CHUNK_MASK;
663         if (fOffset[chunk][index] != -1) {
664             if (fStringProducer[chunk][index] != null)
665                 fStringProducer[chunk][index].releaseString(fOffset[chunk][index], fLength[chunk][index]);
666             releaseStringInternal(chunk, index);
667         }
668     }
669     //
670
// Get String value. Cache the result.
671
//
672
public String JavaDoc toString(int stringIndex) {
673         if (stringIndex >= 0 && stringIndex < fString[0].length) {
674             String JavaDoc result = fString[0][stringIndex];
675             if (result != null) {
676                 return result;
677             }
678         }
679
680         if (stringIndex < 0 || stringIndex >= fStringCount)
681             return null;
682         int chunk = stringIndex >> CHUNK_SHIFT;
683         int index = stringIndex & CHUNK_MASK;
684         String JavaDoc s = fString[chunk][index];
685         if (s != null)
686             return s;
687         s = fStringProducer[chunk][index].toString(fOffset[chunk][index], fLength[chunk][index]);
688         fStringProducer[chunk][index].releaseString(fOffset[chunk][index], fLength[chunk][index]);
689         fString[chunk][index] = s;
690         fStringProducer[chunk][index] = null;
691         return s;
692     }
693     //
694
//
695
//
696
public String JavaDoc orphanString(int stringIndex) {
697         if (stringIndex < 0 || stringIndex >= fStringCount)
698             return null;
699         int chunk = stringIndex >> CHUNK_SHIFT;
700         int index = stringIndex & CHUNK_MASK;
701         String JavaDoc s = fString[chunk][index];
702         if (s == null) {
703             s = fStringProducer[chunk][index].toString(fOffset[chunk][index], fLength[chunk][index]);
704             fStringProducer[chunk][index].releaseString(fOffset[chunk][index], fLength[chunk][index]);
705             releaseStringInternal(chunk, index);
706         } else if (fOffset[chunk][index] != -1) {
707             releaseStringInternal(chunk, index);
708         }
709         return s;
710     }
711 }
712
Popular Tags