Date Type Android

/*
 *  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.
 *
 * Contributors:
 *     Makoto YUI - imported from Android JDK and made some modification.
 */
//package xbird.util.collections;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.RandomAccess;
/**
 * ArrayList is an implementation of {@link List}, backed by an array. All
 * optional operations adding, removing, and replacing are supported. The
 * elements can be any objects.
 */
public class FixedArrayList extends AbstractList
        implements List, Cloneable, Serializable, RandomAccess {
    private static final long serialVersionUID = 8683452581122892189L;
    private transient int firstIndex;
    private transient int lastIndex;
    private transient E[] array;
    /**
     * Constructs a new instance of {@code ArrayList} with the specified
     * capacity.
     *
     * @param capacity
     *            the initial capacity of this {@code ArrayList}.
     */
    public FixedArrayList(int capacity) {
        firstIndex = lastIndex = 0;
        try {
            array = newElementArray(capacity);
        } catch (NegativeArraySizeException e) {
            throw new IllegalArgumentException();
        }
    }
    public FixedArrayList(E[] array) {
        firstIndex = lastIndex = 0;
        this.array = array;
    }
    @SuppressWarnings("unchecked")
    private E[] newElementArray(int size) {
        return (E[]) new Object[size];
    }
    /**
     * Inserts the specified object into this {@code ArrayList} at the specified
     * location. The object is inserted before any previous element at the
     * specified location. If the location is equal to the size of this
     * {@code ArrayList}, the object is added at the end.
     *
     * @param location
     *            the index at which to insert the object.
     * @param object
     *            the object to add.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || > size()}
     */
    @Override
    public void add(int location, E object) {
        int size = lastIndex - firstIndex;
        if(0 < location && location < size) {
            if(firstIndex == 0 && lastIndex == array.length) {
                throw new UnsupportedOperationException("BoundedArrayList cannot grow");
            } else if((location < size / 2 && firstIndex > 0) || lastIndex == array.length) {
                System.arraycopy(array, firstIndex, array, --firstIndex, location);
            } else {
                int index = location + firstIndex;
                System.arraycopy(array, index, array, index + 1, size - location);
                lastIndex++;
            }
            array[location + firstIndex] = object;
        } else if(location == 0) {
            if(firstIndex == 0) {
                throw new UnsupportedOperationException("BoundedArrayList cannot grow");
            }
            array[--firstIndex] = object;
        } else if(location == size) {
            if(lastIndex == array.length) {
                throw new UnsupportedOperationException("BoundedArrayList cannot grow");
            }
            array[lastIndex++] = object;
        } else {
            throw new IndexOutOfBoundsException();
        }
        modCount++;
    }
    /**
     * Adds the specified object at the end of this {@code ArrayList}.
     *
     * @param object
     *            the object to add.
     * @return always true
     */
    @Override
    public boolean add(E object) {
        if(lastIndex == array.length) {
            throw new UnsupportedOperationException("BoundedArrayList cannot grow");
        }
        array[lastIndex++] = object;
        modCount++;
        return true;
    }
    /**
     * Inserts the objects in the specified collection at the specified location
     * in this List. The objects are added in the order they are returned from
     * the collection's iterator.
     *
     * @param location
     *            the index at which to insert.
     * @param collection
     *            the collection of objects.
     * @return {@code true} if this {@code ArrayList} is modified, {@code false}
     *         otherwise.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || > size()}
     */
    @Override
    public boolean addAll(int location, Collection collection) {
        int size = size();
        if(location < 0 || location > size) {
            throw new IndexOutOfBoundsException();
        }
        int growSize = collection.size();
        if(0 < location && location < size) {
            if(array.length - size < growSize) {
                throw new UnsupportedOperationException("BoundedArrayList cannot grow");
            } else if((location < size / 2 && firstIndex > 0)
                    || lastIndex > array.length - growSize) {
                int newFirst = firstIndex - growSize;
                if(newFirst < 0) {
                    int index = location + firstIndex;
                    System.arraycopy(array, index, array, index - newFirst, size - location);
                    lastIndex -= newFirst;
                    newFirst = 0;
                }
                System.arraycopy(array, firstIndex, array, newFirst, location);
                firstIndex = newFirst;
            } else {
                int index = location + firstIndex;
                System.arraycopy(array, index, array, index + growSize, size - location);
                lastIndex += growSize;
            }
        } else if(location == 0) {
            throw new UnsupportedOperationException("BoundedArrayList cannot grow");
        } else if(location == size) {
            if(lastIndex > array.length - growSize) {
                throw new UnsupportedOperationException("BoundedArrayList cannot grow");
            }
            lastIndex += growSize;
        }
        if(growSize > 0) {
            Iterator it = collection.iterator();
            int index = location + firstIndex;
            int end = index + growSize;
            while(index < end) {
                array[index++] = it.next();
            }
            modCount++;
            return true;
        }
        return false;
    }
    /**
     * Adds the objects in the specified collection to this {@code ArrayList}.
     *
     * @param collection
     *            the collection of objects.
     * @return {@code true} if this {@code ArrayList} is modified, {@code false}
     *         otherwise.
     */
    @Override
    public boolean addAll(Collection collection) {
        int growSize = collection.size();
        if(growSize > 0) {
            if(lastIndex > array.length - growSize) {
                throw new UnsupportedOperationException("BoundedArrayList cannot grow");
            }
            Iterator it = collection.iterator();
            int end = lastIndex + growSize;
            while(lastIndex < end) {
                array[lastIndex++] = it.next();
            }
            modCount++;
            return true;
        }
        return false;
    }
    /**
     * Removes all elements from this {@code ArrayList}, leaving it empty.
     *
     * @see #isEmpty
     * @see #size
     */
    @Override
    public void clear() {
        if(firstIndex != lastIndex) {
            Arrays.fill(array, firstIndex, lastIndex, null);
            firstIndex = lastIndex = 0;
            modCount++;
        }
    }
    /**
     * Non-null version of {@link #clear()}.
     */
    public void trimToZero() {
        firstIndex = lastIndex = 0;
        modCount++;
    }
    /**
     * Returns a new {@code ArrayList} with the same elements, the same size and
     * the same capacity as this {@code ArrayList}.
     *
     * @return a shallow copy of this {@code ArrayList}
     * @see java.lang.Cloneable
     */
    @Override
    @SuppressWarnings("unchecked")
    public Object clone() {
        try {
            FixedArrayList newList = (FixedArrayList) super.clone();
            newList.array = array.clone();
            return newList;
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
    /**
     * Searches this {@code ArrayList} for the specified object.
     *
     * @param object
     *            the object to search for.
     * @return {@code true} if {@code object} is an element of this
     *         {@code ArrayList}, {@code false} otherwise
     */
    @Override
    public boolean contains(Object object) {
        if(object != null) {
            for(int i = firstIndex; i < lastIndex; i++) {
                if(object.equals(array[i])) {
                    return true;
                }
            }
        } else {
            for(int i = firstIndex; i < lastIndex; i++) {
                if(array[i] == null) {
                    return true;
                }
            }
        }
        return false;
    }
    @Override
    public E get(int location) {
        int _firstIndex = firstIndex;
        if(0 <= location && location < lastIndex - _firstIndex) {
            return array[_firstIndex + location];
        }
        throw new IndexOutOfBoundsException("Invalid location " + location + ", size is "
                + (lastIndex - _firstIndex));
    }
    @Override
    public int indexOf(Object object) {
        if(object != null) {
            for(int i = firstIndex; i < lastIndex; i++) {
                if(object.equals(array[i])) {
                    return i - firstIndex;
                }
            }
        } else {
            for(int i = firstIndex; i < lastIndex; i++) {
                if(array[i] == null) {
                    return i - firstIndex;
                }
            }
        }
        return -1;
    }
    @Override
    public boolean isEmpty() {
        return lastIndex == firstIndex;
    }
    @Override
    public int lastIndexOf(Object object) {
        if(object != null) {
            for(int i = lastIndex - 1; i >= firstIndex; i--) {
                if(object.equals(array[i])) {
                    return i - firstIndex;
                }
            }
        } else {
            for(int i = lastIndex - 1; i >= firstIndex; i--) {
                if(array[i] == null) {
                    return i - firstIndex;
                }
            }
        }
        return -1;
    }
    /**
     * Replaces the element at the specified location in this {@code ArrayList}
     * with the specified object.
     *
     * @param location
     *            the index at which to put the specified object.
     * @param object
     *            the object to add.
     * @return the previous element at the index.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || >= size()}
     */
    @Override
    public E set(int location, E object) {
        // BEGIN android-changed: slight performance improvement
        if(0 <= location && location < (lastIndex - firstIndex)) {
            // END android-changed
            E result = array[firstIndex + location];
            array[firstIndex + location] = object;
            return result;
        }
        throw new IndexOutOfBoundsException();
    }
    /**
     * Returns the number of elements in this {@code ArrayList}.
     *
     * @return the number of elements in this {@code ArrayList}.
     */
    @Override
    public int size() {
        return lastIndex - firstIndex;
    }
    /**
     * Returns a new array containing all elements contained in this
     * {@code ArrayList}.
     *
     * @return an array of the elements from this {@code ArrayList}
     */
    @Override
    public E[] toArray() {
        return array;
    }
    /**
     * Returns an array containing all elements contained in this
     * {@code ArrayList}. If the specified array is large enough to hold the
     * elements, the specified array is used, otherwise an array of the same
     * type is created. If the specified array is used and is larger than this
     * {@code ArrayList}, the array element following the collection elements
     * is set to null.
     *
     * @param contents
     *            the array.
     * @return an array of the elements from this {@code ArrayList}.
     * @throws ArrayStoreException
     *             when the type of an element in this {@code ArrayList} cannot
     *             be stored in the type of the specified array.
     */
    @Override
    @SuppressWarnings("unchecked")
    public  T[] toArray(T[] contents) {
        int size = size();
        if(size > contents.length) {
            Class ct = contents.getClass().getComponentType();
            contents = (T[]) Array.newInstance(ct, size);
        }
        System.arraycopy(array, firstIndex, contents, 0, size);
        if(size < contents.length) {
            contents[size] = null;
        }
        return contents;
    }
    /**
     * Sets the capacity of this {@code ArrayList} to be the same as the current
     * size.
     *
     * @see #size
     */
    public void trimToSize() {
        throw new UnsupportedOperationException();
    }
    private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("size", Integer.TYPE) }; //$NON-NLS-1$
    private void writeObject(ObjectOutputStream stream) throws IOException {
        ObjectOutputStream.PutField fields = stream.putFields();
        fields.put("size", size()); //$NON-NLS-1$
        stream.writeFields();
        stream.writeInt(array.length);
        Iterator it = iterator();
        while(it.hasNext()) {
            stream.writeObject(it.next());
        }
    }
    @SuppressWarnings("unchecked")
    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
        ObjectInputStream.GetField fields = stream.readFields();
        lastIndex = fields.get("size", 0); //$NON-NLS-1$
        array = newElementArray(stream.readInt());
        for(int i = 0; i < lastIndex; i++) {
            array[i] = (E) stream.readObject();
        }
    }
}