1 /* 2 * Copyright (c) 2015, 2019, 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.Objects; 31 import java.util.Spliterator; 32 import java.util.function.Consumer; 33 import java.util.function.IntConsumer; 34 import java.util.stream.IntStream; 35 import java.util.stream.Stream; 36 import java.util.stream.StreamSupport; 37 import jdk.internal.HotSpotIntrinsicCandidate; 38 import jdk.internal.util.ArraysSupport; 39 40 import static java.lang.String.LATIN1; 41 import static java.lang.String.UTF16; 42 import static java.lang.String.checkOffset; 43 44 final class StringLatin1 { 45 46 public static char charAt(byte[] value, int index) { 47 if (index < 0 || index >= value.length) { 48 throw new StringIndexOutOfBoundsException(index); 49 } 50 return (char)(value[index] & 0xff); 51 } 52 53 public static boolean canEncode(int cp) { 54 return cp >>> 8 == 0; 55 } 56 57 public static int length(byte[] value) { 58 return value.length; 59 } 60 61 public static int codePointAt(byte[] value, int index, int end) { 62 return value[index] & 0xff; 63 } 64 65 public static int codePointBefore(byte[] value, int index) { 66 return value[index - 1] & 0xff; 67 } 68 69 public static int codePointCount(byte[] value, int beginIndex, int endIndex) { 70 return endIndex - beginIndex; 71 } 72 73 public static char[] toChars(byte[] value) { 74 char[] dst = new char[value.length]; 75 inflate(value, 0, dst, 0, value.length); 76 return dst; 77 } 78 79 public static byte[] inflate(byte[] value, int off, int len) { 80 byte[] ret = StringUTF16.newBytesFor(len); 81 inflate(value, off, ret, 0, len); 82 return ret; 83 } 84 85 public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) { 86 inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); 87 } 88 89 public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) { 90 System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); 91 } 92 93 @HotSpotIntrinsicCandidate 94 public static boolean equals(byte[] value, byte[] other) { 95 if (value.length == other.length) { 96 for (int i = 0; i < value.length; i++) { 97 if (value[i] != other[i]) { 98 return false; 99 } 100 } 101 return true; 102 } 103 return false; 104 } 105 106 @HotSpotIntrinsicCandidate 107 public static int compareTo(byte[] value, byte[] other) { 108 int len1 = value.length; 109 int len2 = other.length; 110 return compareTo(value, other, len1, len2); 111 } 112 113 public static int compareTo(byte[] value, byte[] other, int len1, int len2) { 114 int lim = Math.min(len1, len2); 115 for (int k = 0; k < lim; k++) { 116 if (value[k] != other[k]) { 117 return getChar(value, k) - getChar(other, k); 118 } 119 } 120 return len1 - len2; 121 } 122 123 @HotSpotIntrinsicCandidate 124 public static int compareToUTF16(byte[] value, byte[] other) { 125 int len1 = length(value); 126 int len2 = StringUTF16.length(other); 127 return compareToUTF16Values(value, other, len1, len2); 128 } 129 130 /* 131 * Checks the boundary and then compares the byte arrays. 132 */ 133 public static int compareToUTF16(byte[] value, byte[] other, int len1, int len2) { 134 checkOffset(len1, length(value)); 135 checkOffset(len2, StringUTF16.length(other)); 136 137 return compareToUTF16Values(value, other, len1, len2); 138 } 139 140 private static int compareToUTF16Values(byte[] value, byte[] other, int len1, int len2) { 141 int lim = Math.min(len1, len2); 142 for (int k = 0; k < lim; k++) { 143 char c1 = getChar(value, k); 144 char c2 = StringUTF16.getChar(other, k); 145 if (c1 != c2) { 146 return c1 - c2; 147 } 148 } 149 return len1 - len2; 150 } 151 152 public static int compareToCI(byte[] value, byte[] other) { 153 int len1 = value.length; 154 int len2 = other.length; 155 int lim = Math.min(len1, len2); 156 for (int k = 0; k < lim; k++) { 157 if (value[k] != other[k]) { 158 char c1 = (char) CharacterDataLatin1.instance.toUpperCase(getChar(value, k)); 159 char c2 = (char) CharacterDataLatin1.instance.toUpperCase(getChar(other, k)); 160 if (c1 != c2) { 161 c1 = Character.toLowerCase(c1); 162 c2 = Character.toLowerCase(c2); 163 if (c1 != c2) { 164 return c1 - c2; 165 } 166 } 167 } 168 } 169 return len1 - len2; 170 } 171 172 public static int compareToCI_UTF16(byte[] value, byte[] other) { 173 int len1 = length(value); 174 int len2 = StringUTF16.length(other); 175 int lim = Math.min(len1, len2); 176 for (int k = 0; k < lim; k++) { 177 char c1 = getChar(value, k); 178 char c2 = StringUTF16.getChar(other, k); 179 if (c1 != c2) { 180 c1 = Character.toUpperCase(c1); 181 c2 = Character.toUpperCase(c2); 182 if (c1 != c2) { 183 c1 = Character.toLowerCase(c1); 184 c2 = Character.toLowerCase(c2); 185 if (c1 != c2) { 186 return c1 - c2; 187 } 188 } 189 } 190 } 191 return len1 - len2; 192 } 193 194 public static int hashCode(byte[] value) { 195 int h = 0; 196 for (byte v : value) { 197 h = 31 * h + (v & 0xff); 198 } 199 return h; 200 } 201 202 public static int indexOf(byte[] value, int ch, int fromIndex) { 203 if (!canEncode(ch)) { 204 return -1; 205 } 206 int max = value.length; 207 if (fromIndex < 0) { 208 fromIndex = 0; 209 } else if (fromIndex >= max) { 210 // Note: fromIndex might be near -1>>>1. 211 return -1; 212 } 213 byte c = (byte)ch; 214 for (int i = fromIndex; i < max; i++) { 215 if (value[i] == c) { 216 return i; 217 } 218 } 219 return -1; 220 } 221 222 @HotSpotIntrinsicCandidate 223 public static int indexOf(byte[] value, byte[] str) { 224 if (str.length == 0) { 225 return 0; 226 } 227 if (value.length == 0) { 228 return -1; 229 } 230 return indexOf(value, value.length, str, str.length, 0); 231 } 232 233 @HotSpotIntrinsicCandidate 234 public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { 235 byte first = str[0]; 236 int max = (valueCount - strCount); 237 for (int i = fromIndex; i <= max; i++) { 238 // Look for first character. 239 if (value[i] != first) { 240 while (++i <= max && value[i] != first); 241 } 242 // Found first character, now look at the rest of value 243 if (i <= max) { 244 int j = i + 1; 245 int end = j + strCount - 1; 246 for (int k = 1; j < end && value[j] == str[k]; j++, k++); 247 if (j == end) { 248 // Found whole string. 249 return i; 250 } 251 } 252 } 253 return -1; 254 } 255 256 public static int lastIndexOf(byte[] src, int srcCount, 257 byte[] tgt, int tgtCount, int fromIndex) { 258 int min = tgtCount - 1; 259 int i = min + fromIndex; 260 int strLastIndex = tgtCount - 1; 261 char strLastChar = (char)(tgt[strLastIndex] & 0xff); 262 263 startSearchForLastChar: 264 while (true) { 265 while (i >= min && (src[i] & 0xff) != strLastChar) { 266 i--; 267 } 268 if (i < min) { 269 return -1; 270 } 271 int j = i - 1; 272 int start = j - strLastIndex; 273 int k = strLastIndex - 1; 274 while (j > start) { 275 if ((src[j--] & 0xff) != (tgt[k--] & 0xff)) { 276 i--; 277 continue startSearchForLastChar; 278 } 279 } 280 return start + 1; 281 } 282 } 283 284 public static int lastIndexOf(final byte[] value, int ch, int fromIndex) { 285 if (!canEncode(ch)) { 286 return -1; 287 } 288 int off = Math.min(fromIndex, value.length - 1); 289 for (; off >= 0; off--) { 290 if (value[off] == (byte)ch) { 291 return off; 292 } 293 } 294 return -1; 295 } 296 297 public static String replace(byte[] value, char oldChar, char newChar) { 298 if (canEncode(oldChar)) { 299 int len = value.length; 300 int i = -1; 301 while (++i < len) { 302 if (value[i] == (byte)oldChar) { 303 break; 304 } 305 } 306 if (i < len) { 307 if (canEncode(newChar)) { 308 byte[] buf = StringConcatHelper.newArray(len); 309 for (int j = 0; j < i; j++) { // TBD arraycopy? 310 buf[j] = value[j]; 311 } 312 while (i < len) { 313 byte c = value[i]; 314 buf[i] = (c == (byte)oldChar) ? (byte)newChar : c; 315 i++; 316 } 317 return new String(buf, LATIN1); 318 } else { 319 byte[] buf = StringUTF16.newBytesFor(len); 320 // inflate from latin1 to UTF16 321 inflate(value, 0, buf, 0, i); 322 while (i < len) { 323 char c = (char)(value[i] & 0xff); 324 StringUTF16.putChar(buf, i, (c == oldChar) ? newChar : c); 325 i++; 326 } 327 return new String(buf, UTF16); 328 } 329 } 330 } 331 return null; // for string to return this; 332 } 333 334 public static String replace(byte[] value, int valLen, byte[] targ, 335 int targLen, byte[] repl, int replLen) 336 { 337 assert targLen > 0; 338 int i, j, p = 0; 339 if (valLen == 0 || (i = indexOf(value, valLen, targ, targLen, 0)) < 0) { 340 return null; // for string to return this; 341 } 342 343 // find and store indices of substrings to replace 344 int[] pos = new int[16]; 345 pos[0] = i; 346 i += targLen; 347 while ((j = indexOf(value, valLen, targ, targLen, i)) > 0) { 348 if (++p == pos.length) { 349 pos = Arrays.copyOf(pos, ArraysSupport.newLength(p, 1, p >> 1)); 350 } 351 pos[p] = j; 352 i = j + targLen; 353 } 354 355 int resultLen; 356 try { 357 resultLen = Math.addExact(valLen, 358 Math.multiplyExact(++p, replLen - targLen)); 359 } catch (ArithmeticException ignored) { 360 throw new OutOfMemoryError(); 361 } 362 if (resultLen == 0) { 363 return ""; 364 } 365 366 byte[] result = StringConcatHelper.newArray(resultLen); 367 int posFrom = 0, posTo = 0; 368 for (int q = 0; q < p; ++q) { 369 int nextPos = pos[q]; 370 while (posFrom < nextPos) { 371 result[posTo++] = value[posFrom++]; 372 } 373 posFrom += targLen; 374 for (int k = 0; k < replLen; ++k) { 375 result[posTo++] = repl[k]; 376 } 377 } 378 while (posFrom < valLen) { 379 result[posTo++] = value[posFrom++]; 380 } 381 return new String(result, LATIN1); 382 } 383 384 // case insensitive 385 public static boolean regionMatchesCI(byte[] value, int toffset, 386 byte[] other, int ooffset, int len) { 387 int last = toffset + len; 388 while (toffset < last) { 389 char c1 = (char)(value[toffset++] & 0xff); 390 char c2 = (char)(other[ooffset++] & 0xff); 391 if (c1 == c2) { 392 continue; 393 } 394 char u1 = Character.toUpperCase(c1); 395 char u2 = Character.toUpperCase(c2); 396 if (u1 == u2) { 397 continue; 398 } 399 if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { 400 continue; 401 } 402 return false; 403 } 404 return true; 405 } 406 407 public static boolean regionMatchesCI_UTF16(byte[] value, int toffset, 408 byte[] other, int ooffset, int len) { 409 int last = toffset + len; 410 while (toffset < last) { 411 char c1 = (char)(value[toffset++] & 0xff); 412 char c2 = StringUTF16.getChar(other, ooffset++); 413 if (c1 == c2) { 414 continue; 415 } 416 char u1 = Character.toUpperCase(c1); 417 char u2 = Character.toUpperCase(c2); 418 if (u1 == u2) { 419 continue; 420 } 421 if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { 422 continue; 423 } 424 return false; 425 } 426 return true; 427 } 428 429 public static String toLowerCase(String str, byte[] value, Locale locale) { 430 if (locale == null) { 431 throw new NullPointerException(); 432 } 433 int first; 434 final int len = value.length; 435 // Now check if there are any characters that need to be changed, or are surrogate 436 for (first = 0 ; first < len; first++) { 437 int cp = value[first] & 0xff; 438 if (cp != Character.toLowerCase(cp)) { // no need to check Character.ERROR 439 break; 440 } 441 } 442 if (first == len) 443 return str; 444 String lang = locale.getLanguage(); 445 if (lang == "tr" || lang == "az" || lang == "lt") { 446 return toLowerCaseEx(str, value, first, locale, true); 447 } 448 byte[] result = new byte[len]; 449 System.arraycopy(value, 0, result, 0, first); // Just copy the first few 450 // lowerCase characters. 451 for (int i = first; i < len; i++) { 452 int cp = value[i] & 0xff; 453 cp = Character.toLowerCase(cp); 454 if (!canEncode(cp)) { // not a latin1 character 455 return toLowerCaseEx(str, value, first, locale, false); 456 } 457 result[i] = (byte)cp; 458 } 459 return new String(result, LATIN1); 460 } 461 462 private static String toLowerCaseEx(String str, byte[] value, 463 int first, Locale locale, boolean localeDependent) 464 { 465 byte[] result = StringUTF16.newBytesFor(value.length); 466 int resultOffset = 0; 467 for (int i = 0; i < first; i++) { 468 StringUTF16.putChar(result, resultOffset++, value[i] & 0xff); 469 } 470 for (int i = first; i < value.length; i++) { 471 int srcChar = value[i] & 0xff; 472 int lowerChar; 473 char[] lowerCharArray; 474 if (localeDependent) { 475 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale); 476 } else { 477 lowerChar = Character.toLowerCase(srcChar); 478 } 479 if (Character.isBmpCodePoint(lowerChar)) { // Character.ERROR is not a bmp 480 StringUTF16.putChar(result, resultOffset++, lowerChar); 481 } else { 482 if (lowerChar == Character.ERROR) { 483 lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale); 484 } else { 485 lowerCharArray = Character.toChars(lowerChar); 486 } 487 /* Grow result if needed */ 488 int mapLen = lowerCharArray.length; 489 if (mapLen > 1) { 490 byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1); 491 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 492 result = result2; 493 } 494 for (int x = 0; x < mapLen; ++x) { 495 StringUTF16.putChar(result, resultOffset++, lowerCharArray[x]); 496 } 497 } 498 } 499 return StringUTF16.newString(result, 0, resultOffset); 500 } 501 502 public static String toUpperCase(String str, byte[] value, Locale locale) { 503 if (locale == null) { 504 throw new NullPointerException(); 505 } 506 int first; 507 final int len = value.length; 508 509 // Now check if there are any characters that need to be changed, or are surrogate 510 for (first = 0 ; first < len; first++ ) { 511 int cp = value[first] & 0xff; 512 if (cp != Character.toUpperCaseEx(cp)) { // no need to check Character.ERROR 513 break; 514 } 515 } 516 if (first == len) { 517 return str; 518 } 519 String lang = locale.getLanguage(); 520 if (lang == "tr" || lang == "az" || lang == "lt") { 521 return toUpperCaseEx(str, value, first, locale, true); 522 } 523 byte[] result = new byte[len]; 524 System.arraycopy(value, 0, result, 0, first); // Just copy the first few 525 // upperCase characters. 526 for (int i = first; i < len; i++) { 527 int cp = value[i] & 0xff; 528 cp = Character.toUpperCaseEx(cp); 529 if (!canEncode(cp)) { // not a latin1 character 530 return toUpperCaseEx(str, value, first, locale, false); 531 } 532 result[i] = (byte)cp; 533 } 534 return new String(result, LATIN1); 535 } 536 537 private static String toUpperCaseEx(String str, byte[] value, 538 int first, Locale locale, boolean localeDependent) 539 { 540 byte[] result = StringUTF16.newBytesFor(value.length); 541 int resultOffset = 0; 542 for (int i = 0; i < first; i++) { 543 StringUTF16.putChar(result, resultOffset++, value[i] & 0xff); 544 } 545 for (int i = first; i < value.length; i++) { 546 int srcChar = value[i] & 0xff; 547 int upperChar; 548 char[] upperCharArray; 549 if (localeDependent) { 550 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale); 551 } else { 552 upperChar = Character.toUpperCaseEx(srcChar); 553 } 554 if (Character.isBmpCodePoint(upperChar)) { 555 StringUTF16.putChar(result, resultOffset++, upperChar); 556 } else { 557 if (upperChar == Character.ERROR) { 558 if (localeDependent) { 559 upperCharArray = 560 ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale); 561 } else { 562 upperCharArray = Character.toUpperCaseCharArray(srcChar); 563 } 564 } else { 565 upperCharArray = Character.toChars(upperChar); 566 } 567 /* Grow result if needed */ 568 int mapLen = upperCharArray.length; 569 if (mapLen > 1) { 570 byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1); 571 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 572 result = result2; 573 } 574 for (int x = 0; x < mapLen; ++x) { 575 StringUTF16.putChar(result, resultOffset++, upperCharArray[x]); 576 } 577 } 578 } 579 return StringUTF16.newString(result, 0, resultOffset); 580 } 581 582 public static String trim(byte[] value) { 583 int len = value.length; 584 int st = 0; 585 while ((st < len) && ((value[st] & 0xff) <= ' ')) { 586 st++; 587 } 588 while ((st < len) && ((value[len - 1] & 0xff) <= ' ')) { 589 len--; 590 } 591 return ((st > 0) || (len < value.length)) ? 592 newString(value, st, len - st) : null; 593 } 594 595 public static int indexOfNonWhitespace(byte[] value) { 596 int length = value.length; 597 int left = 0; 598 while (left < length) { 599 char ch = getChar(value, left); 600 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) { 601 break; 602 } 603 left++; 604 } 605 return left; 606 } 607 608 public static int lastIndexOfNonWhitespace(byte[] value) { 609 int length = value.length; 610 int right = length; 611 while (0 < right) { 612 char ch = getChar(value, right - 1); 613 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) { 614 break; 615 } 616 right--; 617 } 618 return right; 619 } 620 621 public static String strip(byte[] value) { 622 int left = indexOfNonWhitespace(value); 623 if (left == value.length) { 624 return ""; 625 } 626 int right = lastIndexOfNonWhitespace(value); 627 boolean ifChanged = (left > 0) || (right < value.length); 628 return ifChanged ? newString(value, left, right - left) : null; 629 } 630 631 public static String stripLeading(byte[] value) { 632 int left = indexOfNonWhitespace(value); 633 if (left == value.length) { 634 return ""; 635 } 636 return (left != 0) ? newString(value, left, value.length - left) : null; 637 } 638 639 public static String stripTrailing(byte[] value) { 640 int right = lastIndexOfNonWhitespace(value); 641 if (right == 0) { 642 return ""; 643 } 644 return (right != value.length) ? newString(value, 0, right) : null; 645 } 646 647 private final static class LinesSpliterator implements Spliterator<String> { 648 private byte[] value; 649 private int index; // current index, modified on advance/split 650 private final int fence; // one past last index 651 652 private LinesSpliterator(byte[] value, int start, int length) { 653 this.value = value; 654 this.index = start; 655 this.fence = start + length; 656 } 657 658 private int indexOfLineSeparator(int start) { 659 for (int current = start; current < fence; current++) { 660 char ch = getChar(value, current); 661 if (ch == '\n' || ch == '\r') { 662 return current; 663 } 664 } 665 return fence; 666 } 667 668 private int skipLineSeparator(int start) { 669 if (start < fence) { 670 if (getChar(value, start) == '\r') { 671 int next = start + 1; 672 if (next < fence && getChar(value, next) == '\n') { 673 return next + 1; 674 } 675 } 676 return start + 1; 677 } 678 return fence; 679 } 680 681 private String next() { 682 int start = index; 683 int end = indexOfLineSeparator(start); 684 index = skipLineSeparator(end); 685 return newString(value, start, end - start); 686 } 687 688 @Override 689 public boolean tryAdvance(Consumer<? super String> action) { 690 if (action == null) { 691 throw new NullPointerException("tryAdvance action missing"); 692 } 693 if (index != fence) { 694 action.accept(next()); 695 return true; 696 } 697 return false; 698 } 699 700 @Override 701 public void forEachRemaining(Consumer<? super String> action) { 702 if (action == null) { 703 throw new NullPointerException("forEachRemaining action missing"); 704 } 705 while (index != fence) { 706 action.accept(next()); 707 } 708 } 709 710 @Override 711 public Spliterator<String> trySplit() { 712 int half = (fence + index) >>> 1; 713 int mid = skipLineSeparator(indexOfLineSeparator(half)); 714 if (mid < fence) { 715 int start = index; 716 index = mid; 717 return new LinesSpliterator(value, start, mid - start); 718 } 719 return null; 720 } 721 722 @Override 723 public long estimateSize() { 724 return fence - index + 1; 725 } 726 727 @Override 728 public int characteristics() { 729 return Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL; 730 } 731 732 static LinesSpliterator spliterator(byte[] value) { 733 return new LinesSpliterator(value, 0, value.length); 734 } 735 } 736 737 static Stream<String> lines(byte[] value) { 738 return StreamSupport.stream(LinesSpliterator.spliterator(value), false); 739 } 740 741 public static void putChar(byte[] val, int index, int c) { 742 //assert (canEncode(c)); 743 val[index] = (byte)(c); 744 } 745 746 public static char getChar(byte[] val, int index) { 747 return (char)(val[index] & 0xff); 748 } 749 750 public static byte[] toBytes(int[] val, int off, int len) { 751 byte[] ret = new byte[len]; 752 for (int i = 0; i < len; i++) { 753 int cp = val[off++]; 754 if (!canEncode(cp)) { 755 return null; 756 } 757 ret[i] = (byte)cp; 758 } 759 return ret; 760 } 761 762 public static byte[] toBytes(char c) { 763 return new byte[] { (byte)c }; 764 } 765 766 public static String newString(byte[] val, int index, int len) { 767 return new String(Arrays.copyOfRange(val, index, index + len), 768 LATIN1); 769 } 770 771 public static void fillNull(byte[] val, int index, int end) { 772 Arrays.fill(val, index, end, (byte)0); 773 } 774 775 // inflatedCopy byte[] -> char[] 776 @HotSpotIntrinsicCandidate 777 public static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) { 778 for (int i = 0; i < len; i++) { 779 dst[dstOff++] = (char)(src[srcOff++] & 0xff); 780 } 781 } 782 783 // inflatedCopy byte[] -> byte[] 784 @HotSpotIntrinsicCandidate 785 public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { 786 StringUTF16.inflate(src, srcOff, dst, dstOff, len); 787 } 788 789 static class CharsSpliterator implements Spliterator.OfInt { 790 private final byte[] array; 791 private int index; // current index, modified on advance/split 792 private final int fence; // one past last index 793 private final int cs; 794 795 CharsSpliterator(byte[] array, int acs) { 796 this(array, 0, array.length, acs); 797 } 798 799 CharsSpliterator(byte[] array, int origin, int fence, int acs) { 800 this.array = array; 801 this.index = origin; 802 this.fence = fence; 803 this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED 804 | Spliterator.SUBSIZED; 805 } 806 807 @Override 808 public OfInt trySplit() { 809 int lo = index, mid = (lo + fence) >>> 1; 810 return (lo >= mid) 811 ? null 812 : new CharsSpliterator(array, lo, index = mid, cs); 813 } 814 815 @Override 816 public void forEachRemaining(IntConsumer action) { 817 byte[] a; int i, hi; // hoist accesses and checks from loop 818 if (action == null) 819 throw new NullPointerException(); 820 if ((a = array).length >= (hi = fence) && 821 (i = index) >= 0 && i < (index = hi)) { 822 do { action.accept(a[i] & 0xff); } while (++i < hi); 823 } 824 } 825 826 @Override 827 public boolean tryAdvance(IntConsumer action) { 828 if (action == null) 829 throw new NullPointerException(); 830 if (index >= 0 && index < fence) { 831 action.accept(array[index++] & 0xff); 832 return true; 833 } 834 return false; 835 } 836 837 @Override 838 public long estimateSize() { return (long)(fence - index); } 839 840 @Override 841 public int characteristics() { 842 return cs; 843 } 844 } 845 }