1 57 58 package org.xquark.xpath.datamodel.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 boolean ensureCapacity(int chunk, int index) { 168 try { 169 return fOffset[chunk][index] == 0; 170 } catch (ArrayIndexOutOfBoundsException ex) { 171 if (index == 0) { 172 String [][] newString = new String [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 [] 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 true; 204 } 205 } catch (NullPointerException ex) { 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 true; 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) { 277 return; 279 } 280 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 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 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 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 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 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 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 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 private boolean ensureListCapacity(int chunk, int index) { 544 try { 545 return fStringList[chunk][index] == 0; 546 } catch (ArrayIndexOutOfBoundsException 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 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 stringListAsString(int stringListIndex) { 615 int chunk = stringListIndex >> CHUNK_SHIFT; 616 int index = stringListIndex & CHUNK_MASK; 617 StringBuffer sb = new StringBuffer (); 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 private void releaseStringInternal(int chunk, int index) { 651 fString[chunk][index] = null; 652 fStringProducer[chunk][index] = null; 653 fLength[chunk][index] = 0; 654 fOffset[chunk][index] = fStringFreeList; 658 int offset = (chunk << CHUNK_SHIFT) + index; 659 fStringFreeList = offset; 660 } 661 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 public String toString(int stringIndex) { 679 if (stringIndex >= 0 && stringIndex < fString[0].length) { 680 String 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 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 public String 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 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 |