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 */
017package org.apache.commons.collections.primitives;
018
019import java.io.IOException;
020import java.io.ObjectInputStream;
021import java.io.ObjectOutputStream;
022import 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 03:14:21 -0500 (Wed, 29 Nov 2006) $
030 */
031public 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}