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 */ 016package org.joda.primitives.list.impl; 017 018import 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 */ 029public 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}