001 /*
002 * Copyright 2001-2010 Stephen Colebourne
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.joda.primitives.list.impl;
017
018 import org.joda.primitives.list.CharList;
019
020 /**
021 * CharList implementation that uses a StringBuffer internally.
022 * <p>
023 * This class implements {@link java.util.List List} allowing
024 * seamless integration with other APIs.
025 *
026 * @author Stephen Colebourne
027 * @since 1.0
028 */
029 public class StringBufferCharList extends AbstractCharList {
030
031 /** The String being wrapped */
032 protected final StringBuffer stringBuffer;
033
034 /**
035 * Decorates the specified string buffer with a StringBufferCharList.
036 * <p>
037 * The specified buffer is used as the datasource, so changes to one
038 * will affect the other.
039 *
040 * @param buf the string buffer to decorate, must not be null
041 * @return the new StringBufferCharList
042 * @throws IllegalArgumentException if the string is null
043 */
044 public static StringBufferCharList decorate(StringBuffer buf) {
045 if (buf == null) {
046 throw new IllegalArgumentException("StringBuffer must not be null");
047 }
048 return new StringBufferCharList(buf);
049 }
050
051 //-----------------------------------------------------------------------
052 /**
053 * Constructor that uses an empty string as the datasource.
054 */
055 public StringBufferCharList() {
056 super();
057 this.stringBuffer = new StringBuffer();
058 }
059
060 /**
061 * Constructor that copies the specified list.
062 *
063 * @param list the list to copy, must not be null
064 * @throws IllegalArgumentException if the list is null
065 */
066 public StringBufferCharList(CharList list) {
067 super();
068 if (list == null) {
069 throw new IllegalArgumentException("List must not be null");
070 }
071 this.stringBuffer = new StringBuffer(list.size());
072 this.stringBuffer.append(list.toCharArray());
073 }
074
075 /**
076 * Constructor that copies the specified string.
077 *
078 * @param str the string to copy, must not be null
079 * @throws IllegalArgumentException if the string is null
080 */
081 public StringBufferCharList(String str) {
082 super();
083 if (str == null) {
084 throw new IllegalArgumentException("String must not be null");
085 }
086 this.stringBuffer = new StringBuffer(str);
087 }
088
089 /**
090 * Constructor that <i>decorates</i> the specified string buffer.
091 *
092 * @param buf the string buffer to decorate, must not be null
093 * @throws IllegalArgumentException if the string is null
094 */
095 protected StringBufferCharList(StringBuffer buf) {
096 super();
097 if (buf == null) {
098 throw new IllegalArgumentException("StringBuffer must not be null");
099 }
100 this.stringBuffer = buf;
101 }
102
103 // Implementation
104 //-----------------------------------------------------------------------
105 /**
106 * Gets the character at the specified index.
107 *
108 * @param index the index to retrieve
109 * @return the character at the specified index
110 */
111 public char getChar(int index) {
112 checkIndexExists(index);
113 return stringBuffer.charAt(index);
114 }
115
116 /**
117 * Gets the size of the list, which is the string length.
118 *
119 * @return the string length
120 */
121 public int size() {
122 return stringBuffer.length();
123 }
124
125 /**
126 * Adds a primitive value to this list at an index.
127 *
128 * @param index the index to add at
129 * @param value the value to add to this collection
130 * @return <code>true</code> if this list was modified by this method call
131 * @throws IndexOutOfBoundsException if the index is invalid
132 */
133 public boolean add(int index, char value) {
134 checkAddModifiable();
135 checkIndex(index);
136 stringBuffer.insert(index, value);
137 return true;
138 }
139
140 /**
141 * Removes a primitive value by index from the list.
142 *
143 * @param index the index to remove from
144 * @return the primitive value previously at this index
145 * @throws IndexOutOfBoundsException if the index is invalid
146 */
147 public char removeIndex(int index) {
148 checkRemoveModifiable();
149 checkIndexExists(index);
150 char old = stringBuffer.charAt(index);
151 stringBuffer.deleteCharAt(index);
152 return old;
153 }
154
155 /**
156 * Sets the primitive value at a specified index.
157 * <p>
158 * This implementation throws UnsupportedOperationException.
159 *
160 * @param index the index to set
161 * @param value the value to store
162 * @return the previous value at the index
163 * @throws IndexOutOfBoundsException if the index is invalid
164 */
165 public char set(int index, char value) {
166 checkSetModifiable();
167 checkIndexExists(index);
168 char old = stringBuffer.charAt(index);
169 stringBuffer.setCharAt(index, value);
170 return old;
171 }
172
173 /**
174 * Are the add methods supported.
175 *
176 * @return true
177 */
178 protected boolean isAddModifiable() {
179 return true;
180 }
181
182 /**
183 * Are the remove methods supported.
184 *
185 * @return true
186 */
187 protected boolean isRemoveModifiable() {
188 return true;
189 }
190
191 /**
192 * Are the set methods supported.
193 *
194 * @return true
195 */
196 protected boolean isSetModifiable() {
197 return true;
198 }
199
200 /**
201 * Is the collection modifiable in any way.
202 *
203 * @return true if supported
204 */
205 public boolean isModifiable() {
206 return true;
207 }
208
209 // Optimisation
210 //-----------------------------------------------------------------------
211 /**
212 * Adds a primitive value to this collection.
213 *
214 * @param value the value to add to this collection
215 * @return <code>true</code> if this collection was modified by this method call
216 */
217 public boolean add(char value) {
218 checkAddModifiable();
219 stringBuffer.append(value);
220 return true;
221 }
222
223 /**
224 * Adds an array of primitive values to this list at an index.
225 *
226 * @param values the values to add to this collection, null treated as empty array
227 * @return <code>true</code> if this list was modified by this method call
228 * @throws IndexOutOfBoundsException if the index is invalid
229 */
230 public boolean addAll(char[] values) {
231 checkAddModifiable();
232 if (values == null || values.length == 0) {
233 return false;
234 }
235 stringBuffer.append(values);
236 return true;
237 }
238
239 /**
240 * Adds an array of primitive values to this list at an index.
241 *
242 * @param index the index to add at
243 * @param values the values to add to this collection, null treated as empty array
244 * @return <code>true</code> if this list was modified by this method call
245 * @throws IndexOutOfBoundsException if the index is invalid
246 */
247 public boolean addAll(int index, char[] values) {
248 checkAddModifiable();
249 checkIndex(index);
250 if (values == null || values.length == 0) {
251 return false;
252 }
253 stringBuffer.insert(index, values);
254 return true;
255 }
256
257 /**
258 * Removes a range of values from the list.
259 *
260 * @param fromIndexInclusive the start of the range to remove, inclusive
261 * @param toIndexExclusive the end of the range to remove, exclusive
262 * @return <code>true</code> if the collection was modified
263 */
264 public boolean removeRange(int fromIndexInclusive, int toIndexExclusive) {
265 checkRemoveModifiable();
266 checkRange(fromIndexInclusive, toIndexExclusive);
267 if (fromIndexInclusive == toIndexExclusive) {
268 return false;
269 }
270 stringBuffer.delete(fromIndexInclusive, toIndexExclusive);
271 return true;
272 }
273
274 /**
275 * Gets the String underlying the list.
276 *
277 * @return the underlying string, not null
278 */
279 public String toStringContents() {
280 return stringBuffer.substring(0, stringBuffer.length());
281 }
282
283 //-----------------------------------------------------------------------
284 /**
285 * Copies data from this collection into the specified array.
286 * This method is pre-validated.
287 *
288 * @param fromIndex the index to start from
289 * @param dest the destination array
290 * @param destIndex the destination start index
291 * @param size the number of items to copy
292 */
293 protected void arrayCopy(int fromIndex, char[] dest, int destIndex, int size) {
294 stringBuffer.getChars(fromIndex, fromIndex + size, dest, destIndex);
295 }
296
297 }