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.collection.impl;
017    
018    import java.util.Collection;
019    import java.util.Iterator;
020    import java.util.NoSuchElementException;
021    
022    import org.joda.primitives.LongUtils;
023    import org.joda.primitives.collection.LongCollection;
024    import 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     */
043    public 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    }