316 lines
9.8 KiB
Java
316 lines
9.8 KiB
Java
|
|
/*
|
||
|
|
* Copyright (c) 2002,2009 Declarative Engineering LLC.
|
||
|
|
* All rights reserved. This program and the accompanying materials
|
||
|
|
* are made available under the terms of the Declarative Engineering LLC
|
||
|
|
* verson 1 which accompanies this distribution, and is available at
|
||
|
|
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||
|
|
*/
|
||
|
|
package com.common.util.optimized;
|
||
|
|
|
||
|
|
import com.common.util.*;
|
||
|
|
import com.common.comparison.*;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This collection maps a value by a key.
|
||
|
|
*/
|
||
|
|
public class IntObjectHashMap extends Map implements IIntObjectHashMap {
|
||
|
|
private int[] keys = null;
|
||
|
|
private int keyCount = 0;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The Entry wrappers the key/value pair.
|
||
|
|
*/
|
||
|
|
protected static class Entry extends BasicEntry {
|
||
|
|
public int key = 0;
|
||
|
|
public Object value = null;
|
||
|
|
|
||
|
|
protected Entry() {
|
||
|
|
super();
|
||
|
|
}//Entry()//
|
||
|
|
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||
|
|
super.readExternal(in);
|
||
|
|
key = in.readInt();
|
||
|
|
value = in.readObject();
|
||
|
|
}//readExternal()//
|
||
|
|
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||
|
|
super.writeExternal(out);
|
||
|
|
out.writeInt(key);
|
||
|
|
out.writeObject(value);
|
||
|
|
}//writeExternal()//
|
||
|
|
public int createKeyHash() {
|
||
|
|
return key;
|
||
|
|
}//createKeyHash()//
|
||
|
|
public String toString() {
|
||
|
|
return super.toString() + "\r\n\thash: " + hash + "\r\n\tkey: " + key + "\r\n\tvalue: " + (value != null ? value.toString() : "null") + (next != null ? ("\r\n" + next.toString()) : "");
|
||
|
|
}//toString()//
|
||
|
|
}//Entry//
|
||
|
|
|
||
|
|
public static class KeyIterator extends Iterator implements IIntIterator {
|
||
|
|
public KeyIterator(IntObjectHashMap hashMap) {
|
||
|
|
super(hashMap);
|
||
|
|
}//KeyIterator()//
|
||
|
|
public int next() {
|
||
|
|
return ((Entry) nextEntry()).key;
|
||
|
|
}//next()//
|
||
|
|
public int previous() {
|
||
|
|
return ((Entry) previousEntry()).key;
|
||
|
|
}//previous()//
|
||
|
|
}//KeyIterator//
|
||
|
|
|
||
|
|
public static class ValueIterator extends Iterator implements IReversableIterator {
|
||
|
|
public ValueIterator(IntObjectHashMap hashMap) {
|
||
|
|
super(hashMap);
|
||
|
|
}//ValueIterator()//
|
||
|
|
public Object next() {
|
||
|
|
return ((Entry) nextEntry()).value;
|
||
|
|
}//next()//
|
||
|
|
public Object previous() {
|
||
|
|
return ((Entry) previousEntry()).value;
|
||
|
|
}//previous()//
|
||
|
|
}//ValueIterator//
|
||
|
|
/**
|
||
|
|
* IntObjectHashMap constructor.
|
||
|
|
*/
|
||
|
|
protected IntObjectHashMap() {
|
||
|
|
this(DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, DEFAULT_VALUE_COMPARATOR);
|
||
|
|
}//IntObjectHashMap()//
|
||
|
|
/**
|
||
|
|
* IntObjectHashMap constructor.
|
||
|
|
* @param initialCapacity The initial capacity of the map. This value should be between 1..+N, a value of zero will be silently modified to a value of one. Any other value will cause an IllegalArgumentException.
|
||
|
|
*/
|
||
|
|
public IntObjectHashMap(int initialCapacity) {
|
||
|
|
this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_VALUE_COMPARATOR);
|
||
|
|
}//IntObjectHashMap()//
|
||
|
|
/**
|
||
|
|
* IntObjectHashMap constructor.
|
||
|
|
* @param initialCapacity The initial capacity of the map. This value should be between 1..+N, a value of zero will be silently modified to a value of one. Any other value will cause an IllegalArgumentException.
|
||
|
|
* @param loadFactor The ratio that determines when the map should increase capacity. This value should be greater than 0.0 and any other value will cause an IllegalArgumentException.
|
||
|
|
*/
|
||
|
|
public IntObjectHashMap(int initialCapacity, float loadFactor) {
|
||
|
|
this(initialCapacity, loadFactor, DEFAULT_VALUE_COMPARATOR);
|
||
|
|
}//IntObjectHashMap()//
|
||
|
|
/**
|
||
|
|
* IntObjectHashMap constructor.
|
||
|
|
* @param initialCapacity The initial capacity of the map. This value should be between 1..+N, a value of zero will be silently modified to a value of one. Any other value will cause an IllegalArgumentException.
|
||
|
|
* @param loadFactor The ratio that determines when the map should increase capacity. This value should be greater than 0.0 and any other value will cause an IllegalArgumentException.
|
||
|
|
* @param valueComparator The comparator used to compare value objects.
|
||
|
|
*/
|
||
|
|
public IntObjectHashMap(int initialCapacity, float loadFactor, IComparator valueComparator) {
|
||
|
|
super(initialCapacity, loadFactor, null, valueComparator);
|
||
|
|
}//IntObjectHashMap()//
|
||
|
|
/**
|
||
|
|
* IntObjectHashMap constructor.
|
||
|
|
* @param initialCapacity The initial capacity of the map. This value should be between 1..+N, a value of zero will be silently modified to a value of one. Any other value will cause an IllegalArgumentException.
|
||
|
|
* @param valueComparator The comparator used to compare value objects.
|
||
|
|
*/
|
||
|
|
public IntObjectHashMap(int initialCapacity, IComparator valueComparator) {
|
||
|
|
this(initialCapacity, DEFAULT_LOAD_FACTOR, valueComparator);
|
||
|
|
}//IntObjectHashMap()//
|
||
|
|
/**
|
||
|
|
* @see IIntObjectHashMap.containsKey(int)
|
||
|
|
*/
|
||
|
|
public boolean containsKey(int key) {
|
||
|
|
return get(key) != null;
|
||
|
|
}//containsKey()//
|
||
|
|
/**
|
||
|
|
* Will create an entry object of the specific type used by this map.
|
||
|
|
* @return BasicEntry An entry object that can be filled and passed to the addEntry method.
|
||
|
|
*/
|
||
|
|
protected IBasicEntry createEntry() {
|
||
|
|
return new Entry();
|
||
|
|
}//createEntry()//
|
||
|
|
/**
|
||
|
|
* Gets the first available value in the map.
|
||
|
|
* @return The first accessable value in the map.
|
||
|
|
*/
|
||
|
|
public Object getFirst() {
|
||
|
|
IBasicEntry[] entries = getEntries();
|
||
|
|
|
||
|
|
for(int index = 0; index < entries.length; index++) {
|
||
|
|
for(Entry entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
|
||
|
|
if(entry != null) {
|
||
|
|
return entry.value;
|
||
|
|
}//if//
|
||
|
|
}//for//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}//getFirst()//
|
||
|
|
/**
|
||
|
|
* @see IIntObjectHashMap.get(int)
|
||
|
|
*/
|
||
|
|
public Object get(int key) {
|
||
|
|
IBasicEntry[] entries = getEntries();
|
||
|
|
int hash = key;
|
||
|
|
int index = (hash & 0x7FFFFFFF) % entries.length;
|
||
|
|
|
||
|
|
for(Entry entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
|
||
|
|
if((entry.hash == hash) && (entry.key == key)) {
|
||
|
|
return entry.value;
|
||
|
|
}//if//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}//get()//
|
||
|
|
/**
|
||
|
|
* This method will get the key at the given index.
|
||
|
|
* <p>NOTE: This method is intended for use by the iterators and it is not advisable to use this method else where.
|
||
|
|
* @param index The index in the list of keys.
|
||
|
|
* @return The key at the given index.
|
||
|
|
*/
|
||
|
|
public int getKey(int index) {
|
||
|
|
if(keys == null) {
|
||
|
|
refreshKeys();
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return keys[index];
|
||
|
|
}//get()//
|
||
|
|
/**
|
||
|
|
* This will invalidate the collection of keys.
|
||
|
|
* This should occur when a value is added/removed/changed in a way that invalidates the collection of keys.
|
||
|
|
*/
|
||
|
|
protected void invalidateKeys() {
|
||
|
|
keys = null;
|
||
|
|
keyCount = 0;
|
||
|
|
}//invalidateKeys()//
|
||
|
|
/**
|
||
|
|
* @see IIntObjectHashMap.keyIterator()
|
||
|
|
*/
|
||
|
|
public IIntIterator keyIterator() {
|
||
|
|
return new KeyIterator(this);
|
||
|
|
}//keyIterator()//
|
||
|
|
/**
|
||
|
|
* @see IIntObjectHashMap.put(int, Object)
|
||
|
|
*/
|
||
|
|
public Object put(int key, Object value) {
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable();
|
||
|
|
|
||
|
|
if(value == null) {
|
||
|
|
//Remove the key if it exists because you cannot associate a key with a null value.//
|
||
|
|
return remove(key);
|
||
|
|
}//if//
|
||
|
|
else {
|
||
|
|
IBasicEntry[] entries = getEntries();
|
||
|
|
int hash = key;
|
||
|
|
int index = (hash & 0x7FFFFFFF) % entries.length;
|
||
|
|
Entry entry = null;
|
||
|
|
|
||
|
|
//Try to locate an existing value.//
|
||
|
|
for(entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
|
||
|
|
if((entry.hash == hash) && (entry.key == key)) {
|
||
|
|
Object oldValue = entry.value;
|
||
|
|
|
||
|
|
entry.value = value;
|
||
|
|
|
||
|
|
return oldValue;
|
||
|
|
}//if//
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
//Determine if we need to re-hash.//
|
||
|
|
if(resize(getSize() + 1)) {
|
||
|
|
entries = getEntries();
|
||
|
|
//Recalculate the insertion index if the map resized.//
|
||
|
|
index = (hash & 0x7FFFFFFF) % entries.length;
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Create and add the new entry.//
|
||
|
|
entry = (Entry) createEntry();
|
||
|
|
entry.hash = hash;
|
||
|
|
entry.key = key;
|
||
|
|
entry.value = value;
|
||
|
|
addEntry(index, entry);
|
||
|
|
|
||
|
|
if(keys != null) {
|
||
|
|
//Just add the key instead of invalidating the keys collection.//
|
||
|
|
if(keyCount == keys.length) {
|
||
|
|
int[] temp = new int[keys.length < 50 ? keys.length << 1 : keys.length + 100];
|
||
|
|
|
||
|
|
System.arraycopy(keys, 0, temp, 0, keys.length);
|
||
|
|
keys = temp;
|
||
|
|
keys[keyCount++] = key;
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
keys[keyCount++] = key;
|
||
|
|
keyCount++;
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}//else//
|
||
|
|
}//put()//
|
||
|
|
/**
|
||
|
|
* Will recreate the collection of keys.
|
||
|
|
*/
|
||
|
|
protected void refreshKeys() {
|
||
|
|
IBasicEntry[] entries = getEntries();
|
||
|
|
int index;
|
||
|
|
Entry entry;
|
||
|
|
|
||
|
|
keys = new int[getSize() + 10];
|
||
|
|
|
||
|
|
for(index = 0; index < entries.length; index++) {
|
||
|
|
for(entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
|
||
|
|
keys[index] = entry.key;
|
||
|
|
keyCount++;
|
||
|
|
}//for//
|
||
|
|
}//for//
|
||
|
|
}//refreshKeys()//
|
||
|
|
/**
|
||
|
|
* Will optimize the collection of Entry objects to improve access time.
|
||
|
|
* @param arrayLength int The new length of the entry array.
|
||
|
|
*/
|
||
|
|
protected void rehash(int arrayLength) {
|
||
|
|
super.rehash(arrayLength);
|
||
|
|
//Invalidate the list of keys.//
|
||
|
|
invalidateKeys();
|
||
|
|
}//rehash()//
|
||
|
|
/**
|
||
|
|
* @see IIntObjectHashMap.remove(int)
|
||
|
|
*/
|
||
|
|
public Object remove(int key) {
|
||
|
|
IBasicEntry[] entries = getEntries();
|
||
|
|
int hash = key;
|
||
|
|
int index = (hash & 0x7FFFFFFF) % entries.length;
|
||
|
|
Entry previousEntry = null;
|
||
|
|
Entry entry = null;
|
||
|
|
Object retVal = null;
|
||
|
|
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable();
|
||
|
|
|
||
|
|
//Iterate through the entries stored at the key's hash location and remove the given key.//
|
||
|
|
for(entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
|
||
|
|
if((entry.hash == hash) && (entry.key == key)) {
|
||
|
|
//Save the removed value.//
|
||
|
|
retVal = entry.value;
|
||
|
|
//Remove the entry from the map.//
|
||
|
|
removeEntry(index, previousEntry);
|
||
|
|
//Could find the key in the collection and remove it, but that may take to long.//
|
||
|
|
invalidateKeys();
|
||
|
|
//Break from the loop so we can exit.//
|
||
|
|
break;
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
previousEntry = entry;
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
return retVal;
|
||
|
|
}//remove()//
|
||
|
|
/**
|
||
|
|
* @see IIntObjectHashMap.removeAll()
|
||
|
|
*/
|
||
|
|
public boolean removeAll() {
|
||
|
|
//Verify that the collection can be modified.//
|
||
|
|
verifyIsChangeable();
|
||
|
|
invalidateKeys();
|
||
|
|
removeAllEntries();
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}//removeAll()//
|
||
|
|
/**
|
||
|
|
* @see IIntObjectHashMap.valueIterator()
|
||
|
|
*/
|
||
|
|
public IIterator valueIterator() {
|
||
|
|
return new ValueIterator(this);
|
||
|
|
}//valueIterator()//
|
||
|
|
}//IntObjectHashMap//
|