| /******************************************************************************* |
| * 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 |
| |
| } |