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.LongUtils; 023import org.joda.primitives.collection.LongCollection; 024import org.joda.primitives.iterator.LongIterator; 025 026/** 027 * Array based implementation of <code>LongCollection</code> for 028 * primitive <code>long</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 ArrayLongCollection extends AbstractLongCollection 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 long[] data; 055 /** The current size */ 056 private int size; 057 058 /** 059 * Constructor. 060 */ 061 public ArrayLongCollection() { 062 super(); 063 data = LongUtils.EMPTY_LONG_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 ArrayLongCollection(int initialSize) { 072 super(); 073 if (initialSize <= 0) { 074 data = LongUtils.EMPTY_LONG_ARRAY; 075 } else { 076 data = new long[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 ArrayLongCollection(long[] values) { 086 super(); 087 if (values == null) { 088 data = LongUtils.EMPTY_LONG_ARRAY; 089 } else { 090 data = (long[]) 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 ArrayLongCollection(Collection<?> coll) { 101 super(); 102 if (coll == null) { 103 data = LongUtils.EMPTY_LONG_ARRAY; 104 } else if (coll instanceof LongCollection) { 105 LongCollection c = (LongCollection) coll; 106 size = c.size(); 107 data = new long[size]; 108 c.toLongArray(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 ArrayLongCollection(Iterator<Long> it) { 121 super(); 122 if (it == null) { 123 data = LongUtils.EMPTY_LONG_ARRAY; 124 } else if (it instanceof LongIterator) { 125 LongIterator typed = (LongIterator) it; 126 data = new long[MIN_GROWTH_SIZE]; 127 while (typed.hasNext()) { 128 add(typed.nextLong()); 129 } 130 } else { 131 data = new long[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 LongIterator 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(long 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 long[] array = new long[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(long 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(long[] 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(LongCollection 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.toLongArray(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(long startInclusive, long endInclusive) { 286 long increaseLong = endInclusive - startInclusive + 1; 287 if (increaseLong < 0L) { 288 return false; 289 } 290 long newSize = size + increaseLong; 291 if (newSize > Integer.MAX_VALUE) { 292 throw new IllegalArgumentException("Range too large"); 293 } 294 ensureCapacity((int) newSize); 295 long i = startInclusive; 296 while (i < endInclusive) { 297 data[size++] = i++; 298 } 299 data[size++] = i; // handles endInclusive=MAX_VALUE 300 return true; 301 } 302 303 /** 304 * Clone implementation that calls Object clone(). 305 * 306 * @return the clone 307 */ 308 public Object clone() { 309 ArrayLongCollection cloned = (ArrayLongCollection) super.clone(); 310 cloned.data = (long[]) data.clone(); 311 return cloned; 312 } 313 314 /** 315 * Copies data from this collection into the specified array. 316 * This method is pre-validated. 317 * 318 * @param fromIndex the index to start from 319 * @param dest the destination array 320 * @param destIndex the destination start index 321 * @param size the number of items to copy 322 */ 323 protected void arrayCopy(int fromIndex, long[] dest, int destIndex, int size) { 324 System.arraycopy(data, fromIndex, dest, destIndex, size); 325 } 326 327 // Internal implementation 328 //----------------------------------------------------------------------- 329 /** 330 * Internal implementation to add to this collection at the specified index. 331 * This method adjusts the capacity and size. 332 * 333 * @param index the index to add at, valid 334 * @param values the array to add, not null 335 * @return true if the array was updated 336 */ 337 protected boolean doAdd(int index, long[] values) { 338 int len = values.length; 339 ensureCapacity(size + len); 340 System.arraycopy(values, 0, data, size, len); 341 size += len; 342 return (len > 0); 343 } 344 345 /** 346 * Internal implementation to remove the element at the specified index. 347 * 348 * @param index the index, valid 349 */ 350 protected void doRemoveIndex(int index) { 351 System.arraycopy(data, index + 1, data, index, size - 1 - index); 352 size--; 353 } 354 355 /** 356 * Internal implementation to ensure that the internal storage array has 357 * at least the specified size. 358 * 359 * @param reqCapacity the amount to expand to 360 */ 361 protected void ensureCapacity(int reqCapacity) { 362 int curCapacity = data.length; 363 if (reqCapacity <= curCapacity) { 364 return; 365 } 366 int newCapacity = curCapacity * GROWTH_FACTOR_MULTIPLIER / GROWTH_FACTOR_DIVISOR; 367 if ((newCapacity - curCapacity) < MIN_GROWTH_SIZE) { 368 newCapacity = curCapacity + MIN_GROWTH_SIZE; 369 } 370 if (newCapacity < reqCapacity) { 371 newCapacity = reqCapacity; 372 } 373 long[] newArray = new long[newCapacity]; 374 System.arraycopy(data, 0, newArray, 0, curCapacity); 375 data = newArray; 376 } 377 378 // Iterator 379 //----------------------------------------------------------------------- 380 /** 381 * Iterator. 382 */ 383 protected static class PIterator implements LongIterator { 384 385 private final ArrayLongCollection collection; 386 private int cursor = 0; 387 private boolean canRemove = false; 388 389 protected PIterator(ArrayLongCollection coll) { 390 super(); 391 this.collection = coll; 392 } 393 394 public boolean hasNext() { 395 return (cursor < collection.size); 396 } 397 398 public long nextLong() { 399 if (hasNext() == false) { 400 throw new NoSuchElementException("No more elements available"); 401 } 402 canRemove = true; 403 return collection.data[cursor++]; 404 } 405 406 public Long next() { 407 return collection.toObject(nextLong()); 408 } 409 410 public void remove() { 411 if (canRemove == false) { 412 throw new IllegalStateException("Element cannot be removed"); 413 } 414 collection.doRemoveIndex(--cursor); 415 canRemove = false; 416 } 417 418 public boolean isModifiable() { 419 return collection.isModifiable(); 420 } 421 422 public boolean isResettable() { 423 return true; 424 } 425 426 public void reset() { 427 cursor = 0; 428 } 429 } 430 431}