/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.uwyn.rife.datastructures.collections.primitives;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* An {@link IntList} backed by an array of <code>int</code>s.
* This implementation supports all optional methods.
*
* @since Commons Primitives 1.0
* @version $Revision: 3913 $ $Date: 2008-04-13 09:38:28 +0200 (Sun, 13 Apr 2008) $
*
* @author Rodney Waldhoff
* @author Robert Fischer
*/
public class ArrayIntList extends RandomAccessIntList implements IntList, Serializable {
// constructors
//-------------------------------------------------------------------------
/**
* Construct an empty list with the default
* initial capacity.
*/
public ArrayIntList() {
this(8);
}
/**
* Construct an empty list with the given
* initial capacity.
* @throws IllegalArgumentException when <i>initialCapacity</i> is negative
*/
public ArrayIntList(int initialCapacity) {
if(initialCapacity < 0) {
throw new IllegalArgumentException("capacity " + initialCapacity);
}
_data = new int[initialCapacity];
_size = 0;
}
/**
* Constructs a list containing the elements of the given collection,
* in the order they are returned by that collection's iterator.
*
* @see ArrayIntList#addAll(com.uwyn.rife.datastructures.collections.primitives.IntCollection)
* @param that the non-<code>null</code> collection of <code>int</code>s
* to add
* @throws NullPointerException if <i>that</i> is <code>null</code>
*/
public ArrayIntList(IntCollection that) {
this(that.size());
addAll(that);
}
/**
* Constructs a list by copying the specified array.
*
* @param array the array to initialize the collection with
* @throws NullPointerException if the array is <code>null</code>
*/
public ArrayIntList(int[] array) {
this(array.length);
System.arraycopy(array, 0, _data, 0, array.length);
_size = array.length;
}
// IntList methods
//-------------------------------------------------------------------------
public int get(int index) {
checkRange(index);
return _data[index];
}
public int size() {
return _size;
}
/**
* Removes the element at the specified position in
* (optional operation). Any subsequent elements
* are shifted to the left, subtracting one from their
* indices. Returns the element that was removed.
*
* @param index the index of the element to remove
* @return the value of the element that was removed
*
* @throws UnsupportedOperationException when this operation is not
* supported
* @throws IndexOutOfBoundsException if the specified index is out of range
*/
public int removeElementAt(int index) {
checkRange(index);
incrModCount();
int oldval = _data[index];
int numtomove = _size - index - 1;
if(numtomove > 0) {
System.arraycopy(_data,index+1,_data,index,numtomove);
}
_size--;
return oldval;
}
/**
* Replaces the element at the specified
* position in me with the specified element
* (optional operation).
*
* @param index the index of the element to change
* @param element the value to be stored at the specified position
* @return the value previously stored at the specified position
*
* @throws UnsupportedOperationException when this operation is not
* supported
* @throws IndexOutOfBoundsException if the specified index is out of range
*/
public int set(int index, int element) {
checkRange(index);
incrModCount();
int oldval = _data[index];
_data[index] = element;
return oldval;
}
/**
* Inserts the specified element at the specified position
* (optional operation). Shifts the element currently
* at that position (if any) and any subsequent elements to the
* right, increasing their indices.
*
* @param index the index at which to insert the element
* @param element the value to insert
*
* @throws UnsupportedOperationException when this operation is not
* supported
* @throws IllegalArgumentException if some aspect of the specified element
* prevents it from being added to me
* @throws IndexOutOfBoundsException if the specified index is out of range
*/
public void add(int index, int element) {
checkRangeIncludingEndpoint(index);
incrModCount();
ensureCapacity(_size+1);
int numtomove = _size-index;
System.arraycopy(_data,index,_data,index+1,numtomove);
_data[index] = element;
_size++;
}
public void clear() {
incrModCount();
_size = 0;
}
public boolean addAll(IntCollection collection) {
return addAll(size(), collection);
}
public boolean addAll(int index, IntCollection collection) {
if (collection.size() == 0) {
return false;
}
checkRangeIncludingEndpoint(index);
incrModCount();
ensureCapacity(_size + collection.size());
if (index != _size) {
// Need to move some elements
System.arraycopy(_data, index, _data, index + collection.size(), _size - index);
}
for (IntIterator it = collection.iterator(); it.hasNext();) {
_data[index] = it.next();
index++;
}
_size += collection.size();
return true;
}
// capacity methods
//-------------------------------------------------------------------------
/**
* Increases my capacity, if necessary, to ensure that I can hold at
* least the number of elements specified by the minimum capacity
* argument without growing.
*/
public void ensureCapacity(int mincap) {
incrModCount();
if(mincap > _data.length) {
int newcap = (_data.length * 3)/2 + 1;
int[] olddata = _data;
_data = new int[newcap < mincap ? mincap : newcap];
System.arraycopy(olddata,0,_data,0,_size);
}
}
/**
* Reduce my capacity, if necessary, to match my
* current {@link #size size}.
*/
public void trimToSize() {
incrModCount();
if(_size < _data.length) {
int[] olddata = _data;
_data = new int[_size];
System.arraycopy(olddata,0,_data,0,_size);
}
}
// private methods
//-------------------------------------------------------------------------
private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
out.writeInt(_data.length);
for(int i=0;i<_size;i++) {
out.writeInt(_data[i]);
}
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
_data = new int[in.readInt()];
for(int i=0;i<_size;i++) {
_data[i] = in.readInt();
}
}
private final void checkRange(int index) {
if(index < 0 || index >= _size) {
throw new IndexOutOfBoundsException("Should be at least 0 and less than " + _size + ", found " + index);
}
}
private final void checkRangeIncludingEndpoint(int index) {
if(index < 0 || index > _size) {
throw new IndexOutOfBoundsException("Should be at least 0 and at most " + _size + ", found " + index);
}
}
// attributes
//-------------------------------------------------------------------------
private transient int[] _data = null;
private int _size = 0;
}