/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2010 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package org.exist.util.hashtable;
import net.jcip.annotations.NotThreadSafe;
/**
* A hashtable which maps object keys to long values.
*
* Keys are compared by their object identity, i.e. two objects are equal
* if object1 == object2.
*
* @author Stephan Körnig
* @author Wolfgang Meier (wolfgang@exist-db.org)
*/
@NotThreadSafe
public class Object2LongIdentityHashMap<K> extends Object2LongHashMap<K> {
Object2LongIdentityHashMap() {
super();
}
public Object2LongIdentityHashMap(final int iSize) {
super(iSize);
}
@Override
public long get(final K key) {
int idx = hash(key) % tabSize;
if (idx < 0) {
idx *= -1;
}
if (keys[idx] == null) {
return -1; // key does not exist
}
else if (keys[idx] == key) {
return values[idx];
}
final int rehashVal = rehash(idx);
for (int i = 0; i < tabSize; i++) {
idx = (idx + rehashVal) % tabSize;
if (keys[idx] == null) {
return -1; // key not found
} else if (keys[idx] == key) {
return values[idx];
}
}
return -1;
}
@Override
public boolean containsKey(final K key) {
int idx = hash(key) % tabSize;
if (idx < 0) {
idx *= -1;
}
if (keys[idx] == null) {
return false; // key does not exist
}
else if (keys[idx] == key) {
return true;
}
final int rehashVal = rehash(idx);
for (int i = 0; i < tabSize; i++) {
idx = (idx + rehashVal) % tabSize;
if (keys[idx] == null) {
return false; // key not found
} else if (keys[idx] == key) {
return true;
}
}
return false;
}
@SuppressWarnings("unchecked")
@Override
public long remove(final K key) {
int idx = hash(key) % tabSize;
if (idx < 0) {
idx *= -1;
}
if (keys[idx] == null) {
return -1; // key does not exist
} else if (keys[idx] == key) {
keys[idx] = (K) REMOVED;
--items;
return values[idx];
}
final int rehashVal = rehash(idx);
for (int i = 0; i < tabSize; i++) {
idx = (idx + rehashVal) % tabSize;
if (keys[idx] == null) {
return -1; // key not found
} else if (keys[idx] == key) {
keys[idx] = (K) REMOVED;
--items;
return values[idx];
}
}
return -1;
}
@Override
protected void insert(final K key, final long value) throws HashSetOverflowException {
if (key == null) {
throw new IllegalArgumentException("Illegal value: null");
}
int idx = hash(key) % tabSize;
if (idx < 0) {
idx *= -1;
}
int bucket = -1;
// look for an empty bucket
if (keys[idx] == null) {
keys[idx] = key;
values[idx] = value;
++items;
return;
} else if (keys[idx] == REMOVED) {
// remember the bucket, but continue to check
// for duplicate keys
bucket = idx;
} else if (keys[idx] == key) {
// duplicate value
values[idx] = value;
return;
}
final int rehashVal = rehash(idx);
int rehashCnt = 1;
for (int i = 0; i < tabSize; i++) {
idx = (idx + rehashVal) % tabSize;
if (keys[idx] == REMOVED) {
bucket = idx;
} else if (keys[idx] == null) {
if (bucket > -1) {
// store key into the empty bucket first found
idx = bucket;
}
keys[idx] = key;
values[idx] = value;
++items;
return;
} else if (keys[idx] == key) {
// duplicate value
values[idx] = value;
return;
}
++rehashCnt;
}
// should never happen, but just to be sure:
// if the key has not been inserted yet, do it now
if (bucket > -1) {
keys[bucket] = key;
values[bucket] = value;
++items;
return;
}
throw new HashSetOverflowException();
}
}