1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.lang; 19 20 import java.io.InvalidObjectException; 21 import java.util.Arrays; 22 23 import org.apache.harmony.luni.util.Msg; 24 25 /** 26 * <p> 27 * A modifiable {@link CharSequence sequence of characters} for use in creating 28 * and modifying Strings. This class is intended as a base class for 29 * {@link StringBuffer} and {@link StringBuilder}. 30 * </p> 31 * 32 * @see StringBuffer 33 * @see StringBuilder 34 * @since Android 1.0 35 */ 36 abstract class AbstractStringBuilder { 37 38 static final int INITIAL_CAPACITY = 16; 39 40 private char[] value; 41 42 private int count; 43 44 private boolean shared; 45 46 /* 47 * Returns the character array. 48 */ getValue()49 final char[] getValue() { 50 return value; 51 } 52 53 /* 54 * Returns the underlying buffer and sets the shared flag. 55 */ shareValue()56 final char[] shareValue() { 57 shared = true; 58 return value; 59 } 60 61 /* 62 * Restores internal state after deserialization. 63 */ set(char[] val, int len)64 final void set(char[] val, int len) throws InvalidObjectException { 65 if (val == null) { 66 val = new char[0]; 67 } 68 if (val.length < len) { 69 throw new InvalidObjectException(Msg.getString("K0199")); //$NON-NLS-1$ 70 } 71 72 shared = false; 73 value = val; 74 count = len; 75 } 76 AbstractStringBuilder()77 AbstractStringBuilder() { 78 value = new char[INITIAL_CAPACITY]; 79 } 80 AbstractStringBuilder(int capacity)81 AbstractStringBuilder(int capacity) { 82 if (capacity < 0) { 83 throw new NegativeArraySizeException(); 84 } 85 value = new char[capacity]; 86 } 87 AbstractStringBuilder(String string)88 AbstractStringBuilder(String string) { 89 count = string.length(); 90 shared = false; 91 value = new char[count + INITIAL_CAPACITY]; 92 // BEGIN android-changed 93 string._getChars(0, count, value, 0); 94 // END android-changed 95 } 96 enlargeBuffer(int min)97 private void enlargeBuffer(int min) { 98 int twice = (value.length << 1) + 2; 99 char[] newData = new char[min > twice ? min : twice]; 100 System.arraycopy(value, 0, newData, 0, count); 101 value = newData; 102 shared = false; 103 } 104 appendNull()105 final void appendNull() { 106 int newSize = count + 4; 107 if (newSize > value.length) { 108 enlargeBuffer(newSize); 109 } else if (shared) { 110 value = value.clone(); 111 shared = false; 112 } 113 value[count++] = 'n'; 114 value[count++] = 'u'; 115 value[count++] = 'l'; 116 value[count++] = 'l'; 117 } 118 append0(char chars[])119 final void append0(char chars[]) { 120 int newSize = count + chars.length; 121 if (newSize > value.length) { 122 enlargeBuffer(newSize); 123 } else if (shared) { 124 value = value.clone(); 125 shared = false; 126 } 127 System.arraycopy(chars, 0, value, count, chars.length); 128 count = newSize; 129 } 130 append0(char chars[], int start, int length)131 final void append0(char chars[], int start, int length) { 132 if (chars == null) { 133 throw new NullPointerException(); 134 } 135 // start + length could overflow, start/length maybe MaxInt 136 if (start >= 0 && 0 <= length && length <= chars.length - start) { 137 int newSize = count + length; 138 if (newSize > value.length) { 139 enlargeBuffer(newSize); 140 } else if (shared) { 141 value = value.clone(); 142 shared = false; 143 } 144 System.arraycopy(chars, start, value, count, length); 145 count = newSize; 146 } else { 147 throw new ArrayIndexOutOfBoundsException(); 148 } 149 } 150 append0(char ch)151 final void append0(char ch) { 152 if (count == value.length) { 153 enlargeBuffer(count + 1); 154 } 155 if (shared) { 156 value = value.clone(); 157 shared = false; 158 } 159 value[count++] = ch; 160 } 161 append0(String string)162 final void append0(String string) { 163 if (string == null) { 164 appendNull(); 165 return; 166 } 167 int adding = string.length(); 168 int newSize = count + adding; 169 if (newSize > value.length) { 170 enlargeBuffer(newSize); 171 } else if (shared) { 172 value = value.clone(); 173 shared = false; 174 } 175 // BEGIN android-changed 176 string._getChars(0, adding, value, count); 177 // END android-changed 178 count = newSize; 179 } 180 append0(CharSequence s, int start, int end)181 final void append0(CharSequence s, int start, int end) { 182 if (s == null) { 183 s = "null"; //$NON-NLS-1$ 184 } 185 if (start < 0 || end < 0 || start > end || end > s.length()) { 186 throw new IndexOutOfBoundsException(); 187 } 188 189 // BEGIN android-changed 190 int adding = end - start; 191 int newSize = count + adding; 192 if (newSize > value.length) { 193 enlargeBuffer(newSize); 194 } else if (shared) { 195 value = value.clone(); 196 shared = false; 197 } 198 199 if (s instanceof String) { 200 // BEGIN android-changed 201 ((String) s)._getChars(start, end, value, count); 202 // END android-changed 203 } else { 204 int j = count; // Destination index. 205 for (int i = start; i < end; i++) { 206 value[j++] = s.charAt(i); 207 } 208 } 209 210 this.count = newSize; 211 // END android-changed 212 } 213 214 /** 215 * Returns the number of characters that can be held without growing. 216 * 217 * @return the capacity 218 * @see #ensureCapacity 219 * @see #length 220 */ capacity()221 public int capacity() { 222 return value.length; 223 } 224 225 /** 226 * Retrieves the character at the {@code index}. 227 * 228 * @param index 229 * the index of the character to retrieve. 230 * @return the char value. 231 * @throws IndexOutOfBoundsException 232 * if {@code index} is negative or greater than or equal to the 233 * current {@link #length()}. 234 */ charAt(int index)235 public char charAt(int index) { 236 if (index < 0 || index >= count) { 237 throw new StringIndexOutOfBoundsException(index); 238 } 239 return value[index]; 240 } 241 delete0(int start, int end)242 final void delete0(int start, int end) { 243 if (start >= 0) { 244 if (end > count) { 245 end = count; 246 } 247 if (end == start) { 248 return; 249 } 250 if (end > start) { 251 int length = count - end; 252 if (length > 0) { 253 if (!shared) { 254 System.arraycopy(value, end, value, start, length); 255 } else { 256 char[] newData = new char[value.length]; 257 System.arraycopy(value, 0, newData, 0, start); 258 System.arraycopy(value, end, newData, start, length); 259 value = newData; 260 shared = false; 261 } 262 } 263 count -= end - start; 264 return; 265 } 266 } 267 throw new StringIndexOutOfBoundsException(); 268 } 269 deleteCharAt0(int location)270 final void deleteCharAt0(int location) { 271 if (0 > location || location >= count) { 272 throw new StringIndexOutOfBoundsException(location); 273 } 274 int length = count - location - 1; 275 if (length > 0) { 276 if (!shared) { 277 System.arraycopy(value, location + 1, value, location, length); 278 } else { 279 char[] newData = new char[value.length]; 280 System.arraycopy(value, 0, newData, 0, location); 281 System 282 .arraycopy(value, location + 1, newData, location, 283 length); 284 value = newData; 285 shared = false; 286 } 287 } 288 count--; 289 } 290 291 /** 292 * Ensures that this object has a minimum capacity available before 293 * requiring the internal buffer to be enlarged. The general policy of this 294 * method is that if the {@code minimumCapacity} is larger than the current 295 * {@link #capacity()}, then the capacity will be increased to the largest 296 * value of either the {@code minimumCapacity} or the current capacity 297 * multiplied by two plus two. Although this is the general policy, there is 298 * no guarantee that the capacity will change. 299 * 300 * @param min 301 * the new minimum capacity to set. 302 */ ensureCapacity(int min)303 public void ensureCapacity(int min) { 304 if (min > value.length) { 305 enlargeBuffer(min); 306 } 307 } 308 309 /** 310 * Copies the requested sequence of characters to the {@code char[]} passed 311 * starting at {@code destStart}. 312 * 313 * @param start 314 * the inclusive start index of the characters to copy. 315 * @param end 316 * the exclusive end index of the characters to copy. 317 * @param dest 318 * the {@code char[]} to copy the characters to. 319 * @param destStart 320 * the inclusive start index of {@code dest} to begin copying to. 321 * @throws IndexOutOfBoundsException 322 * if the {@code start} is negative, the {@code destStart} is 323 * negative, the {@code start} is greater than {@code end}, the 324 * {@code end} is greater than the current {@link #length()} or 325 * {@code destStart + end - begin} is greater than 326 * {@code dest.length}. 327 */ getChars(int start, int end, char[] dest, int destStart)328 public void getChars(int start, int end, char[] dest, int destStart) { 329 if (start > count || end > count || start > end) { 330 throw new StringIndexOutOfBoundsException(); 331 } 332 System.arraycopy(value, start, dest, destStart, end - start); 333 } 334 insert0(int index, char[] chars)335 final void insert0(int index, char[] chars) { 336 if (0 > index || index > count) { 337 throw new StringIndexOutOfBoundsException(index); 338 } 339 if (chars.length != 0) { 340 move(chars.length, index); 341 System.arraycopy(chars, 0, value, index, chars.length); 342 count += chars.length; 343 } 344 } 345 insert0(int index, char chars[], int start, int length)346 final void insert0(int index, char chars[], int start, int length) { 347 if (0 <= index && index <= count) { 348 // start + length could overflow, start/length maybe MaxInt 349 if (start >= 0 && 0 <= length && length <= chars.length - start) { 350 if (length != 0) { 351 move(length, index); 352 System.arraycopy(chars, start, value, index, length); 353 count += length; 354 } 355 return; 356 } 357 throw new StringIndexOutOfBoundsException("offset " + start 358 + ", len " + length + ", array.length " + chars.length); 359 } 360 throw new StringIndexOutOfBoundsException(index); 361 } 362 insert0(int index, char ch)363 final void insert0(int index, char ch) { 364 if (0 > index || index > count) { 365 // RI compatible exception type 366 throw new ArrayIndexOutOfBoundsException(index); 367 } 368 move(1, index); 369 value[index] = ch; 370 count++; 371 } 372 insert0(int index, String string)373 final void insert0(int index, String string) { 374 if (0 <= index && index <= count) { 375 if (string == null) { 376 string = "null"; //$NON-NLS-1$ 377 } 378 int min = string.length(); 379 if (min != 0) { 380 move(min, index); 381 // BEGIN android-changed 382 string._getChars(0, min, value, index); 383 // END android-changed 384 count += min; 385 } 386 } else { 387 throw new StringIndexOutOfBoundsException(index); 388 } 389 } 390 insert0(int index, CharSequence s, int start, int end)391 final void insert0(int index, CharSequence s, int start, int end) { 392 if (s == null) { 393 s = "null"; //$NON-NLS-1$ 394 } 395 if (index < 0 || index > count || start < 0 || end < 0 || start > end 396 || end > s.length()) { 397 throw new IndexOutOfBoundsException(); 398 } 399 insert0(index, s.subSequence(start, end).toString()); 400 } 401 402 /** 403 * The current length. 404 * 405 * @return the number of characters contained in this instance. 406 */ length()407 public int length() { 408 return count; 409 } 410 move(int size, int index)411 private void move(int size, int index) { 412 int newSize; 413 if (value.length - count >= size) { 414 if (!shared) { 415 System.arraycopy(value, index, value, index + size, count 416 - index); // index == count case is no-op 417 return; 418 } 419 newSize = value.length; 420 } else { 421 int a = count + size, b = (value.length << 1) + 2; 422 newSize = a > b ? a : b; 423 } 424 425 char[] newData = new char[newSize]; 426 System.arraycopy(value, 0, newData, 0, index); 427 // index == count case is no-op 428 System.arraycopy(value, index, newData, index + size, count - index); 429 value = newData; 430 shared = false; 431 } 432 replace0(int start, int end, String string)433 final void replace0(int start, int end, String string) { 434 if (start >= 0) { 435 if (end > count) { 436 end = count; 437 } 438 if (end > start) { 439 int stringLength = string.length(); 440 int diff = end - start - stringLength; 441 if (diff > 0) { // replacing with fewer characters 442 if (!shared) { 443 // index == count case is no-op 444 System.arraycopy(value, end, value, start 445 + stringLength, count - end); 446 } else { 447 char[] newData = new char[value.length]; 448 System.arraycopy(value, 0, newData, 0, start); 449 // index == count case is no-op 450 System.arraycopy(value, end, newData, start 451 + stringLength, count - end); 452 value = newData; 453 shared = false; 454 } 455 } else if (diff < 0) { 456 // replacing with more characters...need some room 457 move(-diff, end); 458 } else if (shared) { 459 value = value.clone(); 460 shared = false; 461 } 462 // BEGIN android-changed 463 string._getChars(0, stringLength, value, start); 464 // END android-changed 465 count -= diff; 466 return; 467 } 468 if (start == end) { 469 if (string == null) { 470 throw new NullPointerException(); 471 } 472 insert0(start, string); 473 return; 474 } 475 } 476 throw new StringIndexOutOfBoundsException(); 477 } 478 reverse0()479 final void reverse0() { 480 if (count < 2) { 481 return; 482 } 483 if (!shared) { 484 for (int i = 0, end = count, mid = count / 2; i < mid; i++) { 485 char temp = value[--end]; 486 value[end] = value[i]; 487 value[i] = temp; 488 } 489 } else { 490 char[] newData = new char[value.length]; 491 for (int i = 0, end = count; i < count; i++) { 492 newData[--end] = value[i]; 493 } 494 value = newData; 495 shared = false; 496 } 497 } 498 499 /** 500 * Sets the character at the {@code index}. 501 * 502 * @param index 503 * the zero-based index of the character to replace. 504 * @param ch 505 * the character to set. 506 * @throws IndexOutOfBoundsException 507 * if {@code index} is negative or greater than or equal to the 508 * current {@link #length()}. 509 */ setCharAt(int index, char ch)510 public void setCharAt(int index, char ch) { 511 if (0 > index || index >= count) { 512 throw new StringIndexOutOfBoundsException(index); 513 } 514 if (shared) { 515 value = value.clone(); 516 shared = false; 517 } 518 value[index] = ch; 519 } 520 521 /** 522 * Sets the current length to a new value. If the new length is larger than 523 * the current length, then the new characters at the end of this object 524 * will contain the {@code char} value of {@code \u0000}. 525 * 526 * @param length 527 * the new length of this StringBuffer. 528 * @exception IndexOutOfBoundsException 529 * if {@code length < 0}. 530 * @see #length 531 */ setLength(int length)532 public void setLength(int length) { 533 if (length < 0) { 534 throw new StringIndexOutOfBoundsException(length); 535 } 536 if (count < length) { 537 if (length > value.length) { 538 enlargeBuffer(length); 539 } else { 540 if (shared) { 541 char[] newData = new char[value.length]; 542 System.arraycopy(value, 0, newData, 0, count); 543 value = newData; 544 shared = false; 545 } else { 546 Arrays.fill(value, count, length, (char) 0); 547 } 548 } 549 } 550 count = length; 551 } 552 553 /** 554 * Returns the String value of the subsequence from the {@code start} index 555 * to the current end. 556 * 557 * @param start 558 * the inclusive start index to begin the subsequence. 559 * @return a String containing the subsequence. 560 * @throws StringIndexOutOfBoundsException 561 * if {@code start} is negative or greater than the current 562 * {@link #length()}. 563 */ substring(int start)564 public String substring(int start) { 565 if (0 <= start && start <= count) { 566 if (start == count) { 567 return ""; //$NON-NLS-1$ 568 } 569 570 shared = true; 571 return new String(start, count - start, value); 572 } 573 throw new StringIndexOutOfBoundsException(start); 574 } 575 576 /** 577 * Returns the String value of the subsequence from the {@code start} index 578 * to the {@code end} index. 579 * 580 * @param start 581 * the inclusive start index to begin the subsequence. 582 * @param end 583 * the exclusive end index to end the subsequence. 584 * @return a String containing the subsequence. 585 * @throws StringIndexOutOfBoundsException 586 * if {@code start} is negative, greater than {@code end} or if 587 * {@code end} is greater than the current {@link #length()}. 588 */ substring(int start, int end)589 public String substring(int start, int end) { 590 if (0 <= start && start <= end && end <= count) { 591 if (start == end) { 592 return ""; //$NON-NLS-1$ 593 } 594 595 shared = true; 596 return new String(value, start, end - start); 597 } 598 throw new StringIndexOutOfBoundsException(); 599 } 600 601 /** 602 * Returns the current String representation. 603 * 604 * @return a String containing the characters in this instance. 605 */ 606 @Override toString()607 public String toString() { 608 if (count == 0) { 609 return ""; //$NON-NLS-1$ 610 } 611 612 if (count >= 256 && count <= (value.length >> 1)) { 613 return new String(value, 0, count); 614 } 615 shared = true; 616 return new String(0, count, value); 617 } 618 619 /** 620 * Returns a {@code CharSequence} of the subsequence from the {@code start} 621 * index to the {@code end} index. 622 * 623 * @param start 624 * the inclusive start index to begin the subsequence. 625 * @param end 626 * the exclusive end index to end the subsequence. 627 * @return a CharSequence containing the subsequence. 628 * @throws IndexOutOfBoundsException 629 * if {@code start} is negative, greater than {@code end} or if 630 * {@code end} is greater than the current {@link #length()}. 631 */ subSequence(int start, int end)632 public CharSequence subSequence(int start, int end) { 633 return substring(start, end); 634 } 635 636 /** 637 * Searches for the first index of the specified character. The search for 638 * the character starts at the beginning and moves towards the end. 639 * 640 * @param string 641 * the string to find. 642 * @return the index of the specified character, -1 if the character isn't 643 * found. 644 * @see #lastIndexOf(String) 645 */ indexOf(String string)646 public int indexOf(String string) { 647 return indexOf(string, 0); 648 } 649 650 /** 651 * Searches for the index of the specified character. The search for the 652 * character starts at the specified offset and moves towards the end. 653 * 654 * @param subString 655 * the string to find. 656 * @param start 657 * the starting offset. 658 * @return the index of the specified character, -1 if the character isn't 659 * found 660 * @see #lastIndexOf(String,int) 661 */ indexOf(String subString, int start)662 public int indexOf(String subString, int start) { 663 if (start < 0) { 664 start = 0; 665 } 666 int subCount = subString.length(); 667 if (subCount > 0) { 668 if (subCount + start > count) { 669 return -1; 670 } 671 // TODO optimize charAt to direct array access 672 char firstChar = subString.charAt(0); 673 while (true) { 674 int i = start; 675 boolean found = false; 676 for (; i < count; i++) { 677 if (value[i] == firstChar) { 678 found = true; 679 break; 680 } 681 } 682 if (!found || subCount + i > count) { 683 return -1; // handles subCount > count || start >= count 684 } 685 int o1 = i, o2 = 0; 686 while (++o2 < subCount && value[++o1] == subString.charAt(o2)) { 687 // Intentionally empty 688 } 689 if (o2 == subCount) { 690 return i; 691 } 692 start = i + 1; 693 } 694 } 695 return (start < count || start == 0) ? start : count; 696 } 697 698 /** 699 * Searches for the last index of the specified character. The search for 700 * the character starts at the end and moves towards the beginning. 701 * 702 * @param string 703 * the string to find. 704 * @return the index of the specified character, -1 if the character isn't 705 * found. 706 * @see String#lastIndexOf(String) 707 */ lastIndexOf(String string)708 public int lastIndexOf(String string) { 709 return lastIndexOf(string, count); 710 } 711 712 /** 713 * Searches for the index of the specified character. The search for the 714 * character starts at the specified offset and moves towards the beginning. 715 * 716 * @param subString 717 * the string to find. 718 * @param start 719 * the starting offset. 720 * @return the index of the specified character, -1 if the character isn't 721 * found. 722 * @see String#lastIndexOf(String,int) 723 */ lastIndexOf(String subString, int start)724 public int lastIndexOf(String subString, int start) { 725 int subCount = subString.length(); 726 if (subCount <= count && start >= 0) { 727 if (subCount > 0) { 728 if (start > count - subCount) { 729 start = count - subCount; // count and subCount are both 730 } 731 // >= 1 732 // TODO optimize charAt to direct array access 733 char firstChar = subString.charAt(0); 734 while (true) { 735 int i = start; 736 boolean found = false; 737 for (; i >= 0; --i) { 738 if (value[i] == firstChar) { 739 found = true; 740 break; 741 } 742 } 743 if (!found) { 744 return -1; 745 } 746 int o1 = i, o2 = 0; 747 while (++o2 < subCount 748 && value[++o1] == subString.charAt(o2)) { 749 // Intentionally empty 750 } 751 if (o2 == subCount) { 752 return i; 753 } 754 start = i - 1; 755 } 756 } 757 return start < count ? start : count; 758 } 759 return -1; 760 } 761 762 /** 763 * Trims off any extra capacity beyond the current length. Note, this method 764 * is NOT guaranteed to change the capacity of this object. 765 */ trimToSize()766 public void trimToSize() { 767 if (count < value.length) { 768 char[] newValue = new char[count]; 769 System.arraycopy(value, 0, newValue, 0, count); 770 value = newValue; 771 shared = false; 772 } 773 } 774 775 /** 776 * Retrieves the Unicode code point value at the {@code index}. 777 * 778 * @param index 779 * the index to the {@code char} code unit. 780 * @return the Unicode code point value. 781 * @throws IndexOutOfBoundsException 782 * if {@code index} is negative or greater than or equal to 783 * {@link #length()}. 784 * @see Character 785 * @see Character#codePointAt(char[], int, int) 786 */ codePointAt(int index)787 public int codePointAt(int index) { 788 if (index < 0 || index >= count) { 789 throw new StringIndexOutOfBoundsException(index); 790 } 791 return Character.codePointAt(value, index, count); 792 } 793 794 /** 795 * Retrieves the Unicode code point value that precedes the {@code index}. 796 * 797 * @param index 798 * the index to the {@code char} code unit within this object. 799 * @return the Unicode code point value. 800 * @throws IndexOutOfBoundsException 801 * if {@code index} is less than 1 or greater than 802 * {@link #length()}. 803 * @see Character 804 * @see Character#codePointBefore(char[], int) 805 */ codePointBefore(int index)806 public int codePointBefore(int index) { 807 if (index < 1 || index > count) { 808 throw new StringIndexOutOfBoundsException(index); 809 } 810 return Character.codePointBefore(value, index); 811 } 812 813 /** 814 * <p> 815 * Calculates the number of Unicode code points between {@code beginIndex} 816 * and {@code endIndex}. 817 * </p> 818 * 819 * @param beginIndex 820 * the inclusive beginning index of the subsequence. 821 * @param endIndex 822 * the exclusive end index of the subsequence. 823 * @return the number of Unicode code points in the subsequence. 824 * @throws IndexOutOfBoundsException 825 * if {@code beginIndex} is negative or greater than 826 * {@code endIndex} or {@code endIndex} is greater than 827 * {@link #length()}. 828 * @see Character 829 * @see Character#codePointCount(char[], int, int) 830 */ codePointCount(int beginIndex, int endIndex)831 public int codePointCount(int beginIndex, int endIndex) { 832 if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) { 833 throw new StringIndexOutOfBoundsException(); 834 } 835 return Character.codePointCount(value, beginIndex, endIndex 836 - beginIndex); 837 } 838 839 /** 840 * <p> 841 * Returns the index that is offset {@code codePointOffset} code points from 842 * {@code index}. 843 * </p> 844 * 845 * @param index 846 * the index to calculate the offset from. 847 * @param codePointOffset 848 * the number of code points to count. 849 * @return the index that is {@code codePointOffset} code points away from 850 * index. 851 * @throws IndexOutOfBoundsException 852 * if {@code index} is negative or greater than 853 * {@link #length()} or if there aren't enough code points 854 * before or after {@code index} to match 855 * {@code codePointOffset}. 856 * @see Character 857 * @see Character#offsetByCodePoints(char[], int, int, int, int) 858 */ offsetByCodePoints(int index, int codePointOffset)859 public int offsetByCodePoints(int index, int codePointOffset) { 860 return Character.offsetByCodePoints(value, 0, count, index, 861 codePointOffset); 862 } 863 } 864