org.apache.xerces.util.SymbolHash Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xerces.util;
/**
* This class is an unsynchronized hash table primary used for String
* to Object mapping.
*
* The hash code uses the same algorithm as SymbolTable class.
*
* @author Elena Litani
* @version $Id: SymbolHash.java 1357382 2012-07-04 19:56:40Z mrglavas $
*/
public class SymbolHash {
//
// Constants
//
/** Default table size. */
protected static final int TABLE_SIZE = 101;
/** Maximum hash collisions per bucket. */
protected static final int MAX_HASH_COLLISIONS = 40;
protected static final int MULTIPLIERS_SIZE = 1 << 5;
protected static final int MULTIPLIERS_MASK = MULTIPLIERS_SIZE - 1;
//
// Data
//
/** Actual table size **/
protected int fTableSize;
/** Buckets. */
protected Entry[] fBuckets;
/** Number of elements. */
protected int fNum = 0;
/**
* Array of randomly selected hash function multipliers or null
* if the default String.hashCode() function should be used.
*/
protected int[] fHashMultipliers;
//
// Constructors
//
/** Constructs a key table with the default size. */
public SymbolHash() {
this(TABLE_SIZE);
}
/**
* Constructs a key table with a given size.
*
* @param size the size of the key table.
*/
public SymbolHash(int size) {
fTableSize = size;
fBuckets = new Entry[fTableSize];
}
//
// Public methods
//
/**
* Adds the key/value mapping to the key table. If the key already exists,
* the previous value associated with this key is overwritten by the new
* value.
*
* @param key
* @param value
*/
public void put(Object key, Object value) {
// search for identical key
int collisionCount = 0;
final int hash = hash(key);
int bucket = hash % fTableSize;
for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
if (key.equals(entry.key)) {
// replace old value
entry.value = value;
return;
}
++collisionCount;
}
if (fNum >= fTableSize) {
// Rehash the table if the number of entries
// would exceed the number of buckets.
rehash();
bucket = hash % fTableSize;
}
else if (collisionCount >= MAX_HASH_COLLISIONS && key instanceof String) {
// Select a new hash function and rehash the table if
// MAX_HASH_COLLISIONS is exceeded.
rebalance();
bucket = hash(key) % fTableSize;
}
// create new entry
Entry entry = new Entry(key, value, fBuckets[bucket]);
fBuckets[bucket] = entry;
++fNum;
}
/**
* Get the value associated with the given key.
*
* @param key
* @return the value associated with the given key.
*/
public Object get(Object key) {
int bucket = hash(key) % fTableSize;
Entry entry = search(key, bucket);
if (entry != null) {
return entry.value;
}
return null;
}
/**
* Get the number of key/value pairs stored in this table.
*
* @return the number of key/value pairs stored in this table.
*/
public int getLength() {
return fNum;
}
/**
* Add all values to the given array. The array must have enough entry.
*
* @param elements the array to store the elements
* @param from where to start store element in the array
* @return number of elements copied to the array
*/
public int getValues(Object[] elements, int from) {
for (int i=0, j=0; i 0;) {
for (Entry old = oldTable[i]; old != null; ) {
Entry e = old;
old = old.next;
int index = hash(e.key) % newCapacity;
e.next = newTable[index];
newTable[index] = e;
}
}
}
//
// Classes
//
/**
* This class is a key table entry. Each entry acts as a node
* in a linked list.
*/
protected static final class Entry {
// key/value
public Object key;
public Object value;
/** The next entry. */
public Entry next;
public Entry() {
key = null;
value = null;
next = null;
}
public Entry(Object key, Object value, Entry next) {
this.key = key;
this.value = value;
this.next = next;
}
public Entry makeClone() {
Entry entry = new Entry();
entry.key = key;
entry.value = value;
if (next != null)
entry.next = next.makeClone();
return entry;
}
} // entry
} // class SymbolHash