package net.sourceforge.pain.db;
import java.util.*;
abstract class DbAbstractMap extends DbCollection {
static final AMapEntry[] ZERO_DATA = new AMapEntry[0];
final static float DEFAULT_LOAD_FACTOR = 0.9F;
private final static float DEFAULT_EXTENTION_FACTOR = 1.3F;
static final UniversalKey ukey = new UniversalKey();
int nElements;
AMapEntry[] data;
private int modCount = 0;
DbAbstractMap(final DbObject owner, final int fid) { // new object during runtime
super(owner, fid);
nElements = 0;
data = ZERO_DATA;
}
// ---- PAiN DB internal usage methods --- ///
final int _size() {
return nElements;
}
final void _clear() {
if (nElements == 0) {
return;
}
final int len = data.length;
for (int i = 0; i < len; i++) {
for (AMapEntry e = data[i]; e != null; e = e.next) {
e.unlinkFromMap();
}
}
modCount++;
nElements = 0;
}
AMapEntry[] _getData() {
return data;
}
final void restoreFromBackup(final Object o) {
_clear();
restoreFromImage(o);
}
// -- internal private helpers --
private DbObject p_checkObject(final Object o) {
final DbObject obj = (DbObject) o;
obj.ensureReal();
owner.ensureDb(obj);
return obj;
}
private DbObject p_remove(final AMapEntry e) {
final DbObject result = e.obj;
// check();
e.unlinkFromMap();
nElements--;
modCount++;
// check();
return result;
}
private void p_checkRehash(final int n) {
final int newNElements = nElements + n;
if (newNElements > data.length * DEFAULT_LOAD_FACTOR) {
p_rehash(newNElements);
}
}
private void p_rehash(final int minCapacity) {
modCount++;
int newCapacity = (int) (data.length * DEFAULT_EXTENTION_FACTOR);
if (newCapacity < minCapacity) {
newCapacity = (int) (minCapacity * DEFAULT_EXTENTION_FACTOR);
if (newCapacity < 4) {
newCapacity = 4;
}
}
final AMapEntry[] oldData = data;
data = new AMapEntry[newCapacity];
final int oldLen = oldData.length;
for (int i = 0; i < oldLen; i++) {
for (AMapEntry e = oldData[i]; e != null;) {
final AMapEntry next = e.next;
e.rehash();
e = next;
}
}
// check();
}
// -------- ////
// --- MAP --//
// Map interface analog. We should not expose public Map interface from this class
// since one of it's subclasses has Set interface
final Object x_get(UniversalKey key) {
owner.ensureReal();
if (nElements == 0) {
return null;
}
final int index = a_getIndex(key);
for (AMapEntry e = data[index]; e != null; e = e.next) {
if (e.hasSameKey(ukey)) {
return e.obj;
}
}
return null;
}
final DbObject x_remove(final UniversalKey ukey) {
owner.ensureReal();
if (nElements == 0) {
return null;
}
final int index = a_getIndex(ukey);
for (AMapEntry e = data[index]; e != null; e = e.next) {
if (e.hasSameKey(ukey)) {
owner.onCollectionChange(this);
return p_remove(e);
}
}
return null;
}
final DbObject x_removeAll(final UniversalKey ukey) {
owner.ensureReal();
if (nElements == 0) {
return null;
}
final int index = a_getIndex(ukey);
for (AMapEntry e = data[index]; e != null; e = e.next) {
if (e.hasSameKey(ukey)) {
owner.onCollectionChange(this);
return p_remove(e);
}
}
return null;
}
final int x_size() {
owner.ensureReal();
return nElements;
}
final boolean x_isEmpty() {
return x_size() == 0;
}
final boolean x_containsKey(final UniversalKey key) {
return x_get(key) != null;
}
final boolean x_containsValue(final Object o) {
owner.ensureReal();
if (o == null) {
return false;
}
final DbObject obj = p_checkObject(o);
final int len = data.length;
for (int i = 0; i < len; i++) {
for (AMapEntry e = data[i]; e != null; e = e.next) {
if (e.obj == obj) {
return true;
}
}
}
return false;
}
final void x_putAll(final Map t) {
throw new UnsupportedOperationException();
}
final void x_clear() {
owner.ensureReal();
owner.onCollectionChange(this);
_clear();
}
final Set x_keySet() {
owner.ensureReal();
return new Keys();
}
final Iterator x_keysIterator() {
owner.ensureReal();
return new MapIterator(MapIterator.KEYS);
}
final Collection x_values() {
owner.ensureReal();
return new Values();
}
final Iterator x_valuesIterator() {
owner.ensureReal();
return new MapIterator(MapIterator.VALUES);
}
final Set x_entrySet() {
owner.ensureReal();
return new EntrySet();
}
final Object x_put(UniversalKey ukey, Object o) {
owner.ensureReal();
if (o == null) {
throw new NullPointerException();
}
final DbObject obj = p_checkObject(o);
owner.onCollectionChange(this);
p_checkRehash(1);
final int index = a_getIndex(ukey);
DbObject result = null;
for (AMapEntry e = data[index]; e != null; e = e.next) {
if (e.hasSameKey(ukey)) {
result = e.obj;
p_remove(e);
break;
}
}
modCount++;
a_addNewEntry(ukey, obj);
nElements++;
// check();
return result;
}
// -- abstracts --- //
abstract int a_getIndex(final UniversalKey key);
abstract Object a_get(Object key);
abstract void restoreFromImage(Object image);
abstract Object createBackupImage();
abstract void a_addNewEntry(UniversalKey key, DbObject value);
//----------------- inners -----------------------//
abstract class AMapEntry extends DbInverseRef implements Map.Entry {
AMapEntry next;
private AMapEntry prev;
AMapEntry(final DbObject obj) {
super(obj);
}
final void linkToMap() { // called by subclass at the end of constructor when all fields are set
final int index = getIndex();
next = data[index];
data[index] = this;
if (next != null) {
next.prev = this;
}
}
abstract int getIndex();
public abstract Object getKey();
final void rehash() {
final int index = getIndex();
prev = null;
next = data[index];
data[index] = this;
if (next != null) {
next.prev = this;
}
}
final void _onTargetDelete() {
// check();
owner.onCollectionChange(DbAbstractMap.this);
p_remove(this);
}
final public Object getValue() {
return obj;
}
public final Object setValue(final Object value) {
throw new UnsupportedOperationException();
}
private void unlinkFromMap() {
if (prev == null) {
final int index = getIndex();
assert(data[index] == this);
data[index] = next;
} else {
prev.next = next;
}
if (next != null) {
next.prev = prev;
}
onReferenceDestroy();
}
abstract boolean hasSameKey(UniversalKey ukey);
};
final class Values implements Collection {
public Values() {
}
public int size() {
owner.ensureReal();
return nElements;
}
public boolean isEmpty() {
owner.ensureReal();
return nElements == 0;
}
public boolean contains(final Object o) {
owner.ensureReal();
if (o == null) {
return false;
}
final DbObject obj = p_checkObject(o);
final int len = data.length;
for (int i = 0; i < len; i++) {
for (AMapEntry e = data[i]; e != null; e = e.next) {
if (e.obj == obj) {
return true;
}
}
}
return false;
}
public Iterator iterator() {
owner.ensureReal();
return new MapIterator(MapIterator.VALUES);
}
public Object[] toArray() {
owner.ensureReal();
final DbObject[] arr = new DbObject[nElements];
int j = 0;
final int len = data.length;
for (int i = 0; i < len; i++) {
for (AMapEntry e = data[i]; e != null; e = e.next) {
arr[j] = e.obj;
j++;
}
}
return arr;
}
public Object[] toArray(Object a[]) {
owner.ensureReal();
if (a.length < nElements) {
a = (Object[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), nElements);
}
int j = 0;
final int len = data.length;
for (int i = 0; i < len; i++) {
for (AMapEntry e = data[i]; e != null; e = e.next) {
a[j] = e.obj;
j++;
}
}
if (a.length > nElements) {
a[nElements] = null;
}
return a;
}
public boolean add(final Object o) {
throw new UnsupportedOperationException();
}
public boolean remove(final Object o) {
throw new UnsupportedOperationException();
}
public boolean containsAll(final Collection c) {
owner.ensureReal();
for (Iterator it = c.iterator(); it.hasNext();) {
if (!x_containsValue(it.next())) {
return false;
}
}
return true;
}
public boolean addAll(final Collection c) {
throw new UnsupportedOperationException();
}
public boolean removeAll(final Collection c) {
throw new UnsupportedOperationException();
}
public boolean retainAll(final Collection c) {
throw new UnsupportedOperationException();
}
public void clear() {
owner.ensureReal();
_clear();
}
};
final class Keys implements Set {
Keys() {
}
public int size() {
owner.ensureReal();
return nElements;
}
public boolean isEmpty() {
owner.ensureReal();
return nElements == 0;
}
public boolean contains(final Object o) {
return a_get(o) != null;
}
public Iterator iterator() {
owner.ensureReal();
return new MapIterator(MapIterator.KEYS);
}
public Object[] toArray() {
owner.ensureReal();
final Object[] arr = new Object[nElements];
int j = 0;
final int len = data.length;
for (int i = 0; i < len; i++) {
for (AMapEntry e = data[i]; e != null; e = e.next) {
arr[j] = e.getKey();
j++;
}
}
return arr;
}
public Object[] toArray(Object a[]) {
owner.ensureReal();
if (a.length < nElements) {
a = (Object[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), nElements);
}
int j = 0;
final int len = data.length;
for (int i = 0; i < len; i++) {
for (AMapEntry e = data[i]; e != null; e = e.next) {
a[j] = e.getKey();
j++;
}
}
if (a.length > nElements) {
a[nElements] = null;
}
return a;
}
public boolean add(final Object o) {
throw new UnsupportedOperationException();
}
public boolean remove(final Object o) {
throw new UnsupportedOperationException();
}
public boolean containsAll(final Collection c) {
owner.ensureReal();
for (Iterator it = c.iterator(); it.hasNext();) {
if (a_get(it.next()) == null) {
return false;
}
}
return true;
}
public boolean addAll(final Collection c) {
throw new UnsupportedOperationException();
}
public boolean retainAll(final Collection c) {
throw new UnsupportedOperationException();
}
public boolean removeAll(final Collection c) {
throw new UnsupportedOperationException();
}
public void clear() {
owner.ensureReal();
_clear();
}
};
final class EntrySet implements Set {
EntrySet() {
}
public int size() {
owner.ensureReal();
return nElements;
}
public boolean isEmpty() {
owner.ensureReal();
return nElements == 0;
}
public boolean contains(final Object o) {
owner.ensureReal();
final AMapEntry f = (AMapEntry) o;
final int len = data.length;
for (int i = 0; i < len; i++) {
for (AMapEntry e = data[i]; e != null; e = e.next) {
if (e == f) {
return true;
}
}
}
return false;
}
public Iterator iterator() {
owner.ensureReal();
return new MapIterator(MapIterator.ENTRIES);
}
public Object[] toArray() {
throw new UnsupportedOperationException();
}
public Object[] toArray(final Object[] a) {
throw new UnsupportedOperationException();
}
public boolean add(final Object o) {
throw new UnsupportedOperationException();
}
public boolean remove(final Object o) {
throw new UnsupportedOperationException();
}
public boolean containsAll(final Collection c) {
throw new UnsupportedOperationException();
}
public boolean addAll(final Collection c) {
throw new UnsupportedOperationException();
}
public boolean retainAll(final Collection c) {
throw new UnsupportedOperationException();
}
public boolean removeAll(final Collection c) {
throw new UnsupportedOperationException();
}
public void clear() {
owner.ensureReal();
_clear();
}
};
final class MapIterator implements Iterator {
final static int VALUES = 1;
final static int KEYS = 2;
final static int ENTRIES = 3;
private int expectedModCount;
private final int type;
private AMapEntry e = null;
private int index = -1;
private int nPassed = 0;
public MapIterator(final int type) {
this.type = type;
expectedModCount = modCount;
}
public boolean hasNext() {
checkState();
return nPassed < nElements;
}
public Object next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
e = (e == null || e.next == null) ? findWithNextIndex() : e.next;
nPassed++;
return (type == KEYS) ? e.getKey() : type == VALUES ? (Object) e.obj : (Object) e;
}
private AMapEntry findWithNextIndex() {
final int len = data.length;
while (++index < len) {
final AMapEntry e = data[index];
if (e != null) {
return e;
}
}
return null;
}
private AMapEntry findWithPrevIndex() {
while (--index >= 0) {
AMapEntry e = data[index];
if (e != null) {
while (e.next != null) {
e = e.next;
}
return e;
}
}
return null;
}
public void remove() {
checkState();
if (e == null) {
throw new IllegalStateException();
}
final AMapEntry re = e;
e = (e.prev == null) ? findWithPrevIndex() : e.prev;
owner.onCollectionChange(DbAbstractMap.this);
p_remove(re);
expectedModCount++;
nPassed--;
}
private void checkState() {
owner.ensureReal();
checkForComodifications();
}
private void checkForComodifications() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
};
final static class UniversalKey {
int intKey;
String strKey;
}
// public void check() {
// for (int i = 0; i < data.length; i++) {
// AMapEntry e = data[i];
// if (e == null) {
// continue;
// }
// assert e.prev == null;
// while (e != null) {
// assert e.getIndex() == i;
// AMapEntry prev = e;
// e = e.next;
// if (e != null) {
// assert e.prev == prev;
// }
// }
// ;
// }
// }
}