001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 1999 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Xerces" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 1999, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057:
058: package org.apache.xerces.utils;
059:
060: /**
061: *
062: * @version
063: */
064: public final class StringPool {
065: //
066: // Debugging
067: //
068: private static final boolean DEBUG_ADDITIONS = false;
069: /**
070: * Constants
071: */
072: public static final int NULL_STRING = -1; // null
073: public static final int EMPTY_STRING = 0; // ""
074:
075: /**
076: *
077: */
078: public interface StringProducer {
079: /**
080: *
081: */
082: public String toString(int offset, int length);
083:
084: /**
085: *
086: */
087: public void releaseString(int offset, int length);
088:
089: /**
090: *
091: */
092: public boolean equalsString(int offset, int length,
093: char[] strChars, int strOffset, int strLength);
094: };
095:
096: //
097: // Chunk size constants
098: //
099: private static final int INITIAL_CHUNK_SHIFT = 8; // 2^8 = 256
100: private static final int INITIAL_CHUNK_SIZE = (1 << INITIAL_CHUNK_SHIFT);
101: private static final int CHUNK_SHIFT = 13; // 2^13 = 8k
102: private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
103: private static final int CHUNK_MASK = CHUNK_SIZE - 1;
104: private static final int INITIAL_CHUNK_COUNT = (1 << (16 - CHUNK_SHIFT)); // 2^16 = 64k
105: //
106: // Instance variables
107: //
108: //
109: // String and Symbol arrays
110: //
111: private int fStringCount = 0;
112: private int fStringFreeList = -1;
113: private String[][] fString = new String[INITIAL_CHUNK_COUNT][];
114: private StringPool.StringProducer[][] fStringProducer = new StringPool.StringProducer[INITIAL_CHUNK_COUNT][];
115: private int[][] fOffset = new int[INITIAL_CHUNK_COUNT][];
116: private int[][] fLength = new int[INITIAL_CHUNK_COUNT][];
117: private int[][] fCharsOffset = new int[INITIAL_CHUNK_COUNT][];
118: //
119: // String Lists
120: //
121: private int fStringListCount = 0;
122: private int fActiveStringList = -1;
123: private int[][] fStringList = new int[INITIAL_CHUNK_COUNT][];
124: //
125: // Symbol Hashtable
126: //
127: private static final int INITIAL_BUCKET_SIZE = 4;
128: private static final int HASHTABLE_SIZE = 128;
129: private int[][] fSymbolTable = new int[HASHTABLE_SIZE][];
130: //
131: // Symbol Cache
132: //
133: private SymbolCache fSymbolCache = null;
134:
135: //
136: //
137: //
138: public StringPool() {
139: fSymbolCache = new SymbolCache();
140: if (addSymbol("") != EMPTY_STRING)
141: throw new RuntimeException("UTL002 cannot happen");
142: }
143:
144: //
145: //
146: //
147: public void reset() {
148: int chunk = 0;
149: int index = 0;
150: for (int i = 0; i < fStringCount; i++) {
151: fString[chunk][index] = null;
152: if (fStringProducer[chunk][index] != null)
153: fStringProducer[chunk][index].releaseString(
154: fOffset[chunk][index], fLength[chunk][index]);
155: fStringProducer[chunk][index] = null;
156: if (++index == CHUNK_SIZE) {
157: chunk++;
158: index = 0;
159: }
160: }
161: for (int i = 0; i < HASHTABLE_SIZE; i++)
162: fSymbolTable[i] = null;
163: fStringCount = 0;
164: fStringFreeList = -1;
165: fStringListCount = 0;
166: fActiveStringList = -1;
167: fSymbolCache.reset();
168: fShuffleCount = 0;
169: if (addSymbol("") != EMPTY_STRING)
170: throw new RuntimeException("UTL002 cannot happen");
171: }
172:
173: //
174: // String interfaces
175: //
176: private void ensureCapacity(int chunk, int index) {
177:
178: if (chunk >= fOffset.length) {
179: String[][] newString = new String[chunk * 2][];
180: System.arraycopy(fString, 0, newString, 0, chunk);
181: fString = newString;
182: StringPool.StringProducer[][] newProducer = new StringPool.StringProducer[chunk * 2][];
183: System.arraycopy(fStringProducer, 0, newProducer, 0, chunk);
184: fStringProducer = newProducer;
185: int[][] newInt = new int[chunk * 2][];
186: System.arraycopy(fOffset, 0, newInt, 0, chunk);
187: fOffset = newInt;
188: newInt = new int[chunk * 2][];
189: System.arraycopy(fLength, 0, newInt, 0, chunk);
190: fLength = newInt;
191: newInt = new int[chunk * 2][];
192: System.arraycopy(fCharsOffset, 0, newInt, 0, chunk);
193: fCharsOffset = newInt;
194: } else if (fOffset[chunk] == null) {
195: } else if (index >= fOffset[chunk].length) {
196: String[] newString = new String[index * 2];
197: System.arraycopy(fString[chunk], 0, newString, 0, index);
198: fString[chunk] = newString;
199: StringPool.StringProducer[] newProducer = new StringPool.StringProducer[index * 2];
200: System.arraycopy(fStringProducer[chunk], 0, newProducer, 0,
201: index);
202: fStringProducer[chunk] = newProducer;
203: int[] newInt = new int[index * 2];
204: System.arraycopy(fOffset[chunk], 0, newInt, 0, index);
205: fOffset[chunk] = newInt;
206: newInt = new int[index * 2];
207: System.arraycopy(fLength[chunk], 0, newInt, 0, index);
208: fLength[chunk] = newInt;
209: newInt = new int[index * 2];
210: System.arraycopy(fCharsOffset[chunk], 0, newInt, 0, index);
211: fCharsOffset[chunk] = newInt;
212: return;
213: } else {
214: return;
215: }
216: fString[chunk] = new String[INITIAL_CHUNK_SIZE];
217: fStringProducer[chunk] = new StringPool.StringProducer[INITIAL_CHUNK_SIZE];
218: fOffset[chunk] = new int[INITIAL_CHUNK_SIZE];
219: fLength[chunk] = new int[INITIAL_CHUNK_SIZE];
220: fCharsOffset[chunk] = new int[INITIAL_CHUNK_SIZE];
221: return;
222: }
223:
224: public int addString(String str) {
225: int chunk;
226: int index;
227: int stringIndex;
228: if (fStringFreeList != -1) {
229: stringIndex = fStringFreeList;
230: chunk = stringIndex >> CHUNK_SHIFT;
231: index = stringIndex & CHUNK_MASK;
232: fStringFreeList = fOffset[chunk][index];
233: } else {
234: stringIndex = fStringCount++;
235: chunk = stringIndex >> CHUNK_SHIFT;
236: index = stringIndex & CHUNK_MASK;
237: ensureCapacity(chunk, index);
238: }
239: fString[chunk][index] = str;
240: fStringProducer[chunk][index] = null;
241: fOffset[chunk][index] = 0;
242: fLength[chunk][index] = str.length();
243: fCharsOffset[chunk][index] = -1;
244: if (DEBUG_ADDITIONS)
245: System.err.println("addString(" + str + ") " + stringIndex);
246: return stringIndex;
247: }
248:
249: public int addString(StringPool.StringProducer stringProducer,
250: int offset, int length) {
251: int chunk;
252: int index;
253: int stringIndex;
254: if (fStringFreeList != -1) {
255: stringIndex = fStringFreeList;
256: chunk = stringIndex >> CHUNK_SHIFT;
257: index = stringIndex & CHUNK_MASK;
258: fStringFreeList = fOffset[chunk][index];
259: } else {
260: stringIndex = fStringCount++;
261: chunk = stringIndex >> CHUNK_SHIFT;
262: index = stringIndex & CHUNK_MASK;
263: ensureCapacity(chunk, index);
264: }
265: fString[chunk][index] = null;
266: fStringProducer[chunk][index] = stringProducer;
267: fOffset[chunk][index] = offset;
268: fLength[chunk][index] = length;
269: fCharsOffset[chunk][index] = -1;
270: if (DEBUG_ADDITIONS)
271: System.err.println("addString("
272: + stringProducer.toString(offset, length) + ") "
273: + stringIndex);
274: return stringIndex;
275: }
276:
277: //
278: // Symbol interfaces
279: //
280: public SymbolCache getSymbolCache() {
281: return fSymbolCache;
282: }
283:
284: //private static int fShuffleCount = 0;
285: private int fShuffleCount = 0;
286:
287: public void resetShuffleCount() {
288: fShuffleCount = 0;
289: }
290:
291: public void updateCacheLine(int symbolIndex, int totalMisses,
292: int length) {
293: if (++fShuffleCount > 200) {
294: // if (fShuffleCount == 201) System.out.println("Stopped shuffling...");
295: return;
296: }
297: // if ((fShuffleCount % 10) == 0) System.out.println("Shuffling pass " + fShuffleCount + " ...");
298: int chunk = symbolIndex >> CHUNK_SHIFT;
299: int index = symbolIndex & CHUNK_MASK;
300: int charsOffset = fCharsOffset[chunk][index];
301: fSymbolCache.updateCacheLine(charsOffset, totalMisses, length);
302: }
303:
304: public int createNonMatchingSymbol(int startOffset, int entry,
305: int[] entries, int offset) throws Exception {
306: int chunk;
307: int index;
308: int stringIndex;
309: if (fStringFreeList != -1) {
310: stringIndex = fStringFreeList;
311: chunk = stringIndex >> CHUNK_SHIFT;
312: index = stringIndex & CHUNK_MASK;
313: fStringFreeList = fOffset[chunk][index];
314: } else {
315: stringIndex = fStringCount++;
316: chunk = stringIndex >> CHUNK_SHIFT;
317: index = stringIndex & CHUNK_MASK;
318: ensureCapacity(chunk, index);
319: }
320: String str = fSymbolCache.createSymbol(stringIndex,
321: startOffset, entry, entries, offset);
322: int slen = str.length();
323: fString[chunk][index] = str;
324: fStringProducer[chunk][index] = null;
325: fOffset[chunk][index] = -1;
326: fLength[chunk][index] = slen;
327: fCharsOffset[chunk][index] = startOffset;
328:
329: int hashcode = StringHasher.hashString(str, slen);
330: int hc = hashcode % HASHTABLE_SIZE;
331: int[] bucket = fSymbolTable[hc];
332: hashSymbol(bucket, hashcode, chunk, index);
333: if (DEBUG_ADDITIONS)
334: System.err.println("addSymbolNew(" + str + ") "
335: + stringIndex);
336: return stringIndex;
337: }
338:
339: private void hashSymbol(int[] bucket, int hashcode, int chunk,
340: int index) {
341: if (bucket == null) {
342: bucket = new int[1 + (INITIAL_BUCKET_SIZE * 3)];
343: bucket[0] = 1;
344: bucket[1] = hashcode;
345: bucket[2] = chunk;
346: bucket[3] = index;
347: int hc = hashcode % HASHTABLE_SIZE;
348: fSymbolTable[hc] = bucket;
349: } else {
350: int count = bucket[0];
351: int offset = 1 + (count * 3);
352: if (offset == bucket.length) {
353: int newSize = count + INITIAL_BUCKET_SIZE;
354: int[] newBucket = new int[1 + (newSize * 3)];
355: System.arraycopy(bucket, 0, newBucket, 0, offset);
356: bucket = newBucket;
357: int hc = hashcode % HASHTABLE_SIZE;
358: fSymbolTable[hc] = bucket;
359: }
360: bucket[offset++] = hashcode;
361: bucket[offset++] = chunk;
362: bucket[offset++] = index;
363: bucket[0] = ++count;
364: }
365: }
366:
367: public int addSymbol(String str) {
368: int slen = str.length();
369: int hashcode = StringHasher.hashString(str, slen);
370: int hc = hashcode % HASHTABLE_SIZE;
371: int[] bucket = fSymbolTable[hc];
372: if (bucket != null) {
373: int j = 1;
374: for (int i = 0; i < bucket[0]; i++) {
375: if (bucket[j] == hashcode) {
376: int chunk = bucket[j + 1];
377: int index = bucket[j + 2];
378: if (slen == fLength[chunk][index]) {
379: int symoff = fCharsOffset[chunk][index];
380: boolean match = true;
381: char[] symbolChars = fSymbolCache
382: .getSymbolChars();
383: for (int k = 0; k < slen; k++) {
384: if (symbolChars[symoff++] != str.charAt(k)) {
385: match = false;
386: break;
387: }
388: }
389: if (match) {
390: return (chunk << CHUNK_SHIFT) + index;
391: }
392: }
393: }
394: j += 3;
395: }
396: }
397: int chunk;
398: int index;
399: int stringIndex;
400: if (fStringFreeList != -1) {
401: stringIndex = fStringFreeList;
402: chunk = stringIndex >> CHUNK_SHIFT;
403: index = stringIndex & CHUNK_MASK;
404: fStringFreeList = fOffset[chunk][index];
405: } else {
406: stringIndex = fStringCount++;
407: chunk = stringIndex >> CHUNK_SHIFT;
408: index = stringIndex & CHUNK_MASK;
409: ensureCapacity(chunk, index);
410: }
411: fString[chunk][index] = str;
412: fStringProducer[chunk][index] = null;
413: fOffset[chunk][index] = -1;
414: fLength[chunk][index] = slen;
415: fCharsOffset[chunk][index] = fSymbolCache.addSymbolToCache(str,
416: slen, stringIndex);
417:
418: hashSymbol(bucket, hashcode, chunk, index);
419: if (DEBUG_ADDITIONS)
420: System.err.println("addSymbolNew(" + str + ") "
421: + stringIndex);
422: return stringIndex;
423: }
424:
425: public int addSymbol(StringPool.StringProducer stringProducer,
426: int offset, int length, int hashcode) {
427: int hc = hashcode % HASHTABLE_SIZE;
428: int[] bucket = fSymbolTable[hc];
429: if (bucket != null) {
430: int j = 1;
431: for (int i = 0; i < bucket[0]; i++) {
432: if (bucket[j] == hashcode) {
433: int chunk = bucket[j + 1];
434: int index = bucket[j + 2];
435: char[] symbolChars = fSymbolCache.getSymbolChars();
436: if (stringProducer.equalsString(offset, length,
437: symbolChars, fCharsOffset[chunk][index],
438: fLength[chunk][index])) {
439: stringProducer.releaseString(offset, length);
440: return (chunk << CHUNK_SHIFT) + index;
441: }
442: }
443: j += 3;
444: }
445: }
446: int chunk;
447: int index;
448: int stringIndex;
449: if (fStringFreeList != -1) {
450: stringIndex = fStringFreeList;
451: chunk = stringIndex >> CHUNK_SHIFT;
452: index = stringIndex & CHUNK_MASK;
453: fStringFreeList = fOffset[chunk][index];
454: } else {
455: stringIndex = fStringCount++;
456: chunk = stringIndex >> CHUNK_SHIFT;
457: index = stringIndex & CHUNK_MASK;
458: ensureCapacity(chunk, index);
459: }
460: String str = stringProducer.toString(offset, length);
461: stringProducer.releaseString(offset, length);
462: int slen = str.length();
463: fString[chunk][index] = str;
464: fStringProducer[chunk][index] = null;
465: fOffset[chunk][index] = -1;
466: fLength[chunk][index] = slen;
467: fCharsOffset[chunk][index] = fSymbolCache.addSymbolToCache(str,
468: slen, stringIndex);
469:
470: hashSymbol(bucket, hashcode, chunk, index);
471: if (DEBUG_ADDITIONS)
472: System.err.println("addSymbol(" + str + ") " + stringIndex);
473: return stringIndex;
474: }
475:
476: public int lookupSymbol(StringPool.StringProducer stringProducer,
477: int offset, int length, int hashcode) {
478: int hc = hashcode % HASHTABLE_SIZE;
479: int[] bucket = fSymbolTable[hc];
480: if (bucket != null) {
481: int j = 1;
482: for (int i = 0; i < bucket[0]; i++) {
483: if (bucket[j] == hashcode) {
484: int chunk = bucket[j + 1];
485: int index = bucket[j + 2];
486: char[] symbolChars = fSymbolCache.getSymbolChars();
487: if (stringProducer.equalsString(offset, length,
488: symbolChars, fCharsOffset[chunk][index],
489: fLength[chunk][index])) {
490: return (chunk << CHUNK_SHIFT) + index;
491: }
492: }
493: j += 3;
494: }
495: }
496: return -1;
497: }
498:
499: public int addNewSymbol(String str, int hashcode) {
500: int hc = hashcode % HASHTABLE_SIZE;
501: int[] bucket = fSymbolTable[hc];
502: int chunk;
503: int index;
504: int stringIndex;
505: if (fStringFreeList != -1) {
506: stringIndex = fStringFreeList;
507: chunk = stringIndex >> CHUNK_SHIFT;
508: index = stringIndex & CHUNK_MASK;
509: fStringFreeList = fOffset[chunk][index];
510: } else {
511: stringIndex = fStringCount++;
512: chunk = stringIndex >> CHUNK_SHIFT;
513: index = stringIndex & CHUNK_MASK;
514: ensureCapacity(chunk, index);
515: }
516: int slen = str.length();
517: fString[chunk][index] = str;
518: fStringProducer[chunk][index] = null;
519: fOffset[chunk][index] = -1;
520: fLength[chunk][index] = slen;
521: fCharsOffset[chunk][index] = fSymbolCache.addSymbolToCache(str,
522: slen, stringIndex);
523:
524: hashSymbol(bucket, hashcode, chunk, index);
525: if (DEBUG_ADDITIONS)
526: System.err.println("addSymbolNew(" + str + ") "
527: + stringIndex);
528: return stringIndex;
529: }
530:
531: public int addSymbol(int stringIndex) {
532: if (stringIndex < 0 || stringIndex >= fStringCount)
533: return -1;
534: int chunk = stringIndex >> CHUNK_SHIFT;
535: int index = stringIndex & CHUNK_MASK;
536: if (fOffset[chunk][index] == -1)
537: return stringIndex;
538: String s = fString[chunk][index];
539: if (s == null) {
540: s = fStringProducer[chunk][index].toString(
541: fOffset[chunk][index], fLength[chunk][index]);
542: fStringProducer[chunk][index].releaseString(
543: fOffset[chunk][index], fLength[chunk][index]);
544: fString[chunk][index] = s;
545: fStringProducer[chunk][index] = null;
546: }
547: return addSymbol(s);
548: }
549:
550: //
551: // Get characters for defined symbols
552: //
553: public class CharArrayRange {
554: public char[] chars;
555: public int offset;
556: public int length;
557: }
558:
559: public CharArrayRange createCharArrayRange() {
560: return new CharArrayRange();
561: }
562:
563: public void getCharArrayRange(int symbolIndex, CharArrayRange r) {
564: if (symbolIndex < 0 || symbolIndex >= fStringCount) {
565: r.chars = null;
566: r.offset = -1;
567: r.length = -1;
568: return;
569: }
570: int chunk = symbolIndex >> CHUNK_SHIFT;
571: int index = symbolIndex & CHUNK_MASK;
572: r.chars = fSymbolCache.getSymbolChars();
573: r.offset = fCharsOffset[chunk][index];
574: r.length = fLength[chunk][index];
575: }
576:
577: public boolean equalNames(int stringIndex1, int stringIndex2) {
578: if (stringIndex1 == stringIndex2)
579: return true;
580: return false;
581: }
582:
583: //
584: // String list support
585: //
586: private void ensureListCapacity(int chunk, int index) {
587: if (chunk >= fStringList.length) {
588: int[][] newInt = new int[chunk * 2][];
589: System.arraycopy(fStringList, 0, newInt, 0, chunk);
590: fStringList = newInt;
591: fStringList[chunk] = new int[INITIAL_CHUNK_SIZE];
592: } else if (fStringList[chunk] == null) {
593: fStringList[chunk] = new int[INITIAL_CHUNK_SIZE];
594: } else if (index >= fStringList[chunk].length) {
595: int[] newInt = new int[index * 2];
596: System.arraycopy(fStringList[chunk], 0, newInt, 0, index);
597: fStringList[chunk] = newInt;
598: }
599: }
600:
601: public int startStringList() {
602: fActiveStringList = fStringListCount;
603: return fStringListCount;
604: }
605:
606: public boolean addStringToList(int stringListIndex, int stringIndex) {
607: if (stringIndex == -1 || stringListIndex != fActiveStringList)
608: return false;
609: int chunk = fStringListCount >> CHUNK_SHIFT;
610: int index = fStringListCount & CHUNK_MASK;
611: ensureListCapacity(chunk, index);
612: fStringList[chunk][index] = stringIndex;
613: fStringListCount++;
614: return true;
615: }
616:
617: public void finishStringList(int stringListIndex) {
618: if (stringListIndex != fActiveStringList)
619: return;
620: int chunk = fStringListCount >> CHUNK_SHIFT;
621: int index = fStringListCount & CHUNK_MASK;
622: ensureListCapacity(chunk, index);
623: fStringList[chunk][index] = -1;
624: fActiveStringList = -1;
625: fStringListCount++;
626: }
627:
628: public int stringListLength(int stringListIndex) {
629: int chunk = stringListIndex >> CHUNK_SHIFT;
630: int index = stringListIndex & CHUNK_MASK;
631: int count = 0;
632: while (true) {
633: if (fStringList[chunk][index] == -1)
634: return count;
635: count++;
636: if (++index == CHUNK_SIZE) {
637: chunk++;
638: index = 0;
639: }
640: }
641: }
642:
643: public boolean stringInList(int stringListIndex, int stringIndex) {
644: int chunk = stringListIndex >> CHUNK_SHIFT;
645: int index = stringListIndex & CHUNK_MASK;
646: while (true) {
647: if (fStringList[chunk][index] == stringIndex)
648: return true;
649: if (fStringList[chunk][index] == -1)
650: return false;
651: if (++index == CHUNK_SIZE) {
652: chunk++;
653: index = 0;
654: }
655: }
656: }
657:
658: public String stringListAsString(int stringListIndex) {
659: int chunk = stringListIndex >> CHUNK_SHIFT;
660: int index = stringListIndex & CHUNK_MASK;
661: StringBuffer sb = new StringBuffer();
662: char sep = '(';
663: while (fStringList[chunk][index] != -1) {
664: sb.append(sep);
665: sep = '|';
666: sb.append(toString(fStringList[chunk][index]));
667: if (++index == CHUNK_SIZE) {
668: chunk++;
669: index = 0;
670: }
671: }
672: if (sep == '|')
673: sb.append(')');
674: return sb.toString();
675: }
676:
677: public int[] stringListAsIntArray(int stringListIndex) {
678: int chunk = stringListIndex >> CHUNK_SHIFT;
679: int index = stringListIndex & CHUNK_MASK;
680: int len = stringListLength(stringListIndex);
681:
682: int[] ia = new int[len];
683: for (int i = 0; i < len; i++) {
684: ia[i] = fStringList[chunk][index];
685: if (++index == CHUNK_SIZE) {
686: chunk++;
687: index = 0;
688: }
689: }
690: return ia;
691: }
692:
693: //
694: //
695: //
696: private void releaseStringInternal(int chunk, int index) {
697: fString[chunk][index] = null;
698: fStringProducer[chunk][index] = null;
699: fLength[chunk][index] = 0;
700: //
701: // REVISIT - not synchronized.
702: //
703: fOffset[chunk][index] = fStringFreeList;
704: int offset = (chunk << CHUNK_SHIFT) + index;
705: fStringFreeList = offset;
706: }
707:
708: //
709: //
710: //
711: public void releaseString(int stringIndex) {
712: if (stringIndex < 0 || stringIndex >= fStringCount)
713: return;
714: int chunk = stringIndex >> CHUNK_SHIFT;
715: int index = stringIndex & CHUNK_MASK;
716: if (fOffset[chunk][index] != -1) {
717: if (fStringProducer[chunk][index] != null)
718: fStringProducer[chunk][index].releaseString(
719: fOffset[chunk][index], fLength[chunk][index]);
720: releaseStringInternal(chunk, index);
721: }
722: }
723:
724: //
725: // Get String value. Cache the result.
726: //
727: public String toString(int stringIndex) {
728: if (stringIndex >= 0 && stringIndex < fString[0].length) {
729: String result = fString[0][stringIndex];
730: if (result != null) {
731: return result;
732: }
733: }
734:
735: if (stringIndex < 0 || stringIndex >= fStringCount)
736: return null;
737: int chunk = stringIndex >> CHUNK_SHIFT;
738: int index = stringIndex & CHUNK_MASK;
739: String s = fString[chunk][index];
740: if (s != null)
741: return s;
742: s = fStringProducer[chunk][index].toString(
743: fOffset[chunk][index], fLength[chunk][index]);
744: fStringProducer[chunk][index].releaseString(
745: fOffset[chunk][index], fLength[chunk][index]);
746: fString[chunk][index] = s;
747: fStringProducer[chunk][index] = null;
748: return s;
749: }
750:
751: //
752: //
753: //
754: public String orphanString(int stringIndex) {
755: if (stringIndex < 0 || stringIndex >= fStringCount)
756: return null;
757: int chunk = stringIndex >> CHUNK_SHIFT;
758: int index = stringIndex & CHUNK_MASK;
759: String s = fString[chunk][index];
760: if (s == null) {
761: s = fStringProducer[chunk][index].toString(
762: fOffset[chunk][index], fLength[chunk][index]);
763: fStringProducer[chunk][index].releaseString(
764: fOffset[chunk][index], fLength[chunk][index]);
765: releaseStringInternal(chunk, index);
766: } else if (fOffset[chunk][index] != -1) {
767: releaseStringInternal(chunk, index);
768: }
769: return s;
770: }
771: }
|