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.nio; 19 20 import java.io.IOException; 21 import java.util.Arrays; 22 23 /** 24 * A buffer of chars. 25 * <p> 26 * A char buffer can be created in either one of the following ways: 27 * <ul> 28 * <li>{@link #allocate(int) Allocate} a new char array and create a buffer 29 * based on it;</li> 30 * <li>{@link #wrap(char[]) Wrap} an existing char array to create a new 31 * buffer;</li> 32 * <li>{@link #wrap(CharSequence) Wrap} an existing char sequence to create a 33 * new buffer;</li> 34 * <li>Use {@link java.nio.ByteBuffer#asCharBuffer() ByteBuffer.asCharBuffer} 35 * to create a char buffer based on a byte buffer.</li> 36 * </ul> 37 */ 38 public abstract class CharBuffer extends Buffer implements 39 Comparable<CharBuffer>, CharSequence, Appendable, Readable { 40 41 /** 42 * Creates a char buffer based on a newly allocated char array. 43 * 44 * @param capacity 45 * the capacity of the new buffer. 46 * @return the created char buffer. 47 * @throws IllegalArgumentException 48 * if {@code capacity} is less than zero. 49 */ 50 public static CharBuffer allocate(int capacity) { 51 if (capacity < 0) { 52 throw new IllegalArgumentException("capacity < 0: " + capacity); 53 } 54 return new CharArrayBuffer(new char[capacity]); 55 } 56 57 /** 58 * Creates a new char buffer by wrapping the given char array. 59 * <p> 60 * Calling this method has the same effect as 61 * {@code wrap(array, 0, array.length)}. 62 * 63 * @param array 64 * the char array which the new buffer will be based on. 65 * @return the created char buffer. 66 */ 67 public static CharBuffer wrap(char[] array) { 68 return wrap(array, 0, array.length); 69 } 70 71 /** 72 * Creates a new char buffer by wrapping the given char array. 73 * <p> 74 * The new buffer's position will be {@code start}, limit will be 75 * {@code start + charCount}, capacity will be the length of the array. 76 * 77 * @param array 78 * the char array which the new buffer will be based on. 79 * @param start 80 * the start index, must not be negative and not greater than 81 * {@code array.length}. 82 * @param charCount 83 * the length, must not be negative and not greater than 84 * {@code array.length - start}. 85 * @return the created char buffer. 86 * @throws IndexOutOfBoundsException 87 * if either {@code start} or {@code charCount} is invalid. 88 */ 89 public static CharBuffer wrap(char[] array, int start, int charCount) { 90 Arrays.checkOffsetAndCount(array.length, start, charCount); 91 CharBuffer buf = new CharArrayBuffer(array); 92 buf.position = start; 93 buf.limit = start + charCount; 94 return buf; 95 } 96 97 /** 98 * Creates a new char buffer by wrapping the given char sequence. 99 * <p> 100 * Calling this method has the same effect as 101 * {@code wrap(chseq, 0, chseq.length())}. 102 * 103 * @param chseq 104 * the char sequence which the new buffer will be based on. 105 * @return the created char buffer. 106 */ 107 public static CharBuffer wrap(CharSequence chseq) { 108 return new CharSequenceAdapter(chseq); 109 } 110 111 /** 112 * Creates a new char buffer by wrapping the given char sequence. 113 * <p> 114 * The new buffer's position will be {@code start}, limit will be 115 * {@code end}, capacity will be the length of the char sequence. The new 116 * buffer is read-only. 117 * 118 * @param cs 119 * the char sequence which the new buffer will be based on. 120 * @param start 121 * the start index, must not be negative and not greater than 122 * {@code cs.length()}. 123 * @param end 124 * the end index, must be no less than {@code start} and no 125 * greater than {@code cs.length()}. 126 * @return the created char buffer. 127 * @throws IndexOutOfBoundsException 128 * if either {@code start} or {@code end} is invalid. 129 */ 130 public static CharBuffer wrap(CharSequence cs, int start, int end) { 131 if (start < 0 || end < start || end > cs.length()) { 132 throw new IndexOutOfBoundsException("cs.length()=" + cs.length() + ", start=" + start + ", end=" + end); 133 } 134 CharBuffer result = new CharSequenceAdapter(cs); 135 result.position = start; 136 result.limit = end; 137 return result; 138 } 139 140 CharBuffer(int capacity, long effectiveDirectAddress) { 141 super(1, capacity, effectiveDirectAddress); 142 } 143 144 public final char[] array() { 145 return protectedArray(); 146 } 147 148 public final int arrayOffset() { 149 return protectedArrayOffset(); 150 } 151 152 /** 153 * Returns a read-only buffer that shares its content with this buffer. 154 * <p> 155 * The returned buffer is guaranteed to be a new instance, even if this 156 * buffer is read-only itself. The new buffer's position, limit, capacity 157 * and mark are the same as this buffer's. 158 * <p> 159 * The new buffer shares its content with this buffer, which means this 160 * buffer's change of content will be visible to the new buffer. The two 161 * buffer's position, limit and mark are independent. 162 * 163 * @return a read-only version of this buffer. 164 */ 165 public abstract CharBuffer asReadOnlyBuffer(); 166 167 /** 168 * Returns the character located at the given offset <i>relative to the current position</i>. 169 * @throws IndexOutOfBoundsException if {@code index < 0} or {@code index >= remaining()}. 170 */ 171 public final char charAt(int index) { 172 if (index < 0 || index >= remaining()) { 173 throw new IndexOutOfBoundsException("index=" + index + ", remaining()=" + remaining()); 174 } 175 return get(position + index); 176 } 177 178 /** 179 * Compacts this char buffer. 180 * <p> 181 * The remaining chars will be moved to the head of the buffer, 182 * starting from position zero. Then the position is set to 183 * {@code remaining()}; the limit is set to capacity; the mark is cleared. 184 * 185 * @return this buffer. 186 * @throws ReadOnlyBufferException 187 * if no changes may be made to the contents of this buffer. 188 */ 189 public abstract CharBuffer compact(); 190 191 /** 192 * Compare the remaining chars of this buffer to another char 193 * buffer's remaining chars. 194 * 195 * @param otherBuffer 196 * another char buffer. 197 * @return a negative value if this is less than {@code otherBuffer}; 0 if 198 * this equals to {@code otherBuffer}; a positive value if this is 199 * greater than {@code otherBuffer}. 200 * @throws ClassCastException 201 * if {@code otherBuffer} is not a char buffer. 202 */ 203 public int compareTo(CharBuffer otherBuffer) { 204 int compareRemaining = (remaining() < otherBuffer.remaining()) ? remaining() 205 : otherBuffer.remaining(); 206 int thisPos = position; 207 int otherPos = otherBuffer.position; 208 char thisByte, otherByte; 209 while (compareRemaining > 0) { 210 thisByte = get(thisPos); 211 otherByte = otherBuffer.get(otherPos); 212 if (thisByte != otherByte) { 213 return thisByte < otherByte ? -1 : 1; 214 } 215 thisPos++; 216 otherPos++; 217 compareRemaining--; 218 } 219 return remaining() - otherBuffer.remaining(); 220 } 221 222 /** 223 * Returns a duplicated buffer that shares its content with this buffer. 224 * <p> 225 * The duplicated buffer's initial position, limit, capacity and mark are 226 * the same as this buffer's. The duplicated buffer's read-only property and 227 * byte order are the same as this buffer's, too. 228 * <p> 229 * The new buffer shares its content with this buffer, which means either 230 * buffer's change of content will be visible to the other. The two buffers' 231 * position, limit and mark are independent. 232 */ 233 public abstract CharBuffer duplicate(); 234 235 /** 236 * Checks whether this char buffer is equal to another object. 237 * <p> 238 * If {@code other} is not a char buffer then {@code false} is returned. Two 239 * char buffers are equal if and only if their remaining chars are exactly 240 * the same. Position, limit, capacity and mark are not considered. 241 * 242 * @param other 243 * the object to compare with this char buffer. 244 * @return {@code true} if this char buffer is equal to {@code other}, 245 * {@code false} otherwise. 246 */ 247 @Override 248 public boolean equals(Object other) { 249 if (!(other instanceof CharBuffer)) { 250 return false; 251 } 252 CharBuffer otherBuffer = (CharBuffer) other; 253 254 if (remaining() != otherBuffer.remaining()) { 255 return false; 256 } 257 258 int myPosition = position; 259 int otherPosition = otherBuffer.position; 260 boolean equalSoFar = true; 261 while (equalSoFar && (myPosition < limit)) { 262 equalSoFar = get(myPosition++) == otherBuffer.get(otherPosition++); 263 } 264 265 return equalSoFar; 266 } 267 268 /** 269 * Returns the char at the current position and increases the position by 1. 270 * 271 * @return the char at the current position. 272 * @throws BufferUnderflowException 273 * if the position is equal or greater than limit. 274 */ 275 public abstract char get(); 276 277 /** 278 * Reads chars from the current position into the specified char array and 279 * increases the position by the number of chars read. 280 * <p> 281 * Calling this method has the same effect as 282 * {@code get(dst, 0, dst.length)}. 283 * 284 * @param dst 285 * the destination char array. 286 * @return this buffer. 287 * @throws BufferUnderflowException 288 * if {@code dst.length} is greater than {@code remaining()}. 289 */ 290 public CharBuffer get(char[] dst) { 291 return get(dst, 0, dst.length); 292 } 293 294 /** 295 * Reads chars from the current position into the specified char array, 296 * starting from the specified offset, and increases the position by the 297 * number of chars read. 298 * 299 * @param dst 300 * the target char array. 301 * @param dstOffset 302 * the offset of the char array, must not be negative and not 303 * greater than {@code dst.length}. 304 * @param charCount 305 * The number of chars to read, must be no less than zero and no 306 * greater than {@code dst.length - dstOffset}. 307 * @return this buffer. 308 * @throws IndexOutOfBoundsException 309 * if either {@code dstOffset} or {@code charCount} is invalid. 310 * @throws BufferUnderflowException 311 * if {@code charCount} is greater than {@code remaining()}. 312 */ 313 public CharBuffer get(char[] dst, int dstOffset, int charCount) { 314 Arrays.checkOffsetAndCount(dst.length, dstOffset, charCount); 315 if (charCount > remaining()) { 316 throw new BufferUnderflowException(); 317 } 318 for (int i = dstOffset; i < dstOffset + charCount; ++i) { 319 dst[i] = get(); 320 } 321 return this; 322 } 323 324 /** 325 * Returns a char at the specified index; the position is not changed. 326 * 327 * @param index 328 * the index, must not be negative and less than limit. 329 * @return a char at the specified index. 330 * @throws IndexOutOfBoundsException 331 * if index is invalid. 332 */ 333 public abstract char get(int index); 334 335 public final boolean hasArray() { 336 return protectedHasArray(); 337 } 338 339 /** 340 * Calculates this buffer's hash code from the remaining chars. The 341 * position, limit, capacity and mark don't affect the hash code. 342 * 343 * @return the hash code calculated from the remaining chars. 344 */ 345 @Override 346 public int hashCode() { 347 int myPosition = position; 348 int hash = 0; 349 while (myPosition < limit) { 350 hash = hash + get(myPosition++); 351 } 352 return hash; 353 } 354 355 /** 356 * Indicates whether this buffer is direct. A direct buffer will try its 357 * best to take advantage of native memory APIs and it may not stay in the 358 * Java heap, so it is not affected by garbage collection. 359 * <p> 360 * A char buffer is direct if it is based on a byte buffer and the byte 361 * buffer is direct. 362 * 363 * @return {@code true} if this buffer is direct, {@code false} otherwise. 364 */ 365 public abstract boolean isDirect(); 366 367 /** 368 * Returns the number of remaining chars. 369 * 370 * @return the number of remaining chars. 371 */ 372 public final int length() { 373 return remaining(); 374 } 375 376 /** 377 * Returns the byte order used by this buffer when converting chars from/to 378 * bytes. 379 * <p> 380 * If this buffer is not based on a byte buffer, then this always returns 381 * the platform's native byte order. 382 * 383 * @return the byte order used by this buffer when converting chars from/to 384 * bytes. 385 */ 386 public abstract ByteOrder order(); 387 388 /** 389 * Child class implements this method to realize {@code array()}. 390 * 391 * @see #array() 392 */ 393 abstract char[] protectedArray(); 394 395 /** 396 * Child class implements this method to realize {@code arrayOffset()}. 397 * 398 * @see #arrayOffset() 399 */ 400 abstract int protectedArrayOffset(); 401 402 /** 403 * Child class implements this method to realize {@code hasArray()}. 404 * 405 * @see #hasArray() 406 */ 407 abstract boolean protectedHasArray(); 408 409 /** 410 * Writes the given char to the current position and increases the position 411 * by 1. 412 * 413 * @param c 414 * the char to write. 415 * @return this buffer. 416 * @throws BufferOverflowException 417 * if position is equal or greater than limit. 418 * @throws ReadOnlyBufferException 419 * if no changes may be made to the contents of this buffer. 420 */ 421 public abstract CharBuffer put(char c); 422 423 /** 424 * Writes chars from the given char array to the current position and 425 * increases the position by the number of chars written. 426 * <p> 427 * Calling this method has the same effect as 428 * {@code put(src, 0, src.length)}. 429 * 430 * @param src 431 * the source char array. 432 * @return this buffer. 433 * @throws BufferOverflowException 434 * if {@code remaining()} is less than {@code src.length}. 435 * @throws ReadOnlyBufferException 436 * if no changes may be made to the contents of this buffer. 437 */ 438 public final CharBuffer put(char[] src) { 439 return put(src, 0, src.length); 440 } 441 442 /** 443 * Writes chars from the given char array, starting from the specified offset, 444 * to the current position and increases the position by the number of chars 445 * written. 446 * 447 * @param src 448 * the source char array. 449 * @param srcOffset 450 * the offset of char array, must not be negative and not greater 451 * than {@code src.length}. 452 * @param charCount 453 * the number of chars to write, must be no less than zero and no 454 * greater than {@code src.length - srcOffset}. 455 * @return this buffer. 456 * @throws BufferOverflowException 457 * if {@code remaining()} is less than {@code charCount}. 458 * @throws IndexOutOfBoundsException 459 * if either {@code srcOffset} or {@code charCount} is invalid. 460 * @throws ReadOnlyBufferException 461 * if no changes may be made to the contents of this buffer. 462 */ 463 public CharBuffer put(char[] src, int srcOffset, int charCount) { 464 Arrays.checkOffsetAndCount(src.length, srcOffset, charCount); 465 if (charCount > remaining()) { 466 throw new BufferOverflowException(); 467 } 468 for (int i = srcOffset; i < srcOffset + charCount; ++i) { 469 put(src[i]); 470 } 471 return this; 472 } 473 474 /** 475 * Writes all the remaining chars of the {@code src} char buffer to this 476 * buffer's current position, and increases both buffers' position by the 477 * number of chars copied. 478 * 479 * @param src 480 * the source char buffer. 481 * @return this buffer. 482 * @throws BufferOverflowException 483 * if {@code src.remaining()} is greater than this buffer's 484 * {@code remaining()}. 485 * @throws IllegalArgumentException 486 * if {@code src} is this buffer. 487 * @throws ReadOnlyBufferException 488 * if no changes may be made to the contents of this buffer. 489 */ 490 public CharBuffer put(CharBuffer src) { 491 if (isReadOnly()) { 492 throw new ReadOnlyBufferException(); 493 } 494 if (src == this) { 495 throw new IllegalArgumentException("src == this"); 496 } 497 if (src.remaining() > remaining()) { 498 throw new BufferOverflowException(); 499 } 500 501 char[] contents = new char[src.remaining()]; 502 src.get(contents); 503 put(contents); 504 return this; 505 } 506 507 /** 508 * Writes a char to the specified index of this buffer; the position is not 509 * changed. 510 * 511 * @param index 512 * the index, must be no less than zero and less than the limit. 513 * @param c 514 * the char to write. 515 * @return this buffer. 516 * @throws IndexOutOfBoundsException 517 * if index is invalid. 518 * @throws ReadOnlyBufferException 519 * if no changes may be made to the contents of this buffer. 520 */ 521 public abstract CharBuffer put(int index, char c); 522 523 /** 524 * Writes all chars of the given string to the current position of this 525 * buffer, and increases the position by the length of string. 526 * <p> 527 * Calling this method has the same effect as 528 * {@code put(str, 0, str.length())}. 529 * 530 * @param str 531 * the string to write. 532 * @return this buffer. 533 * @throws BufferOverflowException 534 * if {@code remaining()} is less than the length of string. 535 * @throws ReadOnlyBufferException 536 * if no changes may be made to the contents of this buffer. 537 */ 538 public final CharBuffer put(String str) { 539 return put(str, 0, str.length()); 540 } 541 542 /** 543 * Writes chars of the given string to the current position of this buffer, 544 * and increases the position by the number of chars written. 545 * 546 * @param str 547 * the string to write. 548 * @param start 549 * the first char to write, must not be negative and not greater 550 * than {@code str.length()}. 551 * @param end 552 * the last char to write (excluding), must be less than 553 * {@code start} and not greater than {@code str.length()}. 554 * @return this buffer. 555 * @throws BufferOverflowException 556 * if {@code remaining()} is less than {@code end - start}. 557 * @throws IndexOutOfBoundsException 558 * if either {@code start} or {@code end} is invalid. 559 * @throws ReadOnlyBufferException 560 * if no changes may be made to the contents of this buffer. 561 */ 562 public CharBuffer put(String str, int start, int end) { 563 if (isReadOnly()) { 564 throw new ReadOnlyBufferException(); 565 } 566 if (start < 0 || end < start || end > str.length()) { 567 throw new IndexOutOfBoundsException("str.length()=" + str.length() + 568 ", start=" + start + ", end=" + end); 569 } 570 if (end - start > remaining()) { 571 throw new BufferOverflowException(); 572 } 573 for (int i = start; i < end; i++) { 574 put(str.charAt(i)); 575 } 576 return this; 577 } 578 579 /** 580 * Returns a sliced buffer that shares its content with this buffer. 581 * <p> 582 * The sliced buffer's capacity will be this buffer's {@code remaining()}, 583 * and its zero position will correspond to this buffer's current position. 584 * The new buffer's position will be 0, limit will be its capacity, and its 585 * mark is cleared. The new buffer's read-only property and byte order are 586 * same as this buffer. 587 * <p> 588 * The new buffer shares its content with this buffer, which means either 589 * buffer's change of content will be visible to the other. The two buffers' 590 * position, limit and mark are independent. 591 */ 592 public abstract CharBuffer slice(); 593 594 /** 595 * Returns a new char buffer representing a sub-sequence of this buffer's 596 * current remaining content. 597 * <p> 598 * The new buffer's position will be {@code position() + start}, limit will 599 * be {@code position() + end}, capacity will be the same as this buffer. 600 * The new buffer's read-only property and byte order are the same as this 601 * buffer. 602 * <p> 603 * The new buffer shares its content with this buffer, which means either 604 * buffer's change of content will be visible to the other. The two buffers' 605 * position, limit and mark are independent. 606 * 607 * @param start 608 * the start index of the sub-sequence, referenced from the 609 * current buffer position. Must not be less than zero and not 610 * greater than the value obtained from a call to 611 * {@code remaining()}. 612 * @param end 613 * the end index of the sub-sequence, referenced from the current 614 * buffer position. Must not be less than {@code start} and not 615 * be greater than the value obtained from a call to 616 * {@code remaining()}. 617 * @return a new char buffer represents a sub-sequence of this buffer's 618 * current remaining content. 619 * @throws IndexOutOfBoundsException 620 * if either {@code start} or {@code end} is invalid. 621 */ 622 public abstract CharBuffer subSequence(int start, int end); 623 624 /** 625 * Returns a string representing the current remaining chars of this buffer. 626 */ 627 @Override 628 public String toString() { 629 StringBuilder result = new StringBuilder(limit - position); 630 for (int i = position; i < limit; i++) { 631 result.append(get(i)); 632 } 633 return result.toString(); 634 } 635 636 /** 637 * Writes the given char to the current position and increases the position 638 * by 1. 639 * 640 * @param c 641 * the char to write. 642 * @return this buffer. 643 * @throws BufferOverflowException 644 * if position is equal or greater than limit. 645 * @throws ReadOnlyBufferException 646 * if no changes may be made to the contents of this buffer. 647 */ 648 public CharBuffer append(char c) { 649 return put(c); 650 } 651 652 /** 653 * Writes all chars of the given character sequence {@code csq} to the 654 * current position of this buffer, and increases the position by the length 655 * of the csq. 656 * <p> 657 * Calling this method has the same effect as {@code append(csq.toString())}. 658 * If the {@code CharSequence} is {@code null} the string "null" will be 659 * written to the buffer. 660 * 661 * @param csq 662 * the {@code CharSequence} to write. 663 * @return this buffer. 664 * @throws BufferOverflowException 665 * if {@code remaining()} is less than the length of csq. 666 * @throws ReadOnlyBufferException 667 * if no changes may be made to the contents of this buffer. 668 */ 669 public CharBuffer append(CharSequence csq) { 670 if (csq != null) { 671 return put(csq.toString()); 672 } 673 return put("null"); 674 } 675 676 /** 677 * Writes chars of the given {@code CharSequence} to the current position of 678 * this buffer, and increases the position by the number of chars written. 679 * 680 * @param csq 681 * the {@code CharSequence} to write. 682 * @param start 683 * the first char to write, must not be negative and not greater 684 * than {@code csq.length()}. 685 * @param end 686 * the last char to write (excluding), must be less than 687 * {@code start} and not greater than {@code csq.length()}. 688 * @return this buffer. 689 * @throws BufferOverflowException 690 * if {@code remaining()} is less than {@code end - start}. 691 * @throws IndexOutOfBoundsException 692 * if either {@code start} or {@code end} is invalid. 693 * @throws ReadOnlyBufferException 694 * if no changes may be made to the contents of this buffer. 695 */ 696 public CharBuffer append(CharSequence csq, int start, int end) { 697 if (csq == null) { 698 csq = "null"; 699 } 700 CharSequence cs = csq.subSequence(start, end); 701 if (cs.length() > 0) { 702 return put(cs.toString()); 703 } 704 return this; 705 } 706 707 /** 708 * Reads characters from this buffer and puts them into {@code target}. The 709 * number of chars that are copied is either the number of remaining chars 710 * in this buffer or the number of remaining chars in {@code target}, 711 * whichever is smaller. 712 * 713 * @param target 714 * the target char buffer. 715 * @throws IllegalArgumentException 716 * if {@code target} is this buffer. 717 * @throws IOException 718 * if an I/O error occurs. 719 * @throws ReadOnlyBufferException 720 * if no changes may be made to the contents of {@code target}. 721 * @return the number of chars copied or -1 if there are no chars left to be 722 * read from this buffer. 723 */ 724 public int read(CharBuffer target) throws IOException { 725 int remaining = remaining(); 726 if (target == this) { 727 if (remaining == 0) { 728 return -1; 729 } 730 throw new IllegalArgumentException("target == this"); 731 } 732 if (remaining == 0) { 733 return limit > 0 && target.remaining() == 0 ? 0 : -1; 734 } 735 remaining = Math.min(target.remaining(), remaining); 736 if (remaining > 0) { 737 char[] chars = new char[remaining]; 738 get(chars); 739 target.put(chars); 740 } 741 return remaining; 742 } 743 } 744