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.ByteUtils;
023    import org.joda.primitives.collection.ByteCollection;
024    import org.joda.primitives.iterator.ByteIterator;
025    
026    /**
027     * Array based implementation of <code>ByteCollection</code> for
028     * primitive <code>byte</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 ArrayByteCollection extends AbstractByteCollection 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 byte[] data;
055        /** The current size */
056        private int size;
057    
058        /**
059         * Constructor.
060         */
061        public ArrayByteCollection() {
062            super();
063            data = ByteUtils.EMPTY_BYTE_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 ArrayByteCollection(int initialSize) {
072            super();
073            if (initialSize <= 0) {
074                data = ByteUtils.EMPTY_BYTE_ARRAY;
075            } else {
076                data = new byte[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 ArrayByteCollection(byte[] values) {
086            super();
087            if (values == null) {
088                data = ByteUtils.EMPTY_BYTE_ARRAY;
089            } else {
090                data = (byte[]) 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 ArrayByteCollection(Collection<?> coll) {
101            super();
102            if (coll == null) {
103                data = ByteUtils.EMPTY_BYTE_ARRAY;
104            } else if (coll instanceof ByteCollection) {
105                ByteCollection c = (ByteCollection) coll;
106                size = c.size();
107                data = new byte[size];
108                c.toByteArray(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 ArrayByteCollection(Iterator<Byte> it) {
121            super();
122            if (it == null) {
123                data = ByteUtils.EMPTY_BYTE_ARRAY;
124            } else if (it instanceof ByteIterator) {
125                ByteIterator typed = (ByteIterator) it;
126                data = new byte[MIN_GROWTH_SIZE];
127                while (typed.hasNext()) {
128                    add(typed.nextByte());
129                }
130            } else {
131                data = new byte[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 ByteIterator 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(byte 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                byte[] array = new byte[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(byte 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(byte[] 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(ByteCollection 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.toByteArray(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(byte startInclusive, byte endInclusive) {
286            int increase = endInclusive - startInclusive + 1;
287            if (increase < 0) {
288                return false;
289            }
290            ensureCapacity(size + increase);
291            byte 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            ArrayByteCollection cloned = (ArrayByteCollection) super.clone();
306            cloned.data = (byte[]) 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, byte[] 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, byte[] 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            byte[] newArray = new byte[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 ByteIterator {
380    
381            private final ArrayByteCollection collection;
382            private int cursor = 0;
383            private boolean canRemove = false;
384    
385            protected PIterator(ArrayByteCollection coll) {
386                super();
387                this.collection = coll;
388            }
389    
390            public boolean hasNext() {
391                return (cursor < collection.size);
392            }
393    
394            public byte nextByte() {
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 Byte next() {
403                return collection.toObject(nextByte());
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    }