package java.lang; import sun.misc.ConstantLengthCharSequence; /** * ArrayCharSequence is a simple {@link CharSequence} implementation based on the * primitive character array. It represents a view of the underlying sub-array * bounded by {@code offset} and {@code length}. * The underlying array can not be mutated through the ArrayCharSequence, * but direct changes to the underlying array are visible through the ArrayCharSequence. * ArrayCharSequence is not {@link java.io.Serializable}. * * @since 1.9 */ public final class ArrayCharSequence implements CharSequence, ConstantLengthCharSequence { private final char[] chars; private final int offset, length; /** * Constructs an {@code ArrayCharSequence} representing the view of the * characters of the given {@code chars} array. Any changes to the * array are visible through the sequence, but the array can not be modified * through the sequence. * * @param chars the character array to construct the sequence with * @throws NullPointerException if given {@code chars} array is {@code null} */ public ArrayCharSequence(char[] chars) { this(chars, 0, chars.length, true); } /** * Constructs an {@code ArrayCharSequence} representing the sub-array view of * the given {@code chars} array. The sequence starts with the {@code char} * value at the specified index and ends with the {@code char} value at index * {@code end - 1}. The length (in {@code char}s) of the constructed sequence * is {@code end - start}, so if {@code start == end} then constructed sequence * is empty. Any changes to the given {@code chars} array that pertain to the * represented range are visible through the sequence, but the array can not * be modified through the sequence. * * @param chars the character array to construct the sequence with * @param start the start index, inclusive * @param end the end index, exclusive * @throws NullPointerException if given {@code chars} array is {@code null} * @throws IndexOutOfBoundsException if {@code start} or {@code end} are negative, * if {@code end} is greater than * {@code chars.length}, or if {@code start} * is greater than {@code end} */ public ArrayCharSequence(char[] chars, int start, int end) { this(chars, checkSubSequenceIndexReturnStart(start, end, chars.length), end - start, true); } /** * Constructs an {@code ArrayCharSequence} representing the * characters of the given {@code string}. The constructed sequence may * share the character storage with the given {@code string}. * * @param string the {@code String} to construct the sequence from * @throws NullPointerException if given {@code string} is {@code null} */ public ArrayCharSequence(String string) { this(string.getCharsShared(), 0, string.length(), true); } /** * Constructs an {@code ArrayCharSequence} representing the sub-sequence of * the given {@code string}. The sequence starts with the {@code char} * value at the specified index and ends with the {@code char} value at index * {@code end - 1}. The length (in {@code char}s) of the constructed sequence * is {@code end - start}, so if {@code start == end} then constructed sequence * is empty. The constructed sequence may share the character storage with * the given {@code string}. * * @param string the {@code String} to construct the sequence from * @param start the start index, inclusive * @param end the end index, exclusive * @throws NullPointerException if given {@code chars} array is {@code null} * @throws IndexOutOfBoundsException if {@code start} or {@code end} are negative, * if {@code end} is greater than * {@code string.length()}, or if {@code start} * is greater than {@code end} */ public ArrayCharSequence(String string, int start, int end) { this(string.getCharsShared(), checkSubSequenceIndexReturnStart(start, end, string.length()), end - start, true); } // designated unchecked constructor private ArrayCharSequence(char[] chars, int offset, int length, boolean unchecked) { this.chars = chars; this.offset = offset; this.length = length; } /** * @inheritDoc */ @Override public int length() { return length; } /** * @inheritDoc */ @Override public char charAt(int index) { if (index < 0 || index >= length) { throw new IndexOutOfBoundsException("index: " + index); } return chars[offset + index]; } /** * Returns an {@code ArrayCharSequence} that is a subsequence of this sequence. * The subsequence starts with the {@code char} value at the specified index and * ends with the {@code char} value at index {@code end - 1}. The length * (in {@code char}s) of the * returned sequence is {@code end - start}, so if {@code start == end} * then an empty sequence is returned. *

* The returned {@code ArrayCharSequence} * represents a subsequence view of this sequence, so any changes to the * underlying array of this sequence that pertain to the range of the returned * sub-sequence are also visible in the returned sub-sequence. * * @param start the start index, inclusive * @param end the end index, exclusive * @return the specified subsequence * @throws IndexOutOfBoundsException if {@code start} or {@code end} are negative, * if {@code end} is greater than {@code length()}, * or if {@code start} is greater than {@code end} * @implSpec The returned {@code ArrayCharSequence} shares the underlying character storage * with this sequence and is obtainable in constant time. It is therefore advisable * to use it only as intermediate result of some computation that is not * retained for extended period of time, to allow the underlying shared character * storage to be reclaimed. */ @Override public ArrayCharSequence subSequence(int start, int end) { checkSubSequenceIndexReturnStart(start, end, length); if (start == 0 && end == length) { return this; } else { return new ArrayCharSequence(chars, offset + start, end - start); } } /** * Copies characters from this {@code ArrayCharSequence} into the * destination character array. *

* The first character to be copied is at index {@code srcBegin}; * the last character to be copied is at index {@code srcEnd-1} * (thus the total number of characters to be copied is * {@code srcEnd-srcBegin}). The characters are copied into the * subarray of {@code dst} starting at index {@code dstBegin} * and ending at index: *

     *     dstBegin + (srcEnd-srcBegin) - 1
     * 
* * @param srcBegin index of the first character in the sequence * to copy. * @param srcEnd index after the last character in the sequence * to copy. * @param dst the destination array. * @param dstBegin the start offset in the destination array. * @throws IndexOutOfBoundsException If any of the following * is true: * */ public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { if (srcBegin < 0) { throw new IndexOutOfBoundsException("srcBegin: " + srcBegin); } if (srcEnd > length) { throw new IndexOutOfBoundsException("srcEnd: " + srcEnd); } if (srcBegin > srcEnd) { throw new IndexOutOfBoundsException("srcBegin: " + srcBegin + " > srcEnd: " + srcEnd); } System.arraycopy(chars, offset + srcBegin, dst, dstBegin, srcEnd - srcBegin); } /** * Returns a string containing the characters in this sequence in the same * order as this sequence. The length of the string will be the length of * this sequence. * * @return a string consisting of exactly this sequence of characters */ @Override public String toString() { return new String(chars, offset, length); } // common subSequence arguments checking method private static int checkSubSequenceIndexReturnStart(int start, int end, int length) { if (start < 0 || end < 0 || start > end || end > length) { throw new IndexOutOfBoundsException("start: " + start + ", end: " + end); } return start; } }