/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package com.db4o.collections;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import com.db4o.activation.*;
import com.db4o.ta.*;
/**
* Transparent activatable ArrayList implementation.
* Implements List interface using an array to store elements.
* Each ArrayList4 instance has a capacity, which indicates the
* size of the internal array. <br><br>
* When instantiated as a result of a query, all the internal members
* are NOT activated at all. When internal members are required to
* perform an operation, the instance transparently activates all
* the members.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.partial
* @sharpen.ignore.implements
* @sharpen.ignore.extends
* @sharpen.if !SILVERLIGHT
*/
@decaf.Ignore(unlessCompatible=decaf.Platform.JDK15)
public class ArrayList4<E> extends AbstractList4<E> implements Cloneable,
Serializable, RandomAccess, Activatable {
/**
* @sharpen.ignore
*/
private static final long serialVersionUID = 7971683768827646182L;
private E[] elements;
private int listSize;
private transient Activator _activator;
/**
* activate basic implementation.
*
* @see com.db4o.ta.Activatable
*/
public void activate(ActivationPurpose purpose) {
if(_activator != null) {
_activator.activate(purpose);
}
}
/**
* bind basic implementation.
*
* @see com.db4o.ta.Activatable
*/
public void bind(Activator activator) {
if (_activator == activator) {
return;
}
if (activator != null && _activator != null) {
throw new IllegalStateException();
}
_activator = activator;
}
/**
* Same behavior as java.util.ArrayList
*
* @see java.util.ArrayList
*/
public ArrayList4() {
this(10);
}
/**
* Same behaviour as java.util.ArrayList
*
* @see java.util.ArrayList
*/
@SuppressWarnings("unchecked")
public ArrayList4(Collection<? extends E> c) {
E[] data = collectionToArray(c);
elements = allocateStorage(data.length);
listSize = data.length;
System.arraycopy(data, 0, elements, 0, data.length);
}
/**
* @sharpen.ignore
*/
@SuppressWarnings("unchecked")
private E[] allocateStorage(int size) {
return (E[]) new Object[size];
}
/**
* @sharpen.ignore
*/
@SuppressWarnings("unchecked")
private E[] collectionToArray(Collection<? extends E> c) {
return (E[]) c.toArray();
}
/**
* Same behaviour as java.util.ArrayList
*
* @see java.util.ArrayList
*/
@SuppressWarnings("unchecked")
public ArrayList4(int initialCapacity) {
if (initialCapacity < 0) {
throw new IllegalArgumentException();
}
elements = allocateStorage(initialCapacity);
listSize = 0;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.internal
*/
public void add(int index, E element) {
checkIndex(index, 0, size());
ensureCapacity(size() + 1);
arrayCopyElements(index, index + 1, listSize - index);
elements[index] = element;
increaseSize(1);
markModified();
}
private void arrayCopyElements(int sourceIndex, int targetIndex, int length) {
activateForWrite();
System.arraycopy(elements, sourceIndex, elements, targetIndex, length);
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.ignore
*/
public boolean addAll(Collection<? extends E> c) {
return addAll(size(), c);
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.ignore
*/
@SuppressWarnings("unchecked")
public boolean addAll(int index, Collection<? extends E> c) {
return addAllImpl(index, (E[]) c.toArray());
}
/**
* @sharpen.internal
*/
private boolean addAllImpl(int index, E[] toBeAdded) {
checkIndex(index, 0, size());
int length = toBeAdded.length;
if(length == 0) {
return false;
}
ensureCapacity(size() + length);
arrayCopyElements(index, index+length, size() - index);
System.arraycopy(toBeAdded, 0, elements, index, length);
increaseSize(length);
markModified();
return true;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*/
public void clear() {
int size = size();
activateForWrite();
Arrays.fill(elements, 0, size, defaultValue());
setSize(0);
markModified();
}
/**
* Used to abstract default value gathering because java does not support <b>default(E)</b>
*
* @sharpen.ignore
*/
private E defaultValue() {
return null;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.ignore
*/
@SuppressWarnings("unchecked")
public Object clone() {
activate(ActivationPurpose.READ);
try {
ArrayList4 <E> clonedList = (ArrayList4<E>) super.clone();
clonedList.elements = elements.clone();
clonedList._activator = null;
return clonedList;
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*/
public void ensureCapacity(int minCapacity) {
activate(ActivationPurpose.READ);
if (minCapacity <= capacity()) {
return;
}
resize(minCapacity);
}
private int capacity() {
return elements.length;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*/
public E get(int index) {
checkIndex(index, 0, size() - 1);
return elements[index];
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.ignore
*/
public int indexOf(Object o) {
for (int index = 0; index < size(); ++index) {
E element = get(index);
if (o == null ? element == null : o.equals(element)) {
return index;
}
}
return -1;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.ignore
*/
@SuppressWarnings("unchecked")
public int lastIndexOf(Object o) {
for (int index = size() - 1; index >= 0; --index) {
E element = get(index);
if (o == null ? element == null : o.equals(element)) {
return index;
}
}
return -1;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.internal
* @sharpen.rename RemoveImpl
*/
public E remove(int index) {
int size = size();
E element = get(index);
arrayCopyElements(index + 1, index, size - index - 1);
elements[size - 1] = defaultValue();
decreaseSize(1);
markModified();
return element;
}
/**
* @sharpen.ignore
*/
protected void removeRange(int fromIndex, int toIndex) {
removeRangeImpl(fromIndex, toIndex - fromIndex);
}
private void removeRangeImpl(int fromIndex, int count) {
int size = size();
int toIndex = fromIndex + count;
if ((fromIndex < 0 || fromIndex >= size || toIndex > size || toIndex < fromIndex)) {
throw new IndexOutOfBoundsException();
}
if (count == 0) {
return;
}
System.arraycopy(elements, toIndex, elements, fromIndex, size - toIndex);
Arrays.fill(elements, size - count, size, defaultValue());
decreaseSize(count);
markModified();
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.internal
*/
public E set(int index, E element) {
E oldValue = get(index);
activateForWrite();
elements[index] = element;
return oldValue;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*/
public int size() {
activate(ActivationPurpose.READ);
return listSize;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.ignore
*/
public Object[] toArray() {
int size = size();
Object[] data = new Object[size];
System.arraycopy(elements, 0, data, 0, size);
return data;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.ignore
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if(a.length < size) {
a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
}
System.arraycopy(elements, 0, a, 0, size);
return a;
}
/**
* same as java.util.ArrayList but transparently
* activates the members as required.
*
* @see java.util.ArrayList
* @see com.db4o.ta.Activatable
*
* @sharpen.rename TrimExcess
*/
public void trimToSize() {
activateForWrite();
resize(size());
}
@SuppressWarnings("unchecked")
private void resize(int minCapacity) {
markModified();
E[] temp = allocateStorage(minCapacity);
System.arraycopy(elements, 0, temp, 0, size());
elements = temp;
}
/**
* @sharpen.internal
*/
void setSize(int count) {
listSize = count;
}
/**
* @sharpen.internal
*/
void increaseSize(int count) {
listSize += count;
}
/**
* @sharpen.internal
*/
void decreaseSize(int count) {
listSize -= count;
}
/**
* @sharpen.internal
*/
void markModified() {
++modCount;
}
private void activateForWrite() {
activate(ActivationPurpose.WRITE);
}
}