package net.sourceforge.pain.db;
import java.util.*;
/**
* Hash table based persistent implementation of the <tt>Map</tt> interface.<br>
* This map allows only String objects instances as keys and {@link DbObject} as values.
*/
public final class DbStringKeyMap extends DbAbstractMap implements Map {
private static final Object[] ZERO_STRING_KEY_MAP_IMAGE = new Object[]{new String[0], DbConstants.ZERO_INT_ARRAY};//keys, values
DbStringKeyMap(final DbObject owner, final String keys[], final int[] image, final int fid) { //load from image during startup
super(owner, fid);
restoreFromImage(keys, image);
}
DbStringKeyMap(final DbObject owner, final int fid) { // new object during runtime
super(owner, fid);
nElements = 0;
data = ZERO_DATA;
}
void restoreFromImage(Object image) {
final Object[] raw = (Object[]) image;
restoreFromImage((String[]) raw[0], (int[]) raw[1]);
}
private void restoreFromImage(String[] keys, final int[] image) {
final PainDB db = owner._getDB();
final int len = image.length;
nElements = len;
if (data == null || data.length < nElements || data.length > nElements * 2) {
data = nElements == 0 ? ZERO_DATA : new AMapEntry[(int) (nElements / DEFAULT_LOAD_FACTOR)];
}
for (int i = 0; i < len; i++) {
final int indexId = image[i];
final String key = keys[i];
assert(key != null);
new StringKeyMapEntry(key, indexId == -1 ? null : db.getObjectByIndexId(indexId));//key, value
}
}
Object createBackupImage() {
if (nElements == 0) {
return ZERO_STRING_KEY_MAP_IMAGE;
}
final int[] image = new int[nElements];
final String[] keys = new String[nElements];
int pos = 0;
final int nItems = nElements;
for (int i = 0; pos < nItems; i++) {
for (AMapEntry e = data[i]; e != null; e = e.next) {
final DbObject obj = e.obj;
keys[pos] = ((StringKeyMapEntry) e).key;
image[pos] = obj.indexId;
pos++;
}
}
return new Object[]{keys, image};
}
public Iterator valuesIterator() {
return x_valuesIterator();
}
public Iterator keysIterator() {
return x_keysIterator();
}
// ---- DbAbstrat Map impls ---- ///
int a_getIndex(DbAbstractMap.UniversalKey key) {
return _getIndex(key.strKey);
}
private int _getIndex(final String key) {
return (key.hashCode() & 0x7FFFFFFF) % data.length;
}
Object a_get(Object key) {
return get(key);
}
void a_addNewEntry(DbAbstractMap.UniversalKey key, DbObject value) {
new StringKeyMapEntry(key.strKey, value);
}
// --- map interface ------//
public Object get(final Object key) {
ukey.strKey = (String) key;
final Object result = x_get(ukey);
ukey.strKey = null; // release reference
return result;
}
public Object put(final Object key, final Object o) {
ukey.strKey = (String) key;
final Object result = x_put(ukey, o);
ukey.strKey = null;
return result;
}
public Object remove(final Object key) {
ukey.strKey = (String) key;
final Object result = x_remove(ukey);
ukey.strKey = null;
return result;
}
public int size() {
return x_size();
}
public void clear() {
x_clear();
}
public boolean isEmpty() {
return x_isEmpty();
}
public boolean containsKey(Object key) {
ukey.strKey = (String) key;
final boolean result = x_containsKey(ukey);
ukey.strKey = null;
return result;
}
public boolean containsValue(Object value) {
return x_containsValue(value);
}
public Collection values() {
return x_values();
}
public void putAll(Map m) {
x_putAll(m);
}
public Set entrySet() {
return x_entrySet();
}
public Set keySet() {
return x_keySet();
}
//----------------- inners -----------------------//
final class StringKeyMapEntry extends AMapEntry implements Map.Entry {
final String key;
StringKeyMapEntry(final String key, final DbObject obj) {
super(obj);
this.key = key;
linkToMap();
}
public Object getKey() {
return key;
}
int getIndex() {
return _getIndex(key);
}
boolean hasSameKey(UniversalKey ukey) {
return ukey.strKey == key || ukey.strKey.equals(key);
}
};
}