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.collection.impl; 017 018import java.util.Collection; 019import java.util.Iterator; 020import java.util.NoSuchElementException; 021 022import org.joda.primitives.IntUtils; 023import org.joda.primitives.collection.IntCollection; 024import org.joda.primitives.iterator.IntIterator; 025 026/** 027 * Array based implementation of <code>IntCollection</code> for 028 * primitive <code>int</code> elements. 029 * <p> 030 * This collection implementation allows multiple copies of the same value to be added. 031 * Internally, it uses an array, and behaves much like a list. 032 * <p> 033 * This class implements {@link java.util.Collection Collection} allowing 034 * seamless integration with other APIs. 035 * <p> 036 * Add, Remove and Clear are supported. 037 * 038 * @author Stephen Colebourne 039 * @author Jason Tiscione 040 * @version CODE GENERATED 041 * @since 1.0 042 */ 043public class ArrayIntCollection extends AbstractIntCollection implements Cloneable { 044 // This file is CODE GENERATED. Do not change manually. 045 046 /** The minimum size allowed when growth occurs */ 047 private static final int MIN_GROWTH_SIZE = 4; 048 /** The amount the collection grows by when resized (3/2) */ 049 private static final int GROWTH_FACTOR_MULTIPLIER = 3; 050 /** The amount the collection grows by when resized (3/2) */ 051 private static final int GROWTH_FACTOR_DIVISOR = 2; 052 053 /** The array of elements */ 054 private int[] data; 055 /** The current size */ 056 private int size; 057 058 /** 059 * Constructor. 060 */ 061 public ArrayIntCollection() { 062 super(); 063 data = IntUtils.EMPTY_INT_ARRAY; 064 } 065 066 /** 067 * Constructor that defines an initial size for the internal storage array. 068 * 069 * @param initialSize the initial size of the internal array, negative treated as zero 070 */ 071 public ArrayIntCollection(int initialSize) { 072 super(); 073 if (initialSize <= 0) { 074 data = IntUtils.EMPTY_INT_ARRAY; 075 } else { 076 data = new int[initialSize]; 077 } 078 } 079 080 /** 081 * Constructor that copies the specified values. 082 * 083 * @param values an array of values to copy, null treated as zero size array 084 */ 085 public ArrayIntCollection(int[] values) { 086 super(); 087 if (values == null) { 088 data = IntUtils.EMPTY_INT_ARRAY; 089 } else { 090 data = (int[]) values.clone(); 091 size = values.length; 092 } 093 } 094 095 /** 096 * Constructs a new collection by copying values from another collection. 097 * 098 * @param coll a collection of values to copy, null treated as zero size collection 099 */ 100 public ArrayIntCollection(Collection<?> coll) { 101 super(); 102 if (coll == null) { 103 data = IntUtils.EMPTY_INT_ARRAY; 104 } else if (coll instanceof IntCollection) { 105 IntCollection c = (IntCollection) coll; 106 size = c.size(); 107 data = new int[size]; 108 c.toIntArray(data, 0); 109 } else { 110 data = toPrimitiveArray(coll); 111 size = coll.size(); 112 } 113 } 114 115 /** 116 * Constructs a new collection by copying values from an iterator. 117 * 118 * @param it an iterator of values to extract, null treated as zero size collection 119 */ 120 public ArrayIntCollection(Iterator<Integer> it) { 121 super(); 122 if (it == null) { 123 data = IntUtils.EMPTY_INT_ARRAY; 124 } else if (it instanceof IntIterator) { 125 IntIterator typed = (IntIterator) it; 126 data = new int[MIN_GROWTH_SIZE]; 127 while (typed.hasNext()) { 128 add(typed.nextInt()); 129 } 130 } else { 131 data = new int[MIN_GROWTH_SIZE]; 132 while (it.hasNext()) { 133 add(it.next()); 134 } 135 } 136 } 137 138 // Implementation 139 //----------------------------------------------------------------------- 140 /** 141 * Gets the current size of the collection. 142 * 143 * @return the current size 144 */ 145 public int size() { 146 return size; 147 } 148 149 /** 150 * Gets an iterator over this collection capable of accessing the primitive values. 151 * 152 * @return an iterator over this collection 153 */ 154 public IntIterator iterator() { 155 return new PIterator(this); 156 } 157 158 /** 159 * Adds a primitive value to this collection. 160 * 161 * @param value the value to add to this collection 162 * @return <code>true</code> if this collection was modified by this method call 163 * @throws IllegalArgumentException if value is rejected by this collection 164 */ 165 public boolean add(int value) { 166 ensureCapacity(size + 1); 167 data[size++] = value; 168 return true; 169 } 170 171 // Overrides 172 //----------------------------------------------------------------------- 173 /** 174 * Optimizes the implementation. 175 * <p> 176 * This implementation changes the internal array to be the same size as 177 * the size of the collection. 178 */ 179 public void optimize() { 180 if (size < data.length) { 181 int[] array = new int[size]; 182 System.arraycopy(data, 0, array, 0, size); 183 data = array; 184 } 185 } 186 187 /** 188 * Are the add methods supported. 189 * 190 * @return <code>true</code> 191 */ 192 protected boolean isAddModifiable() { 193 return true; 194 } 195 196 /** 197 * Are the remove methods supported. 198 * 199 * @return <code>true</code> 200 */ 201 protected boolean isRemoveModifiable() { 202 return true; 203 } 204 205 /** 206 * Checks whether the object can currently be modified. 207 * 208 * @return <code>true</code> 209 */ 210 public boolean isModifiable() { 211 return true; 212 } 213 214 /** 215 * Checks whether this collection contains a specified primitive value. 216 * <p> 217 * This implementation uses the internal array directly. 218 * 219 * @param value the value to search for 220 * @return <code>true</code> if the value is found 221 */ 222 public boolean contains(int value) { 223 for (int i = 0; i < size; i++) { 224 if (data[i] == value) { 225 return true; 226 } 227 } 228 return false; 229 } 230 231 /** 232 * Clears the collection of all elements. 233 * The collection will have a zero size after this method completes. 234 * <p> 235 * This implementation resets the size, but does not reduce the internal storage array. 236 */ 237 public void clear() { 238 size = 0; 239 } 240 241 /** 242 * Adds an array of primitive values to this collection. 243 * 244 * @param values the values to add to this collection 245 * @return <code>true</code> if this collection was modified by this method call 246 */ 247 public boolean addAll(int[] values) { 248 checkAddModifiable(); 249 if (values == null || values.length == 0) { 250 return false; 251 } 252 return doAdd(0, values); 253 } 254 255 /** 256 * Adds a collection of primitive values to this collection. 257 * 258 * @param values the values to add to this collection, null treated as empty collection 259 * @return <code>true</code> if this collection was modified by this method call 260 */ 261 public boolean addAll(IntCollection values) { 262 checkAddModifiable(); 263 if (values == null || values.size() == 0) { 264 return false; 265 } 266 int len = values.size(); 267 ensureCapacity(size + len); 268 values.toIntArray(data, size); 269 size += len; 270 return true; 271 } 272 273 /** 274 * Adds a range of primitive values to this collection. 275 * <p> 276 * The range is defined to be inclusive of the start and end. 277 * If the start is greater than the end then the range is equivalent to an empty collection. 278 * 279 * @param startInclusive the inclusive range start value 280 * @param endInclusive the inclusive range end value 281 * @return <code>true</code> if this collection was modified by this method call 282 * @throws IllegalArgumentException if a value is rejected by this set 283 * @throws UnsupportedOperationException if not supported by this set 284 */ 285 public boolean addAll(int startInclusive, int endInclusive) { 286 int increase = endInclusive - startInclusive + 1; 287 if (increase < 0) { 288 return false; 289 } 290 ensureCapacity(size + increase); 291 int i = startInclusive; 292 while (i < endInclusive) { 293 data[size++] = i++; 294 } 295 data[size++] = i; // handles endInclusive=MAX_VALUE 296 return true; 297 } 298 299 /** 300 * Clone implementation that calls Object clone(). 301 * 302 * @return the clone 303 */ 304 public Object clone() { 305 ArrayIntCollection cloned = (ArrayIntCollection) super.clone(); 306 cloned.data = (int[]) data.clone(); 307 return cloned; 308 } 309 310 /** 311 * Copies data from this collection into the specified array. 312 * This method is pre-validated. 313 * 314 * @param fromIndex the index to start from 315 * @param dest the destination array 316 * @param destIndex the destination start index 317 * @param size the number of items to copy 318 */ 319 protected void arrayCopy(int fromIndex, int[] dest, int destIndex, int size) { 320 System.arraycopy(data, fromIndex, dest, destIndex, size); 321 } 322 323 // Internal implementation 324 //----------------------------------------------------------------------- 325 /** 326 * Internal implementation to add to this collection at the specified index. 327 * This method adjusts the capacity and size. 328 * 329 * @param index the index to add at, valid 330 * @param values the array to add, not null 331 * @return true if the array was updated 332 */ 333 protected boolean doAdd(int index, int[] values) { 334 int len = values.length; 335 ensureCapacity(size + len); 336 System.arraycopy(values, 0, data, size, len); 337 size += len; 338 return (len > 0); 339 } 340 341 /** 342 * Internal implementation to remove the element at the specified index. 343 * 344 * @param index the index, valid 345 */ 346 protected void doRemoveIndex(int index) { 347 System.arraycopy(data, index + 1, data, index, size - 1 - index); 348 size--; 349 } 350 351 /** 352 * Internal implementation to ensure that the internal storage array has 353 * at least the specified size. 354 * 355 * @param reqCapacity the amount to expand to 356 */ 357 protected void ensureCapacity(int reqCapacity) { 358 int curCapacity = data.length; 359 if (reqCapacity <= curCapacity) { 360 return; 361 } 362 int newCapacity = curCapacity * GROWTH_FACTOR_MULTIPLIER / GROWTH_FACTOR_DIVISOR; 363 if ((newCapacity - curCapacity) < MIN_GROWTH_SIZE) { 364 newCapacity = curCapacity + MIN_GROWTH_SIZE; 365 } 366 if (newCapacity < reqCapacity) { 367 newCapacity = reqCapacity; 368 } 369 int[] newArray = new int[newCapacity]; 370 System.arraycopy(data, 0, newArray, 0, curCapacity); 371 data = newArray; 372 } 373 374 // Iterator 375 //----------------------------------------------------------------------- 376 /** 377 * Iterator. 378 */ 379 protected static class PIterator implements IntIterator { 380 381 private final ArrayIntCollection collection; 382 private int cursor = 0; 383 private boolean canRemove = false; 384 385 protected PIterator(ArrayIntCollection coll) { 386 super(); 387 this.collection = coll; 388 } 389 390 public boolean hasNext() { 391 return (cursor < collection.size); 392 } 393 394 public int nextInt() { 395 if (hasNext() == false) { 396 throw new NoSuchElementException("No more elements available"); 397 } 398 canRemove = true; 399 return collection.data[cursor++]; 400 } 401 402 public Integer next() { 403 return collection.toObject(nextInt()); 404 } 405 406 public void remove() { 407 if (canRemove == false) { 408 throw new IllegalStateException("Element cannot be removed"); 409 } 410 collection.doRemoveIndex(--cursor); 411 canRemove = false; 412 } 413 414 public boolean isModifiable() { 415 return collection.isModifiable(); 416 } 417 418 public boolean isResettable() { 419 return true; 420 } 421 422 public void reset() { 423 cursor = 0; 424 } 425 } 426 427}