001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     * http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.commons.csv;
020    
021    /**
022     * A simple StringBuffer replacement that aims to
023     * reduce copying as much as possible. The buffer
024     * grows as necessary.
025     * This class is not thread safe.
026     *
027     * @author Ortwin Gl???ck
028     */
029    public class CharBuffer {
030    
031        private char[] c;
032    
033        /**
034         * Actually used number of characters in the array.
035         * It is also the index at which
036         * a new character will be inserted into <code>c</code>.
037         */
038        private int length;
039    
040        /**
041         * Creates a new CharBuffer with an initial capacity of 32 characters.
042         */
043        public CharBuffer() {
044            this(32);
045        }
046    
047        /**
048         * Creates a new CharBuffer with an initial capacity
049         * of <code>length</code> characters.
050         */
051        public CharBuffer(final int length) {
052            if (length == 0) {
053                throw new IllegalArgumentException("Can't create an empty CharBuffer");
054            }
055            this.c = new char[length];
056        }
057    
058        /**
059         * Empties the buffer. The capacity still remains the same, so no memory is freed.
060         */
061        public void clear() {
062            length = 0;
063        }
064    
065        /**
066         * Returns the number of characters in the buffer.
067         *
068         * @return the number of characters
069         */
070        public int length() {
071            return length;
072        }
073    
074        /**
075         * Returns the current capacity of the buffer.
076         *
077         * @return the maximum number of characters that can be stored in this buffer without
078         *         resizing it.
079         */
080        public int capacity() {
081            return c.length;
082        }
083    
084    
085        /**
086         * Appends the contents of <code>cb</code> to the end of this CharBuffer.
087         *
088         * @param cb the CharBuffer to append or null
089         */
090        public void append(final CharBuffer cb) {
091            if (cb == null) {
092                return;
093            }
094            provideCapacity(length + cb.length);
095            System.arraycopy(cb.c, 0, c, length, cb.length);
096            length += cb.length;
097        }
098    
099        /**
100         * Appends <code>s</code> to the end of this CharBuffer.
101         * This method involves copying the new data once!
102         *
103         * @param s the String to append or null
104         */
105        public void append(final String s) {
106            if (s == null) {
107                return;
108            }
109            append(s.toCharArray());
110        }
111    
112        /**
113         * Appends <code>sb</code> to the end of this CharBuffer.
114         * This method involves copying the new data once!
115         *
116         * @param sb the StringBuffer to append or null
117         */
118        public void append(final StringBuffer sb) {
119            if (sb == null) {
120                return;
121            }
122            provideCapacity(length + sb.length());
123            sb.getChars(0, sb.length(), c, length);
124            length += sb.length();
125        }
126    
127        /**
128         * Appends <code>data</code> to the end of this CharBuffer.
129         * This method involves copying the new data once!
130         *
131         * @param data the char[] to append or null
132         */
133        public void append(final char[] data) {
134            if (data == null) {
135                return;
136            }
137            provideCapacity(length + data.length);
138            System.arraycopy(data, 0, c, length, data.length);
139            length += data.length;
140        }
141    
142        /**
143         * Appends a single character to the end of this CharBuffer.
144         * This method involves copying the new data once!
145         *
146         * @param data the char to append
147         */
148        public void append(final char data) {
149            provideCapacity(length + 1);
150            c[length] = data;
151            length++;
152        }
153    
154        /**
155         * Shrinks the capacity of the buffer to the current length if necessary.
156         * This method involves copying the data once!
157         */
158        public void shrink() {
159            if (c.length == length) {
160                return;
161            }
162            char[] newc = new char[length];
163            System.arraycopy(c, 0, newc, 0, length);
164            c = newc;
165        }
166    
167        /**
168         * Removes trailing whitespace.
169         */
170        public void trimTrailingWhitespace() {
171            while (length > 0 && Character.isWhitespace(c[length - 1])) {
172                length--;
173            }
174        }
175    
176        /**
177         * Returns the contents of the buffer as a char[]. The returned array may
178         * be the internal array of the buffer, so the caller must take care when
179         * modifying it.
180         * This method allows to avoid copying if the caller knows the exact capacity
181         * before.
182         *
183         * @return
184         */
185        public char[] getCharacters() {
186            if (c.length == length) {
187                return c;
188            }
189            char[] chars = new char[length];
190            System.arraycopy(c, 0, chars, 0, length);
191            return chars;
192        }
193    
194        /**
195         * Returns the character at the specified position.
196         */
197        public char charAt(int pos) {
198            return c[pos];
199        }
200    
201        /**
202         * Converts the contents of the buffer into a StringBuffer.
203         * This method involves copying the new data once!
204         *
205         * @return
206         */
207        public StringBuffer toStringBuffer() {
208            StringBuffer sb = new StringBuffer(length);
209            sb.append(c, 0, length);
210            return sb;
211        }
212    
213        /**
214         * Converts the contents of the buffer into a StringBuffer.
215         * This method involves copying the new data once!
216         *
217         * @return
218         */
219        public String toString() {
220            return new String(c, 0, length);
221        }
222    
223        /**
224         * Copies the data into a new array of at least <code>capacity</code> size.
225         *
226         * @param capacity
227         */
228        public void provideCapacity(final int capacity) {
229            if (c.length >= capacity) {
230                return;
231            }
232            int newcapacity = ((capacity * 3) >> 1) + 1;
233            char[] newc = new char[newcapacity];
234            System.arraycopy(c, 0, newc, 0, length);
235            c = newc;
236        }
237    }