1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.commons.csv;
21
22 /**
23 * A simple StringBuffer replacement that aims to reduce copying as much as possible.
24 * The buffer grows as necessary. This class is not thread safe.
25 *
26 * @author Ortwin Glück
27 */
28 class CharBuffer {
29
30 private char[] c;
31
32 /**
33 * Actually used number of characters in the array.
34 * It is also the index at which a new character will be inserted into <code>c</code>.
35 */
36 private int length;
37
38 /**
39 * Creates a new CharBuffer with an initial capacity of 32 characters.
40 */
41 CharBuffer() {
42 this(32);
43 }
44
45 /**
46 * Creates a new CharBuffer with an initial capacity
47 * of <code>length</code> characters.
48 */
49 CharBuffer(final int length) {
50 if (length == 0) {
51 throw new IllegalArgumentException("Can't create an empty CharBuffer");
52 }
53 this.c = new char[length];
54 }
55
56 /**
57 * Empties the buffer. The capacity still remains the same, so no memory is freed.
58 */
59 void clear() {
60 length = 0;
61 }
62
63 /**
64 * Returns the number of characters in the buffer.
65 *
66 * @return the number of characters
67 */
68 int length() {
69 return length;
70 }
71
72 /**
73 * Returns the current capacity of the buffer.
74 *
75 * @return the maximum number of characters that can be stored in this buffer without resizing it.
76 */
77 int capacity() {
78 return c.length;
79 }
80
81
82 /**
83 * Appends the contents of <code>cb</code> to the end of this CharBuffer.
84 *
85 * @param cb the CharBuffer to append or null
86 */
87 void append(final CharBuffer cb) {
88 if (cb == null) {
89 return;
90 }
91 provideCapacity(length + cb.length);
92 System.arraycopy(cb.c, 0, c, length, cb.length);
93 length += cb.length;
94 }
95
96 /**
97 * Appends <code>s</code> to the end of this CharBuffer.
98 * This method involves copying the new data once!
99 *
100 * @param s the String to append or null
101 */
102 void append(final String s) {
103 if (s == null) {
104 return;
105 }
106 append(s.toCharArray());
107 }
108
109 /**
110 * Appends <code>data</code> to the end of this CharBuffer.
111 * This method involves copying the new data once!
112 *
113 * @param data the char[] to append or null
114 */
115 void append(final char[] data) {
116 if (data == null) {
117 return;
118 }
119 provideCapacity(length + data.length);
120 System.arraycopy(data, 0, c, length, data.length);
121 length += data.length;
122 }
123
124 /**
125 * Appends a single character to the end of this CharBuffer.
126 * This method involves copying the new data once!
127 *
128 * @param data the char to append
129 */
130 void append(final char data) {
131 provideCapacity(length + 1);
132 c[length] = data;
133 length++;
134 }
135
136 /**
137 * Shrinks the capacity of the buffer to the current length if necessary.
138 * This method involves copying the data once!
139 */
140 void shrink() {
141 if (c.length == length) {
142 return;
143 }
144 char[] newc = new char[length];
145 System.arraycopy(c, 0, newc, 0, length);
146 c = newc;
147 }
148
149 /**
150 * Removes trailing whitespace.
151 */
152 void trimTrailingWhitespace() {
153 while (length > 0 && Character.isWhitespace(c[length - 1])) {
154 length--;
155 }
156 }
157
158 /**
159 * Returns the contents of the buffer as a char[]. The returned array may
160 * be the internal array of the buffer, so the caller must take care when
161 * modifying it.
162 * This method allows to avoid copying if the caller knows the exact capacity
163 * before.
164 *
165 * @return
166 */
167 char[] getCharacters() {
168 if (c.length == length) {
169 return c;
170 }
171 char[] chars = new char[length];
172 System.arraycopy(c, 0, chars, 0, length);
173 return chars;
174 }
175
176 /**
177 * Returns the character at the specified position.
178 */
179 char charAt(int pos) {
180 return c[pos];
181 }
182
183 /**
184 * Converts the contents of the buffer into a StringBuffer.
185 * This method involves copying the new data once!
186 *
187 * @return the contents of the character buffer as a String
188 */
189 @Override
190 public String toString() {
191 return new String(c, 0, length);
192 }
193
194 /**
195 * Copies the data into a new array of at least <code>capacity</code> size.
196 *
197 * @param capacity
198 */
199 void provideCapacity(final int capacity) {
200 if (c.length >= capacity) {
201 return;
202 }
203 int newcapacity = ((capacity * 3) >> 1) + 1;
204 char[] newc = new char[newcapacity];
205 System.arraycopy(c, 0, newc, 0, length);
206 c = newc;
207 }
208 }