A hash map with int key and int values.
/* * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, * Version 1.0, and under the Eclipse Public License, Version 1.0 * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ //package org.h2.util; /* * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, * Version 1.0, and under the Eclipse Public License, Version 1.0 * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ //package org.h2.util; /** * A hash map with int key and int values. There is a restriction: the * value -1 (NOT_FOUND) cannot be stored in the map. 0 can be stored. * An empty record has key=0 and value=0. * A deleted record has key=0 and value=DELETED */ public class IntIntHashMap extends HashBase { /** * The value indicating that the entry has not been found. */ public static final int NOT_FOUND = -1; private static final int DELETED = 1; private int[] keys; private int[] values; private int zeroValue; protected void reset(int newLevel) { super.reset(newLevel); keys = new int[len]; values = new int[len]; } /** * Store the given key-value pair. The value is overwritten or added. * * @param key the key * @param value the value (-1 is not supported) */ public void put(int key, int value) { if (key == 0) { zeroKey = true; zeroValue = value; return; } try { checkSizePut(); } catch (Exception e) { // in fact, it is never thrown // TODO hash: maybe optimize it } int index = getIndex(key); int plus = 1; int deleted = -1; do { int k = keys[index]; if (k == 0) { if (values[index] != DELETED) { // found an empty record if (deleted >= 0) { index = deleted; deletedCount--; } size++; keys[index] = key; values[index] = value; return; } // found a deleted record if (deleted < 0) { deleted = index; } } else if (k == key) { // update existing values[index] = value; return; } index = (index + plus++) & mask; } while(plus <= len); } /** * Remove the key-value pair with the given key. * * @param key the key */ public void remove(int key) { if (key == 0) { zeroKey = false; return; } try { checkSizeRemove(); } catch (Exception e) { // in fact, it is never thrown // TODO hash: maybe optimize it } int index = getIndex(key); int plus = 1; do { int k = keys[index]; if (k == key) { // found the record keys[index] = 0; values[index] = DELETED; deletedCount++; size--; return; } else if (k == 0 && values[index] == 0) { // found an empty record return; } index = (index + plus++) & mask; } while(plus <= len); // not found } protected void rehash(int newLevel) { int[] oldKeys = keys; int[] oldValues = values; reset(newLevel); for (int i = 0; i < oldKeys.length; i++) { int k = oldKeys[i]; if (k != 0) { put(k, oldValues[i]); } } } /** * Get the value for the given key. This method returns NOT_FOUND if the * entry has not been found. * * @param key the key * @return the value or NOT_FOUND */ public int get(int key) { if (key == 0) { return zeroKey ? zeroValue : NOT_FOUND; } int index = getIndex(key); int plus = 1; do { int k = keys[index]; if (k == 0 && values[index] == 0) { // found an empty record return NOT_FOUND; } else if (k == key) { // found it return values[index]; } index = (index + plus++) & mask; } while(plus <= len); return NOT_FOUND; } } /** * The base for other hash classes. */ abstract class HashBase { private static final int MAX_LOAD = 90; /** * The bit mask to get the index from the hash code. */ protected int mask; /** * The number of slots in the table. */ protected int len; /** * The number of occupied slots, excluding the zero key (if any). */ protected int size; /** * The number of deleted slots. */ protected int deletedCount; /** * The level. The number of slots is 2 ^ level. */ protected int level; /** * Whether the zero key is used. */ protected boolean zeroKey; private int maxSize, minSize, maxDeleted; public HashBase() { reset(2); } /** * Increase the size of the underlying table and re-distribute the elements. * * @param newLevel the new level */ protected abstract void rehash(int newLevel); /** * Get the size of the map. * * @return the size */ public int size() { return size + (zeroKey ? 1 : 0); } /** * Check the size before adding an entry. This method resizes the map if * required. */ void checkSizePut() { if (deletedCount > size) { rehash(level); } if (size + deletedCount >= maxSize) { rehash(level + 1); } } /** * Check the size before removing an entry. This method resizes the map if * required. */ protected void checkSizeRemove() { if (size < minSize && level > 0) { rehash(level - 1); } else if (deletedCount > maxDeleted) { rehash(level); } } /** * Clear the map and reset the level to the specified value. * * @param newLevel the new level */ protected void reset(int newLevel) { minSize = size * 3 / 4; size = 0; level = newLevel; len = 2 << level; mask = len - 1; maxSize = (int) (len * MAX_LOAD / 100L); deletedCount = 0; maxDeleted = 20 + len / 2; } /** * Calculate the index for this hash code. * * @param hash the hash code * @return the index */ protected int getIndex(int hash) { return hash & mask; } }