package net.sourceforge.pain.db;
import java.util.*;
/**
* Persistent, resizable-array implementation of the <tt>List</tt> interface
*/
public final class DbArrayList extends DbCollection implements List, RandomAccess {
private static final Entry[] ZERO_LIST = new Entry[0];
private int size;
private Entry[] items;
private int modCount;
/** new object*/
DbArrayList(final DbObject owner, final int fid) {
super(owner, fid);
size = 0;
items = ZERO_LIST;
modCount = 0;
}
/** pclean startup */
DbArrayList(final DbObject owner, final int[] refIds, final int fid) {
super(owner, fid);
modCount = 0;
restoreFromImage(refIds);
}
private void restoreFromImage(final int[] refIds) {
final PainDB db = owner._getDB();
items = new Entry[(int) (refIds.length * 1.1)];
size = refIds.length;
for (int i = 0; i < size; i++) {
final int id = refIds[i];
items[i] = (id == -1) ? new Entry(null) : new Entry(db.getObjectByIndexId(refIds[i]));
}
}
final int _size() {
return size;
}
final void _clear() {
if (size == 0) {
return;
}
for (int i = size; --i >= 0;) {
_remove(i);
}
modCount++;
size = 0;
}
final DbArrayList.Entry[] getItems() {
return items;
}
/**
* remove with no explicit checks, onChange not called also
* @param index
* @return
*/
private Object _remove(final int index) {
modCount++;
final Entry oldValue = items[index];
final int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(items, index + 1, items, index, numMoved);
}
items[--size] = null;
if (oldValue == null) {
return null;
}
oldValue.onReferenceDestroy();
return oldValue.obj;
}
public int size() {
owner.ensureReal();
return size;
}
public boolean isEmpty() {
owner.ensureReal();
return size == 0;
}
public boolean contains(final Object o) {
return indexOf(o) >= 0;
}
public java.util.Iterator iterator() {
return listIterator();
}
public Object[] toArray() {
owner.ensureReal();
final Object[] result = new Object[size];
for (int i = 0; i < size; i++) {
result[i] = items[i].obj;
}
return result;
}
public Object[] toArray(Object a[]) {
owner.ensureReal();
if (a.length < size) {
a = (Object[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
}
for (int i = 0; i < size; i++) {
a[i] = items[i].obj;
}
if (a.length > size) {
a[size] = null;
}
return a;
}
private void ensureCapacity(final int minCapacity) {
final int oldCapacity = items.length;
if (minCapacity > oldCapacity) {
modCount++;
final Entry oldData[] = items;
int newCapacity = (oldCapacity * 3) / 2 + 1;
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
items = new Entry[newCapacity];
System.arraycopy(oldData, 0, items, 0, size);
}
}
public boolean add(final Object o) {
owner.ensureReal();
owner.onCollectionChange(this);
_add(checkObject(o));
modCount++;
return true;
}
public void add(final int index, final Object o) {
owner.ensureReal();
checkRange(index);
owner.onCollectionChange(this);
final DbObject obj = checkObject(o);
owner.onCollectionChange(this);
ensureCapacity(index + 1);
_add(index, obj);
modCount++;
}
private void _add(final DbObject obj) {
ensureCapacity(size + 1);
items[size] = new Entry(obj);
size++;
}
public boolean remove(final Object o) {
final int index = indexOf(o);
if (index == -1) {
return false;
}
owner.onCollectionChange(this);
_remove(index);
return true;
}
public boolean containsAll(final Collection c) {
owner.ensureReal();
for (java.util.Iterator iterator = c.iterator(); iterator.hasNext();) {
if (_indexOf(iterator.next()) == -1) {
return false;
}
}
return true;
}
public boolean addAll(final Collection c) {
owner.ensureReal();
owner.onCollectionChange(this);
if (c == null || c.isEmpty()) {
return false;
}
ensureCapacity(size + c.size());
Object array[] = c.toArray();
final int len = array.length;
for (int i = 0; i < len; i++) {
_add(checkObject(array[i]));
}
modCount++;
return true;
}
public boolean addAll(final int index, final Collection c) {
throw new UnsupportedOperationException();
}
private DbObject checkObject(final Object o) {
if (o != null) {
final DbObject obj = (DbObject) o;
obj.ensureReal();
owner.ensureDb(obj);
return obj;
}
return null;
}
public boolean removeAll(final Collection c) {
owner.ensureReal();
boolean changed = false;
for (java.util.Iterator it = c.iterator(); it.hasNext();) {
changed |= remove(it.next());
}
return changed;
}
public boolean retainAll(final Collection c) {
owner.ensureReal();
final DbIntBuffer toRemove = new DbIntBuffer(size);
for (int i = 0; i < size; i++) {
if (!c.contains(items[i].obj)) {
toRemove.add(i);
}
}
if (toRemove.isEmpty()) {
return false;
}
owner.onCollectionChange(this);
for (int i = toRemove.getSize(); --i > 0;) {
_remove(toRemove.data[i]);
}
return true;
}
public void clear() {
owner.ensureReal();
owner.onCollectionChange(this);
_clear();
}
public Object get(final int index) {
owner.ensureReal();
checkRange(index);
final Entry e = items[index];
return e.obj;
}
public Object set(final int index, final Object o) {
owner.ensureReal();
checkRange(index);
final DbObject obj = checkObject(o);
final Entry e = items[index];
if (e.obj == obj) {
return obj;
}
owner.onCollectionChange(this);
final DbObject result;
if (e != null) {
e.onReferenceDestroy();
result = e.obj;
} else {
result = null;
}
items[index] = new Entry(obj);
return result;
}
private void _add(final int index, final DbObject o) {
System.arraycopy(items, index, items, index + 1, size - index);
items[index] = new Entry(o);
modCount++;
size++;
}
public Object remove(final int index) {
owner.ensureReal();
checkRange(index);
return _remove(index);
}
public int indexOf(final Object obj) {
owner.ensureReal();
if (obj != null && (!(obj instanceof DbObject) || !hasSameDb((DbObject) obj))) {
return -1;
}
return _indexOf(obj);
}
private int _indexOf(final Object o) {
if (o != null && !hasSameDb((DbObject) o)) {
return -1;
}
for (int i = 0; i < size; i++) {
final Entry item = items[i];
if (item.obj == o) {
return i;
}
}
return -1;
}
private boolean hasSameDb(final DbObject o) {
return o._getDB() == owner._getDB();
}
public int lastIndexOf(final Object o) {
owner.ensureReal();
if (o != null && hasSameDb((DbObject) o)) {
return -1;
}
for (int i = size; --i > 0;) {
final Entry e = items[i];
if (e.obj == o) {
return i;
}
}
return -1;
}
public ListIterator listIterator() {
owner.ensureReal();
return new DbArrayListIterator(0);
}
public ListIterator listIterator(final int index) {
owner.ensureReal();
return new DbArrayListIterator(index);
}
public List subList(final int fromIndex, final int toIndex) {
throw new UnsupportedOperationException();
}
private void checkRange(final int index) {
if (index >= size || index < 0) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}
Object createBackupImage() {
if (size == 0) {
return DbConstants.ZERO_INT_ARRAY;
}
final int[] refIds = new int[size];
final int len = items.length;
for (int i = 0; i < len; i++) {
final Entry e = items[i];
if (e.obj == null) {
refIds[i] = -1;
} else {
refIds[i] = e.obj.indexId;
}
}
return refIds;
}
void restoreFromBackup(final Object backup) {
final int[] ids = (int[]) backup;
_clear();
restoreFromImage(ids);
}
//--------------inners-----------------------
final class Entry extends DbInverseRef {
public Entry(final DbObject obj) {
super(obj);
}
void _onTargetDelete() {
owner.onCollectionChange(DbArrayList.this); //we keep only indexIds, -> should flush this object to avoid oid collision
}
}
final class DbArrayListIterator implements ListIterator {
private int cursor; //cursor - 1 == prev, cursor +1 == next, cursor = current
private int expectedModCount;
private int dir = 0;
public DbArrayListIterator(final int index) {
if (index > size || index < 0) {
throw new IndexOutOfBoundsException("list iterator index: " + index + ", size: " + size);
}
this.cursor = index;
this.expectedModCount = modCount;
dir = 0;
}
private void checkForComodifications() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
public boolean hasNext() {
checkState();
return cursor < size;
}
public Object next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
dir = 1;
final Entry e = items[cursor];
cursor++;
return e.obj;
}
public boolean hasPrevious() {
checkState();
return cursor > 0;
}
private void checkState() {
owner.ensureReal();
checkForComodifications();
}
public Object previous() {
if (!hasPrevious()) {
throw new NoSuchElementException();
}
cursor--;
dir = -1;
final Entry e = items[cursor];
return e.obj;
}
public int nextIndex() {
checkState();
return cursor;
}
public int previousIndex() {
checkState();
return cursor - 1;
}
public void remove() {
checkState();
if (dir == 0) {
throw new IllegalStateException();
}
owner.onCollectionChange(DbArrayList.this);
if (dir == 1) {
_remove(cursor - 1);
} else {
_remove(cursor);
}
cursor--;
expectedModCount = DbArrayList.this.modCount;
}
public void set(final Object o) {
checkState();
throw new UnsupportedOperationException();
}
public void add(final Object o) {
checkState();
throw new UnsupportedOperationException();
}
}
}