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