1 57 58 package org.enhydra.apache.xerces.utils; 59 60 64 public final class StringPool { 65 private static final boolean DEBUG_ADDITIONS = false; 69 72 public static final int NULL_STRING = -1; public static final int EMPTY_STRING = 0; 77 public interface StringProducer { 78 81 public String toString(int offset, int length); 82 85 public void releaseString(int offset, int length); 86 89 public boolean equalsString(int offset, int length, char[] strChars, int strOffset, int strLength); 90 }; 91 private static final int INITIAL_CHUNK_SHIFT = 8; private static final int INITIAL_CHUNK_SIZE = (1 << INITIAL_CHUNK_SHIFT); 96 private static final int CHUNK_SHIFT = 13; 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)); private int fStringCount = 0; 107 private int fStringFreeList = -1; 108 private String [][] fString = new String [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 private int fStringListCount = 0; 117 private int fActiveStringList = -1; 118 private int[][] fStringList = new int[INITIAL_CHUNK_COUNT][]; 119 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 private SymbolCache fSymbolCache = null; 129 public StringPool() { 133 fSymbolCache = new SymbolCache(); 134 if (addSymbol("") != EMPTY_STRING) 135 throw new RuntimeException ("UTL002 cannot happen"); 136 } 137 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 ("UTL002 cannot happen"); 163 } 164 private void ensureCapacity(int chunk, int index) { 168 169 if (chunk >= fOffset.length) { 170 String [][] newString = new String [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 [] newString = new String [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 [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 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 public SymbolCache getSymbolCache() { 267 return fSymbolCache; 268 } 269 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 return; 278 } 279 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 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 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 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 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 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 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 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 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 stringListAsString(int stringListIndex) { 609 int chunk = stringListIndex >> CHUNK_SHIFT; 610 int index = stringListIndex & CHUNK_MASK; 611 StringBuffer sb = new StringBuffer (); 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 private void releaseStringInternal(int chunk, int index) { 645 fString[chunk][index] = null; 646 fStringProducer[chunk][index] = null; 647 fLength[chunk][index] = 0; 648 fOffset[chunk][index] = fStringFreeList; 652 int offset = (chunk << CHUNK_SHIFT) + index; 653 fStringFreeList = offset; 654 } 655 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 public String toString(int stringIndex) { 673 if (stringIndex >= 0 && stringIndex < fString[0].length) { 674 String 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 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 public String 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 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 |