001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.collections.primitives;
018    
019    import java.io.IOException;
020    import java.io.ObjectInputStream;
021    import java.io.ObjectOutputStream;
022    import java.io.Serializable;
023    
024    /**
025     * An {@link BooleanList} backed by an array of <code>boolean</code>s.
026     * This implementation supports all optional methods.
027     * 
028     * @since Commons Primitives 1.1
029     * @version $Revision: 480460 $ $Date: 2006-11-29 09:14:21 +0100 (Wed, 29 Nov 2006) $
030     */
031    public class ArrayBooleanList extends RandomAccessBooleanList
032            implements BooleanList, Serializable {
033    
034        // constructors
035        //-------------------------------------------------------------------------
036    
037        /** 
038         * Construct an empty list with the default
039         * initial capacity.
040         */
041        public ArrayBooleanList() {
042            this(8);
043        }    
044    
045        /**
046         * Construct an empty list with the given
047         * initial capacity.
048         * @throws IllegalArgumentException when <i>initialCapacity</i> is negative
049         */
050        public ArrayBooleanList(int initialCapacity) {
051            if(initialCapacity < 0) {
052                throw new IllegalArgumentException("capacity " + initialCapacity);
053            }
054            _data = new boolean[initialCapacity];
055            _size = 0;
056        }    
057    
058        /** 
059         * Constructs a list containing the elements of the given collection, 
060         * in the order they are returned by that collection's iterator.
061         * 
062         * @see ArrayBooleanList#addAll(BooleanCollection)
063         * @param that the non-<code>null</code> collection of <code>boolean</code>s
064         *        to add
065         * @throws NullPointerException if <i>that</i> is <code>null</code>
066         */
067        public ArrayBooleanList(BooleanCollection that) {
068            this(that.size());
069            addAll(that);
070        }    
071    
072        /**
073         * Constructs a list by copying the specified array.
074         * 
075         * @param array  the array to initialize the collection with
076         * @throws NullPointerException if the array is <code>null</code>
077         */
078        public ArrayBooleanList(boolean[] array) { 
079            this(array.length);
080            System.arraycopy(array, 0, _data, 0, array.length);
081            _size = array.length;
082        }
083    
084        // BooleanList methods
085        //-------------------------------------------------------------------------
086    
087        public boolean get(int index) {
088            checkRange(index);
089            return _data[index];
090        }
091        
092        public int size() {
093            return _size;
094        }
095        
096        /** 
097         * Removes the element at the specified position in (optional operation).
098         * Any subsequent elements are shifted to the left, subtracting one from
099         * their indices.  Returns the element that was removed.
100         * 
101         * @param index the index of the element to remove
102         * @return the value of the element that was removed
103         * 
104         * @throws UnsupportedOperationException when this operation is not 
105         *         supported
106         * @throws IndexOutOfBoundsException if the specified index is out of range
107         */
108        public boolean removeElementAt(int index) {
109            checkRange(index);
110            incrModCount();
111            boolean oldval = _data[index];
112            int numtomove = _size - index - 1;
113            if(numtomove > 0) {
114                System.arraycopy(_data,index+1,_data,index,numtomove);
115            }
116            _size--;
117            return oldval;
118        }
119        
120        /** 
121         * Replaces the element at the specified position in me with the specified
122         * element (optional operation).
123         * 
124         * @param index the index of the element to change
125         * @param element the value to be stored at the specified position
126         * @return the value previously stored at the specified position
127         * 
128         * @throws UnsupportedOperationException when this operation is not 
129         *         supported
130         * @throws IndexOutOfBoundsException if the specified index is out of range
131         */
132        public boolean set(int index, boolean element) {
133            checkRange(index);
134            incrModCount();
135            boolean oldval = _data[index];
136            _data[index] = element;
137            return oldval;
138        }
139            
140        /** 
141         * Inserts the specified element at the specified position 
142         * (optional operation). Shifts the element currently 
143         * at that position (if any) and any subsequent elements to the 
144         * right, increasing their indices.
145         * 
146         * @param index the index at which to insert the element
147         * @param element the value to insert
148         * 
149         * @throws UnsupportedOperationException when this operation is not 
150         *         supported
151         * @throws IllegalArgumentException if some aspect of the specified element 
152         *         prevents it from being added to me
153         * @throws IndexOutOfBoundsException if the specified index is out of range
154         */
155        public void add(int index, boolean element) {
156            checkRangeIncludingEndpoint(index);
157            incrModCount();
158            ensureCapacity(_size+1);
159            int numtomove = _size-index;
160            System.arraycopy(_data,index,_data,index+1,numtomove);
161            _data[index] = element;
162            _size++;
163        }
164    
165        public void clear() {
166            incrModCount();
167            _size = 0;
168        }
169        
170        public boolean addAll(BooleanCollection collection) {
171            return addAll(size(), collection);
172        }
173    
174        public boolean addAll(int index, BooleanCollection collection) {
175            if (collection.size() == 0) {
176                return false;
177            }
178            checkRangeIncludingEndpoint(index);
179            incrModCount();
180            ensureCapacity(_size + collection.size());
181            if (index != _size) {
182                // Need to move some elements
183                System.arraycopy(_data, index, _data, index + collection.size(), _size - index);
184            }
185            for (BooleanIterator it = collection.iterator(); it.hasNext();) {
186                _data[index] = it.next();
187                index++;
188            }
189            _size += collection.size();
190            return true;
191        }
192    
193        // capacity methods
194        //-------------------------------------------------------------------------
195    
196        /** 
197         * Increases my capacity, if necessary, to ensure that I can hold at 
198         * least the number of elements specified by the minimum capacity 
199         * argument without growing.
200         */
201        public void ensureCapacity(int mincap) {
202            incrModCount();
203            if(mincap > _data.length) {
204                int newcap = (_data.length * 3)/2 + 1;
205                boolean[] olddata = _data;
206                _data = new boolean[newcap < mincap ? mincap : newcap];
207                System.arraycopy(olddata,0,_data,0,_size);
208            }
209        }
210    
211        /** 
212         * Reduce my capacity, if necessary, to match my
213         * current {@link #size size}.
214         */
215        public void trimToSize() {
216            incrModCount();
217            if(_size < _data.length) {
218                boolean[] olddata = _data;
219                _data = new boolean[_size];
220                System.arraycopy(olddata,0,_data,0,_size);
221            }
222        }
223    
224        // private methods
225        //-------------------------------------------------------------------------
226    
227        private void writeObject(ObjectOutputStream out) throws IOException{
228            out.defaultWriteObject();
229            out.writeInt(_data.length);
230            for(int i=0;i<_size;i++) {
231                out.writeBoolean(_data[i]);
232            }
233        }
234    
235        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
236            in.defaultReadObject();
237            _data = new boolean[in.readInt()];
238            for(int i=0;i<_size;i++) {
239                _data[i] = in.readBoolean();
240            }
241        }
242        
243        private final void checkRange(int index) {
244            if(index < 0 || index >= _size) {
245                throw new IndexOutOfBoundsException(
246                        "Should be at least 0 and less than "
247                        + _size + ", found " + index);
248            }
249        }
250    
251        private final void checkRangeIncludingEndpoint(int index) {
252            if(index < 0 || index > _size) {
253                throw new IndexOutOfBoundsException(
254                        "Should be at least 0 and at most " + _size
255                        + ", found " + index);
256            }
257        }
258    
259        // attributes
260        //-------------------------------------------------------------------------
261        
262        private transient boolean[] _data = null;
263        private int _size = 0;
264    
265    }