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}