blob: 1b83753befdb90dab1fdb91e1bbdba6414132e7d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 1997-2007 by ProSyst Software GmbH
* http://www.prosyst.com
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* ProSyst Software GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.internal.util.hash;
import java.util.NoSuchElementException;
/**
* Hashtable for mapping Object keys to int values. The methods of this
* hashtable are not synchronized, and if used concurently must be externally
* synchronized
*
* @author Pavlin Dobrev
* @version 1.0
*/
public class HashObjIntNS {
static final float LOAD_FACTOR = 0.75f;
// count of elements available in table
private int count = 0;
// used for computation of next position
private int step = 499979;
/**
* Used to enumerate the keys in the hash table. The key at index
* <code>i</code> is valid only if
* <ul>
* <code> keys[i] != null </code>
* </ul>
*/
public Object[] keys;
/**
* Used to enumerate the values in the hash table. The value at index
* <code>i</code> is valid only if
* <ul>
* <code> keys[i] != null </code>
* </ul>
*/
public int[] values;
/**
* Can be used to check if a key or value is valid. The value or key at
* index <code>i</code> is valid if the following expression is true
* <ul>
* <code> next[i] != -1 && next[i] < next.length </code>
* </ul>
*/
public int[] next;
private int limit;
private double loadFactor;
/**
* Constructs an empty hash table with keys of type int and values af type
* Object. Uses default load factor (0.75) and default capacity (89)
*
*/
public HashObjIntNS() {
this(101, LOAD_FACTOR);
}
/**
* Constructs an empty hash table with keys of type int and values af type
* Object. Uses default load factor (0.75).
*
* @param capacity
* initial capacity of the table
*
* @exception IllegalArgumentException
* if <code>capacity</code> < 1.
*/
public HashObjIntNS(int capacity) {
this(capacity, LOAD_FACTOR);
}
/**
* Constructs an empty hash table with keys of type int and values of type
* Object.
*
* @param capacity
* initial capacity of the table
* @param lf
* load factor ot the table
*
* @exception IllegalArgumentException
* if <code>capacity</code> < 1 or <code>lf</code> < 0.0
*/
public HashObjIntNS(int capacity, double lf) {
if (capacity < 0) {
throw new IllegalArgumentException("Invalid hashtable capacity: " + capacity + ".");
}
if (capacity == 0)
capacity = 101;
if (lf < 0) {
throw new IllegalArgumentException("Invalid load factor: " + lf + ".");
}
if (lf > 1.0) {
lf = 1.0;
}
loadFactor = lf;
limit = (int) (capacity * lf);
count = 0;
keys = new Object[capacity];
values = new int[capacity];
next = new int[capacity];
for (int i = 0; i < capacity; i++) {
next[i] = -1;
}
}
/**
* Adds in hashtable an element with <code>key</code> key and
* <code>value</code> value. If an element with the specified key is
* already in the table only change it's value.
*
* @param key
* the key of the inserted element
* @param value
* the value of the inserted element
*/
public void put(Object key, int value) {
if (count >= limit) {
rehash();
}
if (_put(key, value)) {
count++;
}
}
/**
* Returns an value which is mapped to the <code>key</code> key. If there
* is no such a key, throws <code>NoSuchElementException</code>.
*
* @param key
* the key we are searching for
* @return the value this key is mapped to in the table.
*
* @exception NoSuchElementException
* if there is no element with the specified key.
*/
public int get(Object key) {
int pos = find(key);
if (pos == -1)
throw new NoSuchElementException();
return values[pos];
}
/**
* Removes an element with the specified key from the table. throws
* <code>NoSuchElementException</code> if there is no element with this
* key.
*
* @param key
* the key of the element we want to remove
* @exception NoSuchElementException
* if there is no element with the specified key.
*/
public int remove(Object key) {
int pos = find(key);
if (pos == -1)
throw new NoSuchElementException();
next[pos] += next.length; // mark this field as empty
count--;
keys[pos] = null;
return values[pos];
}
/**
* Empties the hash table
*/
public void removeAll() {
for (int i = 0; i < values.length; i++) {
keys[i] = null;
next[i] = -1;
}
}
/**
* Rehashes the contents of the hashtable into a hashtable with a larger
* capacity. This method is called automatically when the number of keys in
* the hashtable exceeds this hashtable's capacity and load factor.
*/
public void rehash() {
Object[] tmpKeys = keys;
int[] tmpValues = values;
int[] tmpNext = next;
int capacity = keys.length * 2 + 1;
// polzwame temp array-i za da ne se namaje hashtable-a pri OutOfMemory
Object[] keys = new Object[capacity];
int[] values = new int[capacity];
int[] next = new int[capacity];
for (int i = 0; i < next.length; i++) {
next[i] = -1;
}
this.keys = keys;
this.values = values;
this.next = next;
for (int i = 0; i < tmpNext.length; i++) {
if ((tmpNext[i] >= 0) && (tmpNext[i] < tmpNext.length)) {
_put(tmpKeys[i], tmpValues[i]);
}
}
limit = (int) (capacity * loadFactor);
}
/**
* Returns the count of elements currently in the table
*
* @return the count of elements
*/
public int size() {
return count;
}
public Object[] getKeys() {
return keys;
}
private int find(Object key) {
return find(key, (key.hashCode() & 0x7fffffff) % keys.length);
} // find
private int find(Object key, int pos) {
int i = 0;
// System.out.println("In Zarko's code");
//
// if (key == null)
// System.out.println("key is null");
//
while (next[pos] >= 0) {
if (keys[pos] != null) {
// System.out.println("is null");
if (key.equals(keys[pos])) {
if (next[pos] < next.length) {
return pos;
}
}
}
if ((pos = next[pos]) >= next.length) {
pos -= next.length;
}
if (++i > next.length) {
return -1;
}
}
return -1;
}
private boolean _put(Object key, int value) {
int pos = (key.hashCode() & 0x7fffffff) % keys.length;
int index = find(key, pos);
if (index != -1) {
values[index] = value;
return false;
}
while ((next[pos] >= 0) && (next[pos] < next.length)) {
pos = next[pos];
}
keys[pos] = key;
values[pos] = value;
if (next[pos] < 0) {
next[pos] = (pos + step) % next.length;
} else {
next[pos] -= next.length;
}
return true;
} // _put
}