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.Spliterator; 29 import java.util.function.Consumer; 30 import java.util.function.IntConsumer; 31 import java.util.stream.Stream; 32 import java.util.stream.StreamSupport; 33 import jdk.internal.HotSpotIntrinsicCandidate; 34 35 // BEGIN Android-added: Clarification for usage of StringUTF16 and not StringLatin1. 36 /** 37 * In upstream, this class (StringUTF16) contains implementations of various APIs and their helper 38 * methods for uncompressed strings. Libcore makes use of it to implement APIs for both compressed 39 * and uncompressed strings. 40 * 41 * Upstream implementation also has StringLatin1 class which contains same implementations for 42 * compressed strings (and this class is for uncompressed). In our case we use only StringUTF16 43 * (and StringLatin1 is intentionally not imported) as string characters are managed by ART and 44 * everything is implemented in terms of {@link String#charAt(int)} an other primitives which do not 45 * have direct access to underlying character array. From those two, if we choose to implement 46 * everything in those primitives, StringUTF16 has less difference with upstream, so it is chosen 47 * here. 48 * 49 * @hide 50 */ 51 // END Android-added: Clarification for usage of StringUTF16 and not StringLatin1. 52 final class StringUTF16 { 53 54 // BEGIN Android-changed: Pass String instead of byte[]; implement in terms of charAt(). 55 // @HotSpotIntrinsicCandidate 56 // intrinsic performs no bounds checks 57 /* 58 static char getChar(byte[] val, int index) { 59 assert index >= 0 && index < length(val) : "Trusted caller missed bounds check"; 60 index <<= 1; 61 return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) | 62 ((val[index] & 0xff) << LO_BYTE_SHIFT)); 63 */ 64 @HotSpotIntrinsicCandidate getChar(String val, int index)65 static char getChar(String val, int index) { 66 return val.charAt(index); 67 } 68 // END Android-changed: Pass String instead of byte[]; implement in terms of charAt(). 69 70 // BEGIN Android-changed: Pass String instead of byte[]. 71 /* 72 public static int length(byte[] value) { 73 return value.length >> 1; 74 */ length(String value)75 public static int length(String value) { 76 return value.length(); 77 // END Android-changed: Pass String instead of byte[]. 78 } 79 80 // BEGIN Android-changed: Pass String instead of byte[]. 81 /* 82 public static int indexOfNonWhitespace(byte[] value) { 83 int length = value.length >> 1; 84 */ indexOfNonWhitespace(String value)85 public static int indexOfNonWhitespace(String value) { 86 int length = value.length(); 87 int left = 0; 88 while (left < length) { 89 /* 90 int codepoint = codePointAt(value, left, length); 91 */ 92 int codepoint = value.codePointAt(left); 93 // END Android-changed: Pass String instead of byte[]. 94 if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) { 95 break; 96 } 97 left += Character.charCount(codepoint); 98 } 99 return left; 100 } 101 102 // BEGIN Android-changed: Pass String instead of byte[]. 103 /* 104 public static int lastIndexOfNonWhitespace(byte[] value) { 105 int length = value.length >> 1; 106 int right = length; 107 */ lastIndexOfNonWhitespace(String value)108 public static int lastIndexOfNonWhitespace(String value) { 109 int right = value.length(); 110 while (0 < right) { 111 /* 112 int codepoint = codePointBefore(value, right); 113 */ 114 int codepoint = value.codePointBefore(right); 115 // END Android-changed: Pass String instead of byte[]. 116 if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) { 117 break; 118 } 119 right -= Character.charCount(codepoint); 120 } 121 return right; 122 } 123 124 // BEGIN Android-changed: Pass String instead of byte[]. 125 /* 126 public static String strip(byte[] value) { 127 int length = value.length >> 1; 128 */ strip(String value)129 public static String strip(String value) { 130 int length = value.length(); 131 // END Android-changed: Pass String instead of byte[]. 132 int left = indexOfNonWhitespace(value); 133 if (left == length) { 134 return ""; 135 } 136 int right = lastIndexOfNonWhitespace(value); 137 return ((left > 0) || (right < length)) ? newString(value, left, right - left) : null; 138 } 139 140 // BEGIN Android-changed: Pass String instead of byte[]. 141 /* 142 public static String stripLeading(byte[] value) { 143 int length = value.length >> 1; 144 */ stripLeading(String value)145 public static String stripLeading(String value) { 146 int length = value.length(); 147 // END Android-changed: Pass String instead of byte[]. 148 int left = indexOfNonWhitespace(value); 149 if (left == length) { 150 return ""; 151 } 152 return (left != 0) ? newString(value, left, length - left) : null; 153 } 154 155 // BEGIN Android-changed: Pass String instead of byte[]. 156 /* 157 public static String stripTrailing(byte[] value) { 158 int length = value.length >> 1; 159 */ stripTrailing(String value)160 public static String stripTrailing(String value) { 161 int length = value.length(); 162 // END Android-changed: Pass String instead of byte[]. 163 int right = lastIndexOfNonWhitespace(value); 164 if (right == 0) { 165 return ""; 166 } 167 return (right != length) ? newString(value, 0, right) : null; 168 } 169 170 private final static class LinesSpliterator implements Spliterator<String> { 171 // BEGIN Android-changed: Pass String instead of byte[]. 172 /* 173 private byte[] value; 174 */ 175 private String value; 176 // END Android-changed: Pass String instead of byte[]. 177 private int index; // current index, modified on advance/split 178 private final int fence; // one past last index 179 180 // BEGIN Android-changed: Pass String instead of byte[]. 181 /* 182 LinesSpliterator(byte[] value) { 183 this(value, 0, value.length >>> 1); 184 */ LinesSpliterator(String value)185 LinesSpliterator(String value) { 186 this(value, 0, value.length()); 187 // END Android-changed: Pass String instead of byte[]. 188 } 189 190 // BEGIN Android-changed: Pass String instead of byte[]. 191 /* 192 LinesSpliterator(byte[] value, int start, int length) { 193 */ LinesSpliterator(String value, int start, int length)194 LinesSpliterator(String value, int start, int length) { 195 // END Android-changed: Pass String instead of byte[]. 196 this.value = value; 197 this.index = start; 198 this.fence = start + length; 199 } 200 indexOfLineSeparator(int start)201 private int indexOfLineSeparator(int start) { 202 for (int current = start; current < fence; current++) { 203 char ch = getChar(value, current); 204 if (ch == '\n' || ch == '\r') { 205 return current; 206 } 207 } 208 return fence; 209 } 210 skipLineSeparator(int start)211 private int skipLineSeparator(int start) { 212 if (start < fence) { 213 if (getChar(value, start) == '\r') { 214 int next = start + 1; 215 if (next < fence && getChar(value, next) == '\n') { 216 return next + 1; 217 } 218 } 219 return start + 1; 220 } 221 return fence; 222 } 223 next()224 private String next() { 225 int start = index; 226 int end = indexOfLineSeparator(start); 227 index = skipLineSeparator(end); 228 return newString(value, start, end - start); 229 } 230 231 @Override tryAdvance(Consumer<? super String> action)232 public boolean tryAdvance(Consumer<? super String> action) { 233 if (action == null) { 234 throw new NullPointerException("tryAdvance action missing"); 235 } 236 if (index != fence) { 237 action.accept(next()); 238 return true; 239 } 240 return false; 241 } 242 243 @Override forEachRemaining(Consumer<? super String> action)244 public void forEachRemaining(Consumer<? super String> action) { 245 if (action == null) { 246 throw new NullPointerException("forEachRemaining action missing"); 247 } 248 while (index != fence) { 249 action.accept(next()); 250 } 251 } 252 253 @Override trySplit()254 public Spliterator<String> trySplit() { 255 int half = (fence + index) >>> 1; 256 int mid = skipLineSeparator(indexOfLineSeparator(half)); 257 if (mid < fence) { 258 int start = index; 259 index = mid; 260 return new LinesSpliterator(value, start, mid - start); 261 } 262 return null; 263 } 264 265 @Override estimateSize()266 public long estimateSize() { 267 return fence - index + 1; 268 } 269 270 @Override characteristics()271 public int characteristics() { 272 return Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL; 273 } 274 } 275 276 // BEGIN Android-changed: Pass String instead of byte[]. 277 /* 278 static Stream<String> lines(byte[] value) { 279 */ lines(String value)280 static Stream<String> lines(String value) { 281 return StreamSupport.stream(new LinesSpliterator(value), false); 282 // END Android-changed: Pass String instead of byte[]. 283 } 284 285 // BEGIN Android-changed: Pass String instead of byte[]; implement in terms of substring(). 286 /* 287 public static String newString(byte[] val, int index, int len) { 288 if (String.COMPACT_STRINGS) { 289 byte[] buf = compress(val, index, len); 290 if (buf != null) { 291 return new String(buf, LATIN1); 292 } 293 } 294 int last = index + len; 295 return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16); 296 } 297 */ newString(String val, int index, int len)298 public static String newString(String val, int index, int len) { 299 return val.substring(index, index + len); 300 } 301 // END Android-changed: Pass String instead of byte[]; implement in terms of substring(). 302 303 static class CharsSpliterator implements Spliterator.OfInt { 304 // BEGIN Android-changed: Pass String instead of byte[]. 305 /* 306 private final byte[] array; 307 */ 308 private final String array; 309 // END Android-changed: Pass String instead of byte[]. 310 private int index; // current index, modified on advance/split 311 private final int fence; // one past last index 312 private final int cs; 313 314 // BEGIN Android-changed: Pass String instead of byte[]. 315 /* 316 CharsSpliterator(byte[] array, int acs) { 317 this(array, 0, array.length >> 1, acs); 318 */ CharsSpliterator(String array, int acs)319 CharsSpliterator(String array, int acs) { 320 this(array, 0, array.length(), acs); 321 // END Android-changed: Pass String instead of byte[]. 322 } 323 324 // BEGIN Android-changed: Pass String instead of byte[]. 325 /* 326 CharsSpliterator(byte[] array, int origin, int fence, int acs) { 327 */ CharsSpliterator(String array, int origin, int fence, int acs)328 CharsSpliterator(String array, int origin, int fence, int acs) { 329 // END Android-changed: Pass String instead of byte[]. 330 this.array = array; 331 this.index = origin; 332 this.fence = fence; 333 this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED 334 | Spliterator.SUBSIZED; 335 } 336 337 @Override trySplit()338 public OfInt trySplit() { 339 int lo = index, mid = (lo + fence) >>> 1; 340 return (lo >= mid) 341 ? null 342 : new CharsSpliterator(array, lo, index = mid, cs); 343 } 344 345 @Override forEachRemaining(IntConsumer action)346 public void forEachRemaining(IntConsumer action) { 347 // BEGIN Android-changed: Pass String instead of byte[]. 348 /* 349 byte[] a; int i, hi; // hoist accesses and checks from loop 350 */ 351 String a; int i, hi; // hoist accesses and checks from loop 352 // END Android-changed: Pass String instead of byte[]. 353 if (action == null) 354 throw new NullPointerException(); 355 // BEGIN Android-changed: Pass String instead of byte[]. 356 /* 357 if (((a = array).length >> 1) >= (hi = fence) && 358 */ 359 if (((a = array).length()) >= (hi = fence) && 360 // END Android-changed: Pass String instead of byte[]. 361 (i = index) >= 0 && i < (index = hi)) { 362 do { 363 action.accept(charAt(a, i)); 364 } while (++i < hi); 365 } 366 } 367 368 @Override tryAdvance(IntConsumer action)369 public boolean tryAdvance(IntConsumer action) { 370 if (action == null) 371 throw new NullPointerException(); 372 int i = index; 373 if (i >= 0 && i < fence) { 374 action.accept(charAt(array, i)); 375 index++; 376 return true; 377 } 378 return false; 379 } 380 381 @Override estimateSize()382 public long estimateSize() { return (long)(fence - index); } 383 384 @Override characteristics()385 public int characteristics() { 386 return cs; 387 } 388 } 389 390 static class CodePointsSpliterator implements Spliterator.OfInt { 391 // BEGIN Android-changed: Pass String instead of byte[]. 392 /* 393 private final byte[] array; 394 */ 395 private final String array; 396 // END Android-changed: Pass String instead of byte[]. 397 private int index; // current index, modified on advance/split 398 private final int fence; // one past last index 399 private final int cs; 400 401 // BEGIN Android-changed: Pass String instead of byte[]. 402 /* 403 CodePointsSpliterator(byte[] array, int acs) { 404 this(array, 0, array.length >> 1, acs); 405 */ CodePointsSpliterator(String array, int acs)406 CodePointsSpliterator(String array, int acs) { 407 this(array, 0, array.length(), acs); 408 // END Android-changed: Pass String instead of byte[]. 409 } 410 411 // BEGIN Android-changed: Pass String instead of byte[]. 412 /* 413 CodePointsSpliterator(byte[] array, int origin, int fence, int acs) { 414 */ CodePointsSpliterator(String array, int origin, int fence, int acs)415 CodePointsSpliterator(String array, int origin, int fence, int acs) { 416 // END Android-changed: Pass String instead of byte[]. 417 this.array = array; 418 this.index = origin; 419 this.fence = fence; 420 this.cs = acs | Spliterator.ORDERED; 421 } 422 423 @Override trySplit()424 public OfInt trySplit() { 425 int lo = index, mid = (lo + fence) >>> 1; 426 if (lo >= mid) 427 return null; 428 429 int midOneLess; 430 // If the mid-point intersects a surrogate pair 431 if (Character.isLowSurrogate(charAt(array, mid)) && 432 Character.isHighSurrogate(charAt(array, midOneLess = (mid -1)))) { 433 // If there is only one pair it cannot be split 434 if (lo >= midOneLess) 435 return null; 436 // Shift the mid-point to align with the surrogate pair 437 return new CodePointsSpliterator(array, lo, index = midOneLess, cs); 438 } 439 return new CodePointsSpliterator(array, lo, index = mid, cs); 440 } 441 442 @Override forEachRemaining(IntConsumer action)443 public void forEachRemaining(IntConsumer action) { 444 // BEGIN Android-changed: Pass String instead of byte[]. 445 /* 446 byte[] a; int i, hi; // hoist accesses and checks from loop 447 */ 448 String a; int i, hi; // hoist accesses and checks from loop 449 // END Android-changed: Pass String instead of byte[]. 450 if (action == null) 451 throw new NullPointerException(); 452 // BEGIN Android-changed: Pass String instead of byte[]. 453 /* 454 if (((a = array).length >> 1) >= (hi = fence) && 455 */ 456 if (((a = array).length()) >= (hi = fence) && 457 // END Android-changed: Pass String instead of byte[]. 458 (i = index) >= 0 && i < (index = hi)) { 459 do { 460 i = advance(a, i, hi, action); 461 } while (i < hi); 462 } 463 } 464 465 @Override tryAdvance(IntConsumer action)466 public boolean tryAdvance(IntConsumer action) { 467 if (action == null) 468 throw new NullPointerException(); 469 if (index >= 0 && index < fence) { 470 index = advance(array, index, fence, action); 471 return true; 472 } 473 return false; 474 } 475 476 // Advance one code point from the index, i, and return the next 477 // index to advance from 478 // BEGIN Android-changed: Pass String instead of byte[]. 479 /* 480 private static int advance(byte[] a, int i, int hi, IntConsumer action) { 481 */ advance(String a, int i, int hi, IntConsumer action)482 private static int advance(String a, int i, int hi, IntConsumer action) { 483 // END Android-changed: Pass String instead of byte[]. 484 char c1 = charAt(a, i++); 485 int cp = c1; 486 if (Character.isHighSurrogate(c1) && i < hi) { 487 char c2 = charAt(a, i); 488 if (Character.isLowSurrogate(c2)) { 489 i++; 490 cp = Character.toCodePoint(c1, c2); 491 } 492 } 493 action.accept(cp); 494 return i; 495 } 496 497 @Override estimateSize()498 public long estimateSize() { return (long)(fence - index); } 499 500 @Override characteristics()501 public int characteristics() { 502 return cs; 503 } 504 } 505 506 // BEGIN Android-changed: Pass String instead of byte[]. 507 /* 508 public static char charAt(byte[] value, int index) { 509 */ charAt(String value, int index)510 public static char charAt(String value, int index) { 511 // END Android-changed: Pass String instead of byte[]. 512 checkIndex(index, value); 513 return getChar(value, index); 514 } 515 516 // BEGIN Android-changed: Pass String instead of byte[]. 517 /* 518 public static void checkIndex(int off, byte[] val) { 519 */ checkIndex(int off, String val)520 public static void checkIndex(int off, String val) { 521 // END Android-changed: Pass String instead of byte[]. 522 String.checkIndex(off, length(val)); 523 } 524 525 } 526