KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > xpath > datamodel > 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.xquark.xpath.datamodel.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 boolean ensureCapacity(int chunk, int index) {
168         try {
169             return fOffset[chunk][index] == 0;
170         } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
171             if (index == 0) {
172                 String JavaDoc[][] newString = new String JavaDoc[chunk * 2][];
173                 System.arraycopy(fString, 0, newString, 0, chunk);
174                 fString = newString;
175                 StringPool.StringProducer[][] newProducer = new StringPool.StringProducer[chunk * 2][];
176                 System.arraycopy(fStringProducer, 0, newProducer, 0, chunk);
177                 fStringProducer = newProducer;
178                 int[][] newInt = new int[chunk * 2][];
179                 System.arraycopy(fOffset, 0, newInt, 0, chunk);
180                 fOffset = newInt;
181                 newInt = new int[chunk * 2][];
182                 System.arraycopy(fLength, 0, newInt, 0, chunk);
183                 fLength = newInt;
184                 newInt = new int[chunk * 2][];
185                 System.arraycopy(fCharsOffset, 0, newInt, 0, chunk);
186                 fCharsOffset = newInt;
187             } else {
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 true;
204             }
205         } catch (NullPointerException JavaDoc ex) {
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 true;
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 //System.err.println("found symbol " + toString(symbolIndex) + " after " + totalMisses + " total misses (" + (totalMisses/length) + " misses per character).");
276
if (++fShuffleCount > 200) {
277 // if (fShuffleCount == 201) System.out.println("Stopped shuffling...");
278
return;
279         }
280 // if ((fShuffleCount % 10) == 0) System.out.println("Shuffling pass " + fShuffleCount + " ...");
281
int chunk = symbolIndex >> CHUNK_SHIFT;
282         int index = symbolIndex & CHUNK_MASK;
283         int charsOffset = fCharsOffset[chunk][index];
284         fSymbolCache.updateCacheLine(charsOffset, totalMisses, length);
285     }
286     public int createNonMatchingSymbol(int startOffset,
287                                        int entry,
288                                        int[] entries,
289                                        int offset) throws Exception JavaDoc
290     {
291         int chunk;
292         int index;
293         int stringIndex;
294         if (fStringFreeList != -1) {
295             stringIndex = fStringFreeList;
296             chunk = stringIndex >> CHUNK_SHIFT;
297             index = stringIndex & CHUNK_MASK;
298             fStringFreeList = fOffset[chunk][index];
299         } else {
300             stringIndex = fStringCount++;
301             chunk = stringIndex >> CHUNK_SHIFT;
302             index = stringIndex & CHUNK_MASK;
303             ensureCapacity(chunk, index);
304         }
305         String JavaDoc str = fSymbolCache.createSymbol(stringIndex, startOffset, entry, entries, offset);
306         int slen = str.length();
307         fString[chunk][index] = str;
308         fStringProducer[chunk][index] = null;
309         fOffset[chunk][index] = -1;
310         fLength[chunk][index] = slen;
311         fCharsOffset[chunk][index] = startOffset;
312
313         int hashcode = StringHasher.hashString(str, slen);
314         int hc = hashcode % HASHTABLE_SIZE;
315         int[] bucket = fSymbolTable[hc];
316         hashSymbol(bucket, hashcode, chunk, index);
317         if (DEBUG_ADDITIONS)
318             System.err.println("addSymbolNew(" + str + ") " + stringIndex);
319         return stringIndex;
320     }
321     private void hashSymbol(int[] bucket, int hashcode, int chunk, int index) {
322         if (bucket == null) {
323             bucket = new int[1 + (INITIAL_BUCKET_SIZE * 3)];
324             bucket[0] = 1;
325             bucket[1] = hashcode;
326             bucket[2] = chunk;
327             bucket[3] = index;
328             int hc = hashcode % HASHTABLE_SIZE;
329             fSymbolTable[hc] = bucket;
330         } else {
331             int count = bucket[0];
332             int offset = 1 + (count * 3);
333             if (offset == bucket.length) {
334                 int newSize = count + INITIAL_BUCKET_SIZE;
335                 int[] newBucket = new int[1 + (newSize * 3)];
336                 System.arraycopy(bucket, 0, newBucket, 0, offset);
337                 bucket = newBucket;
338                 int hc = hashcode % HASHTABLE_SIZE;
339                 fSymbolTable[hc] = bucket;
340             }
341             bucket[offset++] = hashcode;
342             bucket[offset++] = chunk;
343             bucket[offset++] = index;
344             bucket[0] = ++count;
345         }
346     }
347     public int addSymbol(String JavaDoc str) {
348         int slen = str.length();
349         int hashcode = StringHasher.hashString(str, slen);
350         int hc = hashcode % HASHTABLE_SIZE;
351         int[] bucket = fSymbolTable[hc];
352         if (bucket != null) {
353             int j = 1;
354             for (int i = 0; i < bucket[0]; i++) {
355                 if (bucket[j] == hashcode) {
356                     int chunk = bucket[j+1];
357                     int index = bucket[j+2];
358                     if (slen == fLength[chunk][index]) {
359                         int symoff = fCharsOffset[chunk][index];
360                         boolean match = true;
361                         char[] symbolChars = fSymbolCache.getSymbolChars();
362                         for (int k = 0; k < slen; k++) {
363                             if (symbolChars[symoff++] != str.charAt(k)) {
364                                 match = false;
365                                 break;
366                             }
367                         }
368                         if (match) {
369                             return (chunk << CHUNK_SHIFT) + index;
370                         }
371                     }
372                 }
373                 j += 3;
374             }
375         }
376         int chunk;
377         int index;
378         int stringIndex;
379         if (fStringFreeList != -1) {
380             stringIndex = fStringFreeList;
381             chunk = stringIndex >> CHUNK_SHIFT;
382             index = stringIndex & CHUNK_MASK;
383             fStringFreeList = fOffset[chunk][index];
384         } else {
385             stringIndex = fStringCount++;
386             chunk = stringIndex >> CHUNK_SHIFT;
387             index = stringIndex & CHUNK_MASK;
388             ensureCapacity(chunk, index);
389         }
390         fString[chunk][index] = str;
391         fStringProducer[chunk][index] = null;
392         fOffset[chunk][index] = -1;
393         fLength[chunk][index] = slen;
394         fCharsOffset[chunk][index] = fSymbolCache.addSymbolToCache(str, slen, stringIndex);
395
396         hashSymbol(bucket, hashcode, chunk, index);
397         if (DEBUG_ADDITIONS)
398             System.err.println("addSymbolNew(" + str + ") " + stringIndex);
399         return stringIndex;
400     }
401     public int addSymbol(StringPool.StringProducer stringProducer, int offset, int length, int hashcode) {
402         int hc = hashcode % HASHTABLE_SIZE;
403         int[] bucket = fSymbolTable[hc];
404         if (bucket != null) {
405             int j = 1;
406             for (int i = 0; i < bucket[0]; i++) {
407                 if (bucket[j] == hashcode) {
408                     int chunk = bucket[j+1];
409                     int index = bucket[j+2];
410                     char[] symbolChars = fSymbolCache.getSymbolChars();
411                     if (stringProducer.equalsString(offset, length, symbolChars, fCharsOffset[chunk][index], fLength[chunk][index])) {
412                         stringProducer.releaseString(offset, length);
413                         return (chunk << CHUNK_SHIFT) + index;
414                     }
415                 }
416                 j += 3;
417             }
418         }
419         int chunk;
420         int index;
421         int stringIndex;
422         if (fStringFreeList != -1) {
423             stringIndex = fStringFreeList;
424             chunk = stringIndex >> CHUNK_SHIFT;
425             index = stringIndex & CHUNK_MASK;
426             fStringFreeList = fOffset[chunk][index];
427         } else {
428             stringIndex = fStringCount++;
429             chunk = stringIndex >> CHUNK_SHIFT;
430             index = stringIndex & CHUNK_MASK;
431             ensureCapacity(chunk, index);
432         }
433         String JavaDoc str = stringProducer.toString(offset, length);
434         stringProducer.releaseString(offset, length);
435         int slen = str.length();
436         fString[chunk][index] = str;
437         fStringProducer[chunk][index] = null;
438         fOffset[chunk][index] = -1;
439         fLength[chunk][index] = slen;
440         fCharsOffset[chunk][index] = fSymbolCache.addSymbolToCache(str, slen, stringIndex);
441
442         hashSymbol(bucket, hashcode, chunk, index);
443         if (DEBUG_ADDITIONS)
444             System.err.println("addSymbol(" + str + ") " + stringIndex);
445         return stringIndex;
446     }
447     public int lookupSymbol(StringPool.StringProducer stringProducer, int offset, int length, int hashcode) {
448         int hc = hashcode % HASHTABLE_SIZE;
449         int[] bucket = fSymbolTable[hc];
450         if (bucket != null) {
451             int j = 1;
452             for (int i = 0; i < bucket[0]; i++) {
453                 if (bucket[j] == hashcode) {
454                     int chunk = bucket[j+1];
455                     int index = bucket[j+2];
456                     char[] symbolChars = fSymbolCache.getSymbolChars();
457                     if (stringProducer.equalsString(offset, length, symbolChars, fCharsOffset[chunk][index], fLength[chunk][index])) {
458                         return (chunk << CHUNK_SHIFT) + index;
459                     }
460                 }
461                 j += 3;
462             }
463         }
464         return -1;
465     }
466     public int addNewSymbol(String JavaDoc str, int hashcode) {
467         int hc = hashcode % HASHTABLE_SIZE;
468         int[] bucket = fSymbolTable[hc];
469         int chunk;
470         int index;
471         int stringIndex;
472         if (fStringFreeList != -1) {
473             stringIndex = fStringFreeList;
474             chunk = stringIndex >> CHUNK_SHIFT;
475             index = stringIndex & CHUNK_MASK;
476             fStringFreeList = fOffset[chunk][index];
477         } else {
478             stringIndex = fStringCount++;
479             chunk = stringIndex >> CHUNK_SHIFT;
480             index = stringIndex & CHUNK_MASK;
481             ensureCapacity(chunk, index);
482         }
483         int slen = str.length();
484         fString[chunk][index] = str;
485         fStringProducer[chunk][index] = null;
486         fOffset[chunk][index] = -1;
487         fLength[chunk][index] = slen;
488         fCharsOffset[chunk][index] = fSymbolCache.addSymbolToCache(str, slen, stringIndex);
489
490         hashSymbol(bucket, hashcode, chunk, index);
491         if (DEBUG_ADDITIONS)
492             System.err.println("addSymbolNew(" + str + ") " + stringIndex);
493         return stringIndex;
494     }
495     public int addSymbol(int stringIndex) {
496         if (stringIndex < 0 || stringIndex >= fStringCount)
497             return -1;
498         int chunk = stringIndex >> CHUNK_SHIFT;
499         int index = stringIndex & CHUNK_MASK;
500         if (fOffset[chunk][index] == -1)
501             return stringIndex;
502         String JavaDoc s = fString[chunk][index];
503         if (s == null) {
504             s = fStringProducer[chunk][index].toString(fOffset[chunk][index], fLength[chunk][index]);
505             fStringProducer[chunk][index].releaseString(fOffset[chunk][index], fLength[chunk][index]);
506             fString[chunk][index] = s;
507             fStringProducer[chunk][index] = null;
508         }
509         return addSymbol(s);
510     }
511     //
512
// Get characters for defined symbols
513
//
514
public class CharArrayRange {
515         public char[] chars;
516         public int offset;
517         public int length;
518     }
519     public CharArrayRange createCharArrayRange() {
520         return new CharArrayRange();
521     }
522     public void getCharArrayRange(int symbolIndex, CharArrayRange r) {
523         if (symbolIndex < 0 || symbolIndex >= fStringCount) {
524             r.chars = null;
525             r.offset = -1;
526             r.length = -1;
527             return;
528         }
529         int chunk = symbolIndex >> CHUNK_SHIFT;
530         int index = symbolIndex & CHUNK_MASK;
531         r.chars = fSymbolCache.getSymbolChars();
532         r.offset = fCharsOffset[chunk][index];
533         r.length = fLength[chunk][index];
534     }
535     public boolean equalNames(int stringIndex1, int stringIndex2) {
536         if (stringIndex1 == stringIndex2)
537             return true;
538         return false;
539     }
540     //
541
// String list support
542
//
543
private boolean ensureListCapacity(int chunk, int index) {
544         try {
545             return fStringList[chunk][index] == 0;
546         } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
547             if (index == 0) {
548                 int[][] newInt = new int[chunk * 2][];
549                 System.arraycopy(fStringList, 0, newInt, 0, chunk);
550                 fStringList = newInt;
551             } else {
552                 int[] newInt = new int[index * 2];
553                 System.arraycopy(fStringList[chunk], 0, newInt, 0, index);
554                 fStringList[chunk] = newInt;
555                 return true;
556             }
557         } catch (NullPointerException JavaDoc ex) {
558         }
559         fStringList[chunk] = new int[INITIAL_CHUNK_SIZE];
560         return true;
561     }
562     public int startStringList() {
563         fActiveStringList = fStringListCount;
564         return fStringListCount;
565     }
566     public boolean addStringToList(int stringListIndex, int stringIndex) {
567         if (stringIndex == -1 || stringListIndex != fActiveStringList)
568             return false;
569         int chunk = fStringListCount >> CHUNK_SHIFT;
570         int index = fStringListCount & CHUNK_MASK;
571         ensureListCapacity(chunk, index);
572         fStringList[chunk][index] = stringIndex;
573         fStringListCount++;
574         return true;
575     }
576     public void finishStringList(int stringListIndex) {
577         if (stringListIndex != fActiveStringList)
578             return;
579         int chunk = fStringListCount >> CHUNK_SHIFT;
580         int index = fStringListCount & CHUNK_MASK;
581         ensureListCapacity(chunk, index);
582         fStringList[chunk][index] = -1;
583         fActiveStringList = -1;
584         fStringListCount++;
585     }
586     public int stringListLength(int stringListIndex) {
587         int chunk = stringListIndex >> CHUNK_SHIFT;
588         int index = stringListIndex & CHUNK_MASK;
589         int count = 0;
590         while (true) {
591             if (fStringList[chunk][index] == -1)
592                 return count;
593             count++;
594             if (++index == CHUNK_SIZE) {
595                 chunk++;
596                 index = 0;
597             }
598         }
599     }
600     public boolean stringInList(int stringListIndex, int stringIndex) {
601         int chunk = stringListIndex >> CHUNK_SHIFT;
602         int index = stringListIndex & CHUNK_MASK;
603         while (true) {
604             if (fStringList[chunk][index] == stringIndex)
605                 return true;
606             if (fStringList[chunk][index] == -1)
607                 return false;
608             if (++index == CHUNK_SIZE) {
609                 chunk++;
610                 index = 0;
611             }
612         }
613     }
614     public String JavaDoc stringListAsString(int stringListIndex) {
615         int chunk = stringListIndex >> CHUNK_SHIFT;
616         int index = stringListIndex & CHUNK_MASK;
617         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
618         char sep = '(';
619         while (fStringList[chunk][index] != -1) {
620             sb.append(sep);
621             sep = '|';
622             sb.append(toString(fStringList[chunk][index]));
623             if (++index == CHUNK_SIZE) {
624                 chunk++;
625                 index = 0;
626             }
627         }
628         if (sep == '|')
629             sb.append(')');
630         return sb.toString();
631     }
632     public int[] stringListAsIntArray(int stringListIndex) {
633         int chunk = stringListIndex >> CHUNK_SHIFT;
634         int index = stringListIndex & CHUNK_MASK;
635         int len = stringListLength(stringListIndex);
636
637         int[] ia = new int[len];
638         for (int i=0; i<len; i++) {
639             ia[i] = fStringList[chunk][index];
640             if (++index == CHUNK_SIZE) {
641                 chunk++;
642                 index = 0;
643             }
644         }
645         return ia;
646     }
647     //
648
//
649
//
650
private void releaseStringInternal(int chunk, int index) {
651         fString[chunk][index] = null;
652         fStringProducer[chunk][index] = null;
653         fLength[chunk][index] = 0;
654         //
655
// REVISIT - not synchronized.
656
//
657
fOffset[chunk][index] = fStringFreeList;
658         int offset = (chunk << CHUNK_SHIFT) + index;
659         fStringFreeList = offset;
660     }
661     //
662
//
663
//
664
public void releaseString(int stringIndex) {
665         if (stringIndex < 0 || stringIndex >= fStringCount)
666             return;
667         int chunk = stringIndex >> CHUNK_SHIFT;
668         int index = stringIndex & CHUNK_MASK;
669         if (fOffset[chunk][index] != -1) {
670             if (fStringProducer[chunk][index] != null)
671                 fStringProducer[chunk][index].releaseString(fOffset[chunk][index], fLength[chunk][index]);
672             releaseStringInternal(chunk, index);
673         }
674     }
675     //
676
// Get String value. Cache the result.
677
//
678
public String JavaDoc toString(int stringIndex) {
679         if (stringIndex >= 0 && stringIndex < fString[0].length) {
680             String JavaDoc result = fString[0][stringIndex];
681             if (result != null) {
682                 return result;
683             }
684         }
685
686         if (stringIndex < 0 || stringIndex >= fStringCount)
687             return null;
688         int chunk = stringIndex >> CHUNK_SHIFT;
689         int index = stringIndex & CHUNK_MASK;
690         String JavaDoc s = fString[chunk][index];
691         if (s != null)
692             return s;
693         s = fStringProducer[chunk][index].toString(fOffset[chunk][index], fLength[chunk][index]);
694         fStringProducer[chunk][index].releaseString(fOffset[chunk][index], fLength[chunk][index]);
695         fString[chunk][index] = s;
696         fStringProducer[chunk][index] = null;
697         return s;
698     }
699     //
700
//
701
//
702
public String JavaDoc orphanString(int stringIndex) {
703         if (stringIndex < 0 || stringIndex >= fStringCount)
704             return null;
705         int chunk = stringIndex >> CHUNK_SHIFT;
706         int index = stringIndex & CHUNK_MASK;
707         String JavaDoc s = fString[chunk][index];
708         if (s == null) {
709             s = fStringProducer[chunk][index].toString(fOffset[chunk][index], fLength[chunk][index]);
710             fStringProducer[chunk][index].releaseString(fOffset[chunk][index], fLength[chunk][index]);
711             releaseStringInternal(chunk, index);
712         } else if (fOffset[chunk][index] != -1) {
713             releaseStringInternal(chunk, index);
714         }
715         return s;
716     }
717 }
718
Popular Tags