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