1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import java.util.Arrays; 29 import java.util.Locale; 30 import java.util.Spliterator; 31 import java.util.function.IntConsumer; 32 import jdk.internal.HotSpotIntrinsicCandidate; 33 34 import static java.lang.String.UTF16; 35 import static java.lang.String.LATIN1; 36 import static java.lang.String.checkIndex; 37 import static java.lang.String.checkOffset; 38 import static java.lang.String.checkBoundsOffCount; 39 40 final class StringUTF16 { 41 42 public static byte[] newBytesFor(int len) { 43 if (len < 0) { 44 throw new NegativeArraySizeException(); 45 } 46 if (len > MAX_LENGTH) { 47 throw new OutOfMemoryError("UTF16 String size is " + len + 48 ", should be less than " + MAX_LENGTH); 49 } 50 return new byte[len << 1]; 51 } 52 53 @HotSpotIntrinsicCandidate 54 public static void putChar(byte[] val, int index, int c) { 55 index <<= 1; 56 val[index++] = (byte)(c >> HI_BYTE_SHIFT); 57 val[index] = (byte)(c >> LO_BYTE_SHIFT); 58 } 59 60 @HotSpotIntrinsicCandidate 61 public static char getChar(byte[] val, int index) { 62 index <<= 1; 63 return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) | 64 ((val[index] & 0xff) << LO_BYTE_SHIFT)); 65 } 66 67 public static char charAt(byte[] value, int index) { 68 if (index < 0 || index >= value.length >> 1) { 69 throw new StringIndexOutOfBoundsException(index); 70 } 71 return getChar(value, index); 72 } 73 74 public static int length(byte[] value) { 75 return value.length >> 1; 76 } 77 78 public static int codePointAt(byte[] value, int index, int end) { 79 char c1 = getChar(value, index); 80 if (Character.isHighSurrogate(c1) && ++index < end) { 81 char c2 = getChar(value, index); 82 if (Character.isLowSurrogate(c2)) { 83 return Character.toCodePoint(c1, c2); 84 } 85 } 86 return c1; 87 } 88 89 public static int codePointBefore(byte[] value, int index) { 90 char c2 = getChar(value, --index); 91 if (Character.isLowSurrogate(c2) && index > 0) { 92 char c1 = getChar(value, --index); 93 if (Character.isHighSurrogate(c1)) { 94 return Character.toCodePoint(c1, c2); 95 } 96 } 97 return c2; 98 } 99 100 public static int codePointCount(byte[] value, int beginIndex, int endIndex) { 101 int count = endIndex - beginIndex; 102 for (int i = beginIndex; i < endIndex; ) { 103 if (Character.isHighSurrogate(getChar(value, i++)) && 104 i < endIndex && 105 Character.isLowSurrogate(getChar(value, i))) { 106 count--; 107 i++; 108 } 109 } 110 return count; 111 } 112 113 public static char[] toChars(byte[] value) { 114 char[] dst = new char[value.length >> 1]; 115 getChars(value, 0, dst.length, dst, 0); 116 return dst; 117 } 118 119 @HotSpotIntrinsicCandidate 120 public static byte[] toBytes(char[] value, int off, int len) { 121 byte[] val = newBytesFor(len); 122 for (int i = 0; i < len; i++) { 123 putChar(val, i, value[off]); 124 off++; 125 } 126 return val; 127 } 128 129 public static byte[] compress(char[] val, int off, int len) { 130 byte[] ret = new byte[len]; 131 if (compress(val, off, ret, 0, len) == len) { 132 return ret; 133 } 134 return null; 135 } 136 137 public static byte[] compress(byte[] val, int off, int len) { 138 byte[] ret = new byte[len]; 139 if (compress(val, off, ret, 0, len) == len) { 140 return ret; 141 } 142 return null; 143 } 144 145 // compressedCopy char[] -> byte[] 146 @HotSpotIntrinsicCandidate 147 private static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) { 148 for (int i = 0; i < len; i++) { 149 char c = src[srcOff]; 150 if (c > 0xFF) { 151 len = 0; 152 break; 153 } 154 dst[dstOff] = (byte)c; 155 srcOff++; 156 dstOff++; 157 } 158 return len; 159 } 160 161 // compressedCopy byte[] -> byte[] 162 @HotSpotIntrinsicCandidate 163 public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { 164 // We need a range check here because 'getChar' has no checks 165 checkBoundsOffCount(srcOff, len, src.length); 166 for (int i = 0; i < len; i++) { 167 char c = getChar(src, srcOff); 168 if (c > 0xFF) { 169 len = 0; 170 break; 171 } 172 dst[dstOff] = (byte)c; 173 srcOff++; 174 dstOff++; 175 } 176 return len; 177 } 178 179 public static byte[] toBytes(int[] val, int index, int len) { 180 final int end = index + len; 181 // Pass 1: Compute precise size of char[] 182 int n = len; 183 for (int i = index; i < end; i++) { 184 int cp = val[i]; 185 if (Character.isBmpCodePoint(cp)) 186 continue; 187 else if (Character.isValidCodePoint(cp)) 188 n++; 189 else throw new IllegalArgumentException(Integer.toString(cp)); 190 } 191 // Pass 2: Allocate and fill in <high, low> pair 192 byte[] buf = newBytesFor(n); 193 for (int i = index, j = 0; i < end; i++, j++) { 194 int cp = val[i]; 195 if (Character.isBmpCodePoint(cp)) { 196 putChar(buf, j, cp); 197 } else { 198 putChar(buf, j++, Character.highSurrogate(cp)); 199 putChar(buf, j, Character.lowSurrogate(cp)); 200 } 201 } 202 return buf; 203 } 204 205 public static byte[] toBytes(char c) { 206 byte[] result = new byte[2]; 207 putChar(result, 0, c); 208 return result; 209 } 210 211 @HotSpotIntrinsicCandidate 212 public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) { 213 // We need a range check here because 'getChar' has no checks 214 checkBoundsOffCount(srcBegin, srcEnd - srcBegin, value.length); 215 for (int i = srcBegin; i < srcEnd; i++) { 216 dst[dstBegin++] = getChar(value, i); 217 } 218 } 219 220 /* @see java.lang.String.getBytes(int, int, byte[], int) */ 221 public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) { 222 srcBegin <<= 1; 223 srcEnd <<= 1; 224 for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) { 225 dst[dstBegin++] = value[i]; 226 } 227 } 228 229 @HotSpotIntrinsicCandidate 230 public static boolean equals(byte[] value, byte[] other) { 231 if (value.length == other.length) { 232 int len = value.length >> 1; 233 for (int i = 0; i < len; i++) { 234 if (getChar(value, i) != getChar(other, i)) { 235 return false; 236 } 237 } 238 return true; 239 } 240 return false; 241 } 242 243 @HotSpotIntrinsicCandidate 244 public static int compareTo(byte[] value, byte[] other) { 245 int len1 = length(value); 246 int len2 = length(other); 247 int lim = Math.min(len1, len2); 248 for (int k = 0; k < lim; k++) { 249 char c1 = getChar(value, k); 250 char c2 = getChar(other, k); 251 if (c1 != c2) { 252 return c1 - c2; 253 } 254 } 255 return len1 - len2; 256 } 257 258 @HotSpotIntrinsicCandidate 259 public static int compareToLatin1(byte[] value, byte[] other) { 260 int len1 = length(value); 261 int len2 = StringLatin1.length(other); 262 int lim = Math.min(len1, len2); 263 for (int k = 0; k < lim; k++) { 264 char c1 = getChar(value, k); 265 char c2 = StringLatin1.getChar(other, k); 266 if (c1 != c2) { 267 return c1 - c2; 268 } 269 } 270 return len1 - len2; 271 } 272 273 public static int hashCode(byte[] value) { 274 int h = 0; 275 int length = value.length >> 1; 276 for (int i = 0; i < length; i++) { 277 h = 31 * h + getChar(value, i); 278 } 279 return h; 280 } 281 282 public static int indexOf(byte[] value, int ch, int fromIndex) { 283 int max = value.length >> 1; 284 if (fromIndex < 0) { 285 fromIndex = 0; 286 } else if (fromIndex >= max) { 287 // Note: fromIndex might be near -1>>>1. 288 return -1; 289 } 290 if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { 291 // handle most cases here (ch is a BMP code point or a 292 // negative value (invalid code point)) 293 return indexOfChar(value, ch, fromIndex, max); 294 } else { 295 return indexOfSupplementary(value, ch, fromIndex, max); 296 } 297 } 298 299 @HotSpotIntrinsicCandidate 300 public static int indexOf(byte[] value, byte[] str) { 301 if (str.length == 0) { 302 return 0; 303 } 304 if (value.length == 0) { 305 return -1; 306 } 307 return indexOf(value, length(value), str, length(str), 0); 308 } 309 310 @HotSpotIntrinsicCandidate 311 public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { 312 char first = getChar(str, 0); 313 int max = (valueCount - strCount); 314 for (int i = fromIndex; i <= max; i++) { 315 // Look for first character. 316 if (getChar(value, i) != first) { 317 while (++i <= max && getChar(value, i) != first); 318 } 319 // Found first character, now look at the rest of value 320 if (i <= max) { 321 int j = i + 1; 322 int end = j + strCount - 1; 323 for (int k = 1; j < end && getChar(value, j) == getChar(str, k); j++, k++); 324 if (j == end) { 325 // Found whole string. 326 return i; 327 } 328 } 329 } 330 return -1; 331 } 332 333 /** 334 * Handles indexOf Latin1 substring in UTF16 string. 335 */ 336 @HotSpotIntrinsicCandidate 337 public static int indexOfLatin1(byte[] value, byte[] str) { 338 if (str.length == 0) { 339 return 0; 340 } 341 if (value.length == 0) { 342 return -1; 343 } 344 return indexOfLatin1(value, length(value), str, str.length, 0); 345 } 346 347 @HotSpotIntrinsicCandidate 348 public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { 349 char first = (char)(tgt[0] & 0xff); 350 int max = (srcCount - tgtCount); 351 for (int i = fromIndex; i <= max; i++) { 352 // Look for first character. 353 if (getChar(src, i) != first) { 354 while (++i <= max && getChar(src, i) != first); 355 } 356 // Found first character, now look at the rest of v2 357 if (i <= max) { 358 int j = i + 1; 359 int end = j + tgtCount - 1; 360 for (int k = 1; 361 j < end && getChar(src, j) == (tgt[k] & 0xff); 362 j++, k++); 363 if (j == end) { 364 // Found whole string. 365 return i; 366 } 367 } 368 } 369 return -1; 370 } 371 372 @HotSpotIntrinsicCandidate 373 private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) { 374 for (int i = fromIndex; i < max; i++) { 375 if (getChar(value, i) == ch) { 376 return i; 377 } 378 } 379 return -1; 380 } 381 382 /** 383 * Handles (rare) calls of indexOf with a supplementary character. 384 */ 385 private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) { 386 if (Character.isValidCodePoint(ch)) { 387 final char hi = Character.highSurrogate(ch); 388 final char lo = Character.lowSurrogate(ch); 389 for (int i = fromIndex; i < max - 1; i++) { 390 if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) { 391 return i; 392 } 393 } 394 } 395 return -1; 396 } 397 398 public static int lastIndexOf(byte[] src, int srcCount, 399 byte[] tgt, int tgtCount, int fromIndex) { 400 int min = tgtCount - 1; 401 int i = min + fromIndex; 402 int strLastIndex = tgtCount - 1; 403 char strLastChar = getChar(tgt, strLastIndex); 404 405 startSearchForLastChar: 406 while (true) { 407 while (i >= min && getChar(src, i) != strLastChar) { 408 i--; 409 } 410 if (i < min) { 411 return -1; 412 } 413 int j = i - 1; 414 int start = j - strLastIndex; 415 int k = strLastIndex - 1; 416 while (j > start) { 417 if (getChar(src, j--) != getChar(tgt, k--)) { 418 i--; 419 continue startSearchForLastChar; 420 } 421 } 422 return start + 1; 423 } 424 } 425 426 public static int lastIndexOf(byte[] value, int ch, int fromIndex) { 427 if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { 428 // handle most cases here (ch is a BMP code point or a 429 // negative value (invalid code point)) 430 int i = Math.min(fromIndex, (value.length >> 1) - 1); 431 for (; i >= 0; i--) { 432 if (getChar(value, i) == ch) { 433 return i; 434 } 435 } 436 return -1; 437 } else { 438 return lastIndexOfSupplementary(value, ch, fromIndex); 439 } 440 } 441 442 /** 443 * Handles (rare) calls of lastIndexOf with a supplementary character. 444 */ 445 private static int lastIndexOfSupplementary(final byte[] value, int ch, int fromIndex) { 446 if (Character.isValidCodePoint(ch)) { 447 char hi = Character.highSurrogate(ch); 448 char lo = Character.lowSurrogate(ch); 449 int i = Math.min(fromIndex, (value.length >> 1) - 2); 450 for (; i >= 0; i--) { 451 if (getChar(value, i) == hi && getChar(value, i + 1) == lo) { 452 return i; 453 } 454 } 455 } 456 return -1; 457 } 458 459 public static String replace(byte[] value, char oldChar, char newChar) { 460 int len = value.length >> 1; 461 int i = -1; 462 while (++i < len) { 463 if (getChar(value, i) == oldChar) { 464 break; 465 } 466 } 467 if (i < len) { 468 byte buf[] = new byte[value.length]; 469 for (int j = 0; j < i; j++) { 470 putChar(buf, j, getChar(value, j)); // TBD:arraycopy? 471 } 472 while (i < len) { 473 char c = getChar(value, i); 474 putChar(buf, i, c == oldChar ? newChar : c); 475 i++; 476 } 477 // Check if we should try to compress to latin1 478 if (String.COMPACT_STRINGS && 479 !StringLatin1.canEncode(oldChar) && 480 StringLatin1.canEncode(newChar)) { 481 byte[] val = compress(buf, 0, len); 482 if (val != null) { 483 return new String(val, LATIN1); 484 } 485 } 486 return new String(buf, UTF16); 487 } 488 return null; 489 } 490 491 public static boolean regionMatchesCI(byte[] value, int toffset, 492 byte[] other, int ooffset, int len) { 493 int last = toffset + len; 494 while (toffset < last) { 495 char c1 = getChar(value, toffset++); 496 char c2 = getChar(other, ooffset++); 497 if (c1 == c2) { 498 continue; 499 } 500 // try converting both characters to uppercase. 501 // If the results match, then the comparison scan should 502 // continue. 503 char u1 = Character.toUpperCase(c1); 504 char u2 = Character.toUpperCase(c2); 505 if (u1 == u2) { 506 continue; 507 } 508 // Unfortunately, conversion to uppercase does not work properly 509 // for the Georgian alphabet, which has strange rules about case 510 // conversion. So we need to make one last check before 511 // exiting. 512 if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { 513 continue; 514 } 515 return false; 516 } 517 return true; 518 } 519 520 public static boolean regionMatchesCI_Latin1(byte[] value, int toffset, 521 byte[] other, int ooffset, 522 int len) { 523 int last = toffset + len; 524 while (toffset < last) { 525 char c1 = getChar(value, toffset++); 526 char c2 = (char)(other[ooffset++] & 0xff); 527 if (c1 == c2) { 528 continue; 529 } 530 char u1 = Character.toUpperCase(c1); 531 char u2 = Character.toUpperCase(c2); 532 if (u1 == u2) { 533 continue; 534 } 535 if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { 536 continue; 537 } 538 return false; 539 } 540 return true; 541 } 542 543 public static String toLowerCase(String str, byte[] value, Locale locale) { 544 if (locale == null) { 545 throw new NullPointerException(); 546 } 547 int first; 548 boolean hasSurr = false; 549 final int len = value.length >> 1; 550 551 // Now check if there are any characters that need to be changed, or are surrogate 552 for (first = 0 ; first < len; first++) { 553 int cp = (int)getChar(value, first); 554 if (Character.isSurrogate((char)cp)) { 555 hasSurr = true; 556 break; 557 } 558 if (cp != Character.toLowerCase(cp)) { // no need to check Character.ERROR 559 break; 560 } 561 } 562 if (first == len) 563 return str; 564 byte[] result = new byte[value.length]; 565 System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few 566 // lowerCase characters. 567 String lang = locale.getLanguage(); 568 if (lang == "tr" || lang == "az" || lang == "lt") { 569 return toLowerCaseEx(str, value, result, first, locale, true); 570 } 571 if (hasSurr) { 572 return toLowerCaseEx(str, value, result, first, locale, false); 573 } 574 int bits = 0; 575 for (int i = first; i < len; i++) { 576 int cp = (int)getChar(value, i); 577 if (cp == '\u03A3' || // GREEK CAPITAL LETTER SIGMA 578 Character.isSurrogate((char)cp)) { 579 return toLowerCaseEx(str, value, result, i, locale, false); 580 } 581 if (cp == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE 582 return toLowerCaseEx(str, value, result, i, locale, true); 583 } 584 cp = Character.toLowerCase(cp); 585 if (!Character.isBmpCodePoint(cp)) { 586 return toLowerCaseEx(str, value, result, i, locale, false); 587 } 588 bits |= cp; 589 putChar(result, i, cp); 590 } 591 if (bits > 0xFF) { 592 return new String(result, UTF16); 593 } else { 594 return newString(result, 0, len); 595 } 596 } 597 598 private static String toLowerCaseEx(String str, byte[] value, 599 byte[] result, int first, Locale locale, 600 boolean localeDependent) { 601 int resultOffset = first; 602 int length = value.length >> 1; 603 int srcCount; 604 for (int i = first; i < length; i += srcCount) { 605 int srcChar = getChar(value, i); 606 int lowerChar; 607 char[] lowerCharArray; 608 srcCount = 1; 609 if (Character.isSurrogate((char)srcChar)) { 610 srcChar = codePointAt(value, i, length); 611 srcCount = Character.charCount(srcChar); 612 } 613 if (localeDependent || 614 srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA 615 srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE 616 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale); 617 } else { 618 lowerChar = Character.toLowerCase(srcChar); 619 } 620 if (Character.isBmpCodePoint(lowerChar)) { // Character.ERROR is not a bmp 621 putChar(result, resultOffset++, lowerChar); 622 } else { 623 if (lowerChar == Character.ERROR) { 624 lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale); 625 } else { 626 lowerCharArray = Character.toChars(lowerChar); 627 } 628 /* Grow result if needed */ 629 int mapLen = lowerCharArray.length; 630 if (mapLen > srcCount) { 631 byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount); 632 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 633 result = result2; 634 } 635 for (int x = 0; x < mapLen; ++x) { 636 putChar(result, resultOffset++, lowerCharArray[x]); 637 } 638 } 639 } 640 return newString(result, 0, resultOffset); 641 } 642 643 public static String toUpperCase(String str, byte[] value, Locale locale) { 644 if (locale == null) { 645 throw new NullPointerException(); 646 } 647 int first; 648 boolean hasSurr = false; 649 final int len = value.length >> 1; 650 651 // Now check if there are any characters that need to be changed, or are surrogate 652 for (first = 0 ; first < len; first++) { 653 int cp = (int)getChar(value, first); 654 if (Character.isSurrogate((char)cp)) { 655 hasSurr = true; 656 break; 657 } 658 if (cp != Character.toUpperCaseEx(cp)) { // no need to check Character.ERROR 659 break; 660 } 661 } 662 if (first == len) { 663 return str; 664 } 665 byte[] result = new byte[value.length]; 666 System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few 667 // upperCase characters. 668 String lang = locale.getLanguage(); 669 if (lang == "tr" || lang == "az" || lang == "lt") { 670 return toUpperCaseEx(str, value, result, first, locale, true); 671 } 672 if (hasSurr) { 673 return toUpperCaseEx(str, value, result, first, locale, false); 674 } 675 int bits = 0; 676 for (int i = first; i < len; i++) { 677 int cp = (int)getChar(value, i); 678 if (Character.isSurrogate((char)cp)) { 679 return toUpperCaseEx(str, value, result, i, locale, false); 680 } 681 cp = Character.toUpperCaseEx(cp); 682 if (!Character.isBmpCodePoint(cp)) { // Character.ERROR is not bmp 683 return toUpperCaseEx(str, value, result, i, locale, false); 684 } 685 bits |= cp; 686 putChar(result, i, cp); 687 } 688 if (bits > 0xFF) { 689 return new String(result, UTF16); 690 } else { 691 return newString(result, 0, len); 692 } 693 } 694 695 private static String toUpperCaseEx(String str, byte[] value, 696 byte[] result, int first, 697 Locale locale, boolean localeDependent) 698 { 699 int resultOffset = first; 700 int length = value.length >> 1; 701 int srcCount; 702 for (int i = first; i < length; i += srcCount) { 703 int srcChar = getChar(value, i); 704 int upperChar; 705 char[] upperCharArray; 706 srcCount = 1; 707 if (Character.isSurrogate((char)srcChar)) { 708 srcChar = codePointAt(value, i, length); 709 srcCount = Character.charCount(srcChar); 710 } 711 if (localeDependent) { 712 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale); 713 } else { 714 upperChar = Character.toUpperCaseEx(srcChar); 715 } 716 if (Character.isBmpCodePoint(upperChar)) { 717 putChar(result, resultOffset++, upperChar); 718 } else { 719 if (upperChar == Character.ERROR) { 720 if (localeDependent) { 721 upperCharArray = 722 ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale); 723 } else { 724 upperCharArray = Character.toUpperCaseCharArray(srcChar); 725 } 726 } else { 727 upperCharArray = Character.toChars(upperChar); 728 } 729 /* Grow result if needed */ 730 int mapLen = upperCharArray.length; 731 if (mapLen > srcCount) { 732 byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount); 733 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 734 result = result2; 735 } 736 for (int x = 0; x < mapLen; ++x) { 737 putChar(result, resultOffset++, upperCharArray[x]); 738 } 739 } 740 } 741 return newString(result, 0, resultOffset); 742 } 743 744 public static String trim(byte[] value) { 745 int length = value.length >> 1; 746 int len = length; 747 int st = 0; 748 while (st < len && getChar(value, st) <= ' ') { 749 st++; 750 } 751 while (st < len && getChar(value, len - 1) <= ' ') { 752 len--; 753 } 754 return ((st > 0) || (len < length )) ? 755 new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) : 756 null; 757 } 758 759 public static void putChars(byte[] val, int index, char[] str, int off, int end) { 760 while (off < end) { 761 putChar(val, index++, str[off++]); 762 } 763 } 764 765 public static String newString(byte[] val, int index, int len) { 766 if (String.COMPACT_STRINGS) { 767 byte[] buf = compress(val, index, len); 768 if (buf != null) { 769 return new String(buf, LATIN1); 770 } 771 } 772 int last = index + len; 773 return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16); 774 } 775 776 public static void fillNull(byte[] val, int index, int end) { 777 Arrays.fill(val, index << 1, end << 1, (byte)0); 778 } 779 780 static class CharsSpliterator implements Spliterator.OfInt { 781 private final byte[] array; 782 private int index; // current index, modified on advance/split 783 private final int fence; // one past last index 784 private final int cs; 785 786 CharsSpliterator(byte[] array, int acs) { 787 this(array, 0, array.length >> 1, acs); 788 } 789 790 CharsSpliterator(byte[] array, int origin, int fence, int acs) { 791 this.array = array; 792 this.index = origin; 793 this.fence = fence; 794 this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED 795 | Spliterator.SUBSIZED; 796 } 797 798 @Override 799 public OfInt trySplit() { 800 int lo = index, mid = (lo + fence) >>> 1; 801 return (lo >= mid) 802 ? null 803 : new CharsSpliterator(array, lo, index = mid, cs); 804 } 805 806 @Override 807 public void forEachRemaining(IntConsumer action) { 808 byte[] a; int i, hi; // hoist accesses and checks from loop 809 if (action == null) 810 throw new NullPointerException(); 811 if (((a = array).length >> 1) >= (hi = fence) && 812 (i = index) >= 0 && i < (index = hi)) { 813 do { action.accept(getChar(a, i)); } while (++i < hi); 814 } 815 } 816 817 @Override 818 public boolean tryAdvance(IntConsumer action) { 819 if (action == null) 820 throw new NullPointerException(); 821 if (index >= 0 && index < fence) { 822 action.accept(getChar(array, index++)); 823 return true; 824 } 825 return false; 826 } 827 828 @Override 829 public long estimateSize() { return (long)(fence - index); } 830 831 @Override 832 public int characteristics() { 833 return cs; 834 } 835 } 836 837 static class CodePointsSpliterator implements Spliterator.OfInt { 838 private final byte[] array; 839 private int index; // current index, modified on advance/split 840 private final int fence; // one past last index 841 private final int cs; 842 843 CodePointsSpliterator(byte[] array, int acs) { 844 this(array, 0, array.length >> 1, acs); 845 } 846 847 CodePointsSpliterator(byte[] array, int origin, int fence, int acs) { 848 this.array = array; 849 this.index = origin; 850 this.fence = fence; 851 this.cs = acs | Spliterator.ORDERED; 852 } 853 854 @Override 855 public OfInt trySplit() { 856 int lo = index, mid = (lo + fence) >>> 1; 857 if (lo >= mid) 858 return null; 859 860 int midOneLess; 861 // If the mid-point intersects a surrogate pair 862 if (Character.isLowSurrogate(getChar(array, mid)) && 863 Character.isHighSurrogate(getChar(array, midOneLess = (mid -1)))) { 864 // If there is only one pair it cannot be split 865 if (lo >= midOneLess) 866 return null; 867 // Shift the mid-point to align with the surrogate pair 868 return new CodePointsSpliterator(array, lo, index = midOneLess, cs); 869 } 870 return new CodePointsSpliterator(array, lo, index = mid, cs); 871 } 872 873 @Override 874 public void forEachRemaining(IntConsumer action) { 875 byte[] a; int i, hi; // hoist accesses and checks from loop 876 if (action == null) 877 throw new NullPointerException(); 878 if (((a = array).length >> 1) >= (hi = fence) && 879 (i = index) >= 0 && i < (index = hi)) { 880 do { 881 i = advance(a, i, hi, action); 882 } while (i < hi); 883 } 884 } 885 886 @Override 887 public boolean tryAdvance(IntConsumer action) { 888 if (action == null) 889 throw new NullPointerException(); 890 if (index >= 0 && index < fence) { 891 index = advance(array, index, fence, action); 892 return true; 893 } 894 return false; 895 } 896 897 // Advance one code point from the index, i, and return the next 898 // index to advance from 899 private static int advance(byte[] a, int i, int hi, IntConsumer action) { 900 char c1 = getChar(a, i++); 901 int cp = c1; 902 if (Character.isHighSurrogate(c1) && i < hi) { 903 char c2 = getChar(a, i); 904 if (Character.isLowSurrogate(c2)) { 905 i++; 906 cp = Character.toCodePoint(c1, c2); 907 } 908 } 909 action.accept(cp); 910 return i; 911 } 912 913 @Override 914 public long estimateSize() { return (long)(fence - index); } 915 916 @Override 917 public int characteristics() { 918 return cs; 919 } 920 } 921 922 //////////////////////////////////////////////////////////////// 923 924 public static void putCharSB(byte[] val, int index, int c) { 925 checkIndex(index, val.length >> 1); 926 putChar(val, index, c); 927 } 928 929 public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) { 930 checkOffset(index + end - off, val.length >> 1); 931 putChars(val, index, ca, off, end); 932 } 933 934 public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) { 935 checkOffset(index + end - off, val.length >> 1); 936 for (int i = off; i < end; i++) { 937 putChar(val, index++, s.charAt(i)); 938 } 939 } 940 941 public static int codePointAtSB(byte[] val, int index, int end) { 942 checkOffset(end, val.length >> 1); 943 return codePointAt(val, index, end); 944 } 945 946 public static int codePointBeforeSB(byte[] val, int index) { 947 checkOffset(index, val.length >> 1); 948 return codePointBefore(val, index); 949 } 950 951 public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) { 952 checkOffset(endIndex, val.length >> 1); 953 return codePointCount(val, beginIndex, endIndex); 954 } 955 956 //////////////////////////////////////////////////////////////// 957 958 private static native boolean isBigEndian(); 959 960 static final int HI_BYTE_SHIFT; 961 static final int LO_BYTE_SHIFT; 962 static { 963 if (isBigEndian()) { 964 HI_BYTE_SHIFT = 8; 965 LO_BYTE_SHIFT = 0; 966 } else { 967 HI_BYTE_SHIFT = 0; 968 LO_BYTE_SHIFT = 8; 969 } 970 } 971 972 static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; 973 }