View Javadoc
1   /*
2    * Copyright 2013 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.util.internal;
17  
18  
19  import java.util.Arrays;
20  
21  public final class AppendableCharSequence implements CharSequence, Appendable {
22      private char[] chars;
23      private int pos;
24  
25      public AppendableCharSequence(int length) {
26          if (length < 1) {
27              throw new IllegalArgumentException("length: " + length + " (length: >= 1)");
28          }
29          chars = new char[length];
30      }
31  
32      private AppendableCharSequence(char[] chars) {
33          this.chars = chars;
34          pos = chars.length;
35      }
36  
37      @Override
38      public int length() {
39          return pos;
40      }
41  
42      @Override
43      public char charAt(int index) {
44          if (index > pos) {
45              throw new IndexOutOfBoundsException();
46          }
47          return chars[index];
48      }
49  
50      @Override
51      public AppendableCharSequence subSequence(int start, int end) {
52          return new AppendableCharSequence(Arrays.copyOfRange(chars, start, end));
53      }
54  
55      @Override
56      public AppendableCharSequence append(char c) {
57          if (pos == chars.length) {
58              char[] old = chars;
59              // double it
60              int len = old.length << 1;
61              if (len < 0) {
62                  throw new IllegalStateException();
63              }
64              chars = new char[len];
65              System.arraycopy(old, 0, chars, 0, old.length);
66          }
67          chars[pos++] = c;
68          return this;
69      }
70  
71      @Override
72      public AppendableCharSequence append(CharSequence csq) {
73          return append(csq, 0, csq.length());
74      }
75  
76      @Override
77      public AppendableCharSequence append(CharSequence csq, int start, int end) {
78          if (csq.length() < end) {
79              throw new IndexOutOfBoundsException();
80          }
81          int length = end - start;
82          if (length > chars.length - pos) {
83              chars = expand(chars, pos + length, pos);
84          }
85          if (csq instanceof AppendableCharSequence) {
86              // Optimize append operations via array copy
87              AppendableCharSequence seq = (AppendableCharSequence) csq;
88              char[] src = seq.chars;
89              System.arraycopy(src, start, chars, pos, length);
90              pos += length;
91              return this;
92          }
93          for (int i = start; i < end; i++) {
94              chars[pos++] = csq.charAt(i);
95          }
96  
97          return this;
98      }
99  
100     /**
101      * Reset the {@link AppendableCharSequence}. Be aware this will only reset the current internal position and not
102      * shrink the internal char array.
103      */
104     public void reset() {
105         pos = 0;
106     }
107 
108     @Override
109     public String toString() {
110         return new String(chars, 0, pos);
111     }
112 
113     /**
114      * Create a new {@link String} from the given start to end.
115      */
116     public String substring(int start, int end) {
117         int length = end - start;
118         if (start > pos || length > pos) {
119             throw new IndexOutOfBoundsException();
120         }
121         return new String(chars, start, length);
122     }
123 
124     private static char[] expand(char[] array, int neededSpace, int size) {
125         int newCapacity = array.length;
126         do {
127             // double capacity until it is big enough
128             newCapacity <<= 1;
129 
130             if (newCapacity < 0) {
131                 throw new IllegalStateException();
132             }
133 
134         } while (neededSpace > newCapacity);
135 
136         char[] newArray = new char[newCapacity];
137         System.arraycopy(array, 0, newArray, 0, size);
138 
139         return newArray;
140     }
141 }