1 package java.lang;
   2 
   3 import sun.misc.ConstantLengthCharSequence;
   4 
   5 /**
   6  * ArrayCharSequence is a simple {@link CharSequence} implementation based on the
   7  * primitive character array. It represents a view of the underlying sub-array
   8  * bounded by {@code offset} and {@code length}.
   9  * The underlying array can not be mutated through the ArrayCharSequence,
  10  * but direct changes to the underlying array are visible through the ArrayCharSequence.
  11  * ArrayCharSequence is not {@link java.io.Serializable}.
  12  *
  13  * @since 1.9
  14  */
  15 public final class ArrayCharSequence implements CharSequence, ConstantLengthCharSequence {
  16     private final char[] chars;
  17     private final int offset, length;
  18 
  19     /**
  20      * Constructs an {@code ArrayCharSequence} representing the view of the
  21      * characters of the given {@code chars} array. Any changes to the
  22      * array are visible through the sequence, but the array can not be modified
  23      * through the sequence.
  24      *
  25      * @param chars the character array to construct the sequence with
  26      * @throws NullPointerException if given {@code chars} array is {@code null}
  27      */
  28     public ArrayCharSequence(char[] chars) {
  29         this(chars, 0, chars.length, true);
  30     }
  31 
  32     /**
  33      * Constructs an {@code ArrayCharSequence} representing the sub-array view of
  34      * the given {@code chars} array. The sequence starts with the {@code char}
  35      * value at the specified index and ends with the {@code char} value at index
  36      * {@code end - 1}.  The length (in {@code char}s) of the constructed sequence
  37      * is {@code end - start}, so if {@code start == end} then constructed sequence
  38      * is empty. Any changes to the given {@code chars} array that pertain to the
  39      * represented range are visible through the sequence, but the array can not
  40      * be modified through the sequence.
  41      *
  42      * @param chars the character array to construct the sequence with
  43      * @param start the start index, inclusive
  44      * @param end   the end index, exclusive
  45      * @throws NullPointerException      if given {@code chars} array is {@code null}
  46      * @throws IndexOutOfBoundsException if {@code start} or {@code end} are negative,
  47      *                                   if {@code end} is greater than
  48      *                                   {@code chars.length}, or if {@code start}
  49      *                                   is greater than {@code end}
  50      */
  51     public ArrayCharSequence(char[] chars, int start, int end) {
  52         this(chars,
  53              checkSubSequenceIndexReturnStart(start, end, chars.length),
  54              end - start, true);
  55     }
  56 
  57     /**
  58      * Constructs an {@code ArrayCharSequence} representing the
  59      * characters of the given {@code string}. The constructed sequence may
  60      * share the character storage with the given {@code string}.
  61      *
  62      * @param string the {@code String} to construct the sequence from
  63      * @throws NullPointerException if given {@code string} is {@code null}
  64      */
  65     public ArrayCharSequence(String string) {
  66         this(string.getCharsShared(), 0, string.length(), true);
  67     }
  68 
  69     /**
  70      * Constructs an {@code ArrayCharSequence} representing the sub-sequence of
  71      * the given {@code string}. The sequence starts with the {@code char}
  72      * value at the specified index and ends with the {@code char} value at index
  73      * {@code end - 1}.  The length (in {@code char}s) of the constructed sequence
  74      * is {@code end - start}, so if {@code start == end} then constructed sequence
  75      * is empty. The constructed sequence may share the character storage with
  76      * the given {@code string}.
  77      *
  78      * @param string the {@code String} to construct the sequence from
  79      * @param start  the start index, inclusive
  80      * @param end    the end index, exclusive
  81      * @throws NullPointerException      if given {@code chars} array is {@code null}
  82      * @throws IndexOutOfBoundsException if {@code start} or {@code end} are negative,
  83      *                                   if {@code end} is greater than
  84      *                                   {@code string.length()}, or if {@code start}
  85      *                                   is greater than {@code end}
  86      */
  87     public ArrayCharSequence(String string, int start, int end) {
  88         this(string.getCharsShared(),
  89              checkSubSequenceIndexReturnStart(start, end, string.length()),
  90              end - start, true);
  91     }
  92 
  93     // designated unchecked constructor
  94     private ArrayCharSequence(char[] chars, int offset, int length, boolean unchecked) {
  95         this.chars = chars;
  96         this.offset = offset;
  97         this.length = length;
  98     }
  99 
 100     /**
 101      * @inheritDoc
 102      */
 103     @Override
 104     public int length() {
 105         return length;
 106     }
 107 
 108     /**
 109      * @inheritDoc
 110      */
 111     @Override
 112     public char charAt(int index) {
 113         if (index < 0 || index >= length) {
 114             throw new IndexOutOfBoundsException("index: " + index);
 115         }
 116         return chars[offset + index];
 117     }
 118 
 119     /**
 120      * Returns an {@code ArrayCharSequence} that is a subsequence of this sequence.
 121      * The subsequence starts with the {@code char} value at the specified index and
 122      * ends with the {@code char} value at index {@code end - 1}.  The length
 123      * (in {@code char}s) of the
 124      * returned sequence is {@code end - start}, so if {@code start == end}
 125      * then an empty sequence is returned.
 126      * <p>
 127      * The returned {@code ArrayCharSequence}
 128      * represents a subsequence view of this sequence, so any changes to the
 129      * underlying array of this sequence that pertain to the range of the returned
 130      * sub-sequence are also visible in the returned sub-sequence.
 131      *
 132      * @param start the start index, inclusive
 133      * @param end   the end index, exclusive
 134      * @return the specified subsequence
 135      * @throws IndexOutOfBoundsException if {@code start} or {@code end} are negative,
 136      *                                   if {@code end} is greater than {@code length()},
 137      *                                   or if {@code start} is greater than {@code end}
 138      * @implSpec The returned {@code ArrayCharSequence} shares the underlying character storage
 139      * with this sequence and is obtainable in constant time. It is therefore advisable
 140      * to use it only as intermediate result of some computation that is not
 141      * retained for extended period of time, to allow the underlying shared character
 142      * storage to be reclaimed.
 143      */
 144     @Override
 145     public ArrayCharSequence subSequence(int start, int end) {
 146         checkSubSequenceIndexReturnStart(start, end, length);
 147         if (start == 0 && end == length) {
 148             return this;
 149         } else {
 150             return new ArrayCharSequence(chars, offset + start, end - start);
 151         }
 152     }
 153 
 154     /**
 155      * Copies characters from this {@code ArrayCharSequence} into the
 156      * destination character array.
 157      * <p>
 158      * The first character to be copied is at index {@code srcBegin};
 159      * the last character to be copied is at index {@code srcEnd-1}
 160      * (thus the total number of characters to be copied is
 161      * {@code srcEnd-srcBegin}). The characters are copied into the
 162      * subarray of {@code dst} starting at index {@code dstBegin}
 163      * and ending at index:
 164      * <blockquote><pre>
 165      *     dstBegin + (srcEnd-srcBegin) - 1
 166      * </pre></blockquote>
 167      *
 168      * @param srcBegin index of the first character in the sequence
 169      *                 to copy.
 170      * @param srcEnd   index after the last character in the sequence
 171      *                 to copy.
 172      * @param dst      the destination array.
 173      * @param dstBegin the start offset in the destination array.
 174      * @throws IndexOutOfBoundsException If any of the following
 175      *                                   is true:
 176      *                                   <ul><li>{@code srcBegin} is negative.
 177      *                                   <li>{@code srcBegin} is greater than {@code srcEnd}
 178      *                                   <li>{@code srcEnd} is greater than the length of this
 179      *                                   sequence
 180      *                                   <li>{@code dstBegin} is negative
 181      *                                   <li>{@code dstBegin+(srcEnd-srcBegin)} is larger than
 182      *                                   {@code dst.length}</ul>
 183      */
 184     public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
 185         if (srcBegin < 0) {
 186             throw new IndexOutOfBoundsException("srcBegin: " + srcBegin);
 187         }
 188         if (srcEnd > length) {
 189             throw new IndexOutOfBoundsException("srcEnd: " + srcEnd);
 190         }
 191         if (srcBegin > srcEnd) {
 192             throw new IndexOutOfBoundsException("srcBegin: " + srcBegin +
 193                                                 " > srcEnd: " + srcEnd);
 194         }
 195         System.arraycopy(chars, offset + srcBegin, dst, dstBegin, srcEnd - srcBegin);
 196     }
 197 
 198     /**
 199      * Returns a string containing the characters in this sequence in the same
 200      * order as this sequence.  The length of the string will be the length of
 201      * this sequence.
 202      *
 203      * @return a string consisting of exactly this sequence of characters
 204      */
 205     @Override
 206     public String toString() {
 207         return new String(chars, offset, length);
 208     }
 209 
 210     // common subSequence arguments checking method
 211     private static int checkSubSequenceIndexReturnStart(int start, int end, int length) {
 212         if (start < 0 || end < 0 || start > end || end > length) {
 213             throw new IndexOutOfBoundsException("start: " + start + ", end: " + end);
 214         }
 215         return start;
 216     }
 217 }