/*******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.parser.util;
import java.util.Comparator;
/**
* @author ddaoust
*/
public class HashTable implements Cloneable {
protected static final int minHashSize = 2;
protected int currEntry = -1;
public boolean isEmpty() {
return currEntry == -1;
}
final public int size() {
return currEntry + 1;
}
protected int[] hashTable;
protected int[] nextTable;
public HashTable(int initialSize) {
int size = 1;
while (size < initialSize)
size <<= 1;
if (size > minHashSize) {
hashTable = new int[size * 2];
nextTable = new int[size];
} else {
hashTable = null;
nextTable = null;
}
}
@Override
public Object clone() {
HashTable newTable = null;
try {
newTable = (HashTable) super.clone();
} catch (CloneNotSupportedException e) {
//shouldn't happen because object supports clone.
return null;
}
int size = capacity();
if (hashTable != null) {
newTable.hashTable = new int[size * 2];
newTable.nextTable = new int[size];
System.arraycopy(hashTable, 0, newTable.hashTable, 0, hashTable.length);
System.arraycopy(nextTable, 0, newTable.nextTable, 0, nextTable.length);
}
newTable.currEntry = currEntry;
return newTable;
}
protected void resize() {
resize(capacity() << 1);
}
public void clear() {
currEntry = -1;
// clear the table
if (hashTable == null)
return;
for (int i = 0; i < capacity(); i++) {
hashTable[2 * i] = 0;
hashTable[2 * i + 1] = 0;
nextTable[i] = 0;
}
}
protected void rehash() {
if (nextTable == null)
return;
// clear the table (don't call clear() or else the subclasses stuff will be cleared too)
for (int i = 0; i < capacity(); i++) {
hashTable[2 * i] = 0;
hashTable[2 * i + 1] = 0;
nextTable[i] = 0;
}
// Need to rehash everything
for (int i = 0; i <= currEntry; ++i) {
linkIntoHashTable(i, hash(i));
}
}
protected void resize(int size) {
if (size > minHashSize) {
hashTable = new int[size * 2];
nextTable = new int[size];
// Need to rehash everything
for (int i = 0; i <= currEntry; ++i) {
linkIntoHashTable(i, hash(i));
}
}
}
protected int hash(int pos) {
// return the hash value of the element in the key table
throw new UnsupportedOperationException();
}
protected void linkIntoHashTable(int i, int hash) {
if (nextTable == null)
return;
if (hashTable[hash] == 0) {
hashTable[hash] = i + 1;
} else {
// need to link
int j = hashTable[hash] - 1;
while (nextTable[j] != 0) {
// if (nextTable[j] - 1 == j) {
// break;
// }
j = nextTable[j] - 1;
}
nextTable[j] = i + 1;
}
}
final public int capacity() {
if (nextTable == null)
return minHashSize;
return nextTable.length;
}
protected void removeEntry(int i, int hash) {
if (nextTable == null) {
--currEntry;
return;
}
// Remove the hash entry
if (hashTable[hash] == i + 1) {
hashTable[hash] = nextTable[i];
} else {
// find entry pointing to me
int j = hashTable[hash] - 1;
while (nextTable[j] != 0 && nextTable[j] != i + 1)
j = nextTable[j] - 1;
nextTable[j] = nextTable[i];
}
if (i < currEntry) {
// shift everything over
System.arraycopy(nextTable, i + 1, nextTable, i, currEntry - i);
// adjust hash and next entries for things that moved
for (int j = 0; j < hashTable.length; ++j) {
if (hashTable[j] > i + 1)
--hashTable[j];
}
for (int j = 0; j < nextTable.length; ++j) {
if (nextTable[j] > i + 1)
--nextTable[j];
}
}
// last entry is now free
nextTable[currEntry] = 0;
--currEntry;
}
final public void sort(Comparator<Object> c) {
if (size() > 1) {
quickSort(c, 0, size() - 1);
rehash();
}
}
final private void quickSort(Comparator<Object> c, int p, int r) {
if (p < r) {
int q = partition(c, p, r);
if (p < q) quickSort(c, p, q);
if (++q < r) quickSort(c, q, r);
}
}
protected int partition(Comparator<Object> c, int p, int r) {
throw new UnsupportedOperationException();
}
public void dumpNexts() {
if (nextTable == null)
return;
for (int i = 0; i < nextTable.length; ++i) {
if (nextTable[i] == 0)
continue;
System.out.print(i);
for (int j = nextTable[i] - 1; j >= 0; j = nextTable[j] - 1)
System.out.print(" -> " + j); //$NON-NLS-1$
System.out.println(""); //$NON-NLS-1$
}
}
}