Initial commit from SVN.
This commit is contained in:
299
Common/src/com/common/util/optimized/LongObjectHashMap.java
Normal file
299
Common/src/com/common/util/optimized/LongObjectHashMap.java
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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 LongObjectHashMap extends Map implements ILongObjectHashMap {
|
||||
private long[] keys = null;
|
||||
private int keyCount = 0;
|
||||
|
||||
/**
|
||||
* The Entry wrappers the key/value pair.
|
||||
*/
|
||||
protected static class Entry extends BasicEntry {
|
||||
public long 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.readLong();
|
||||
value = in.readObject();
|
||||
}//readExternal()//
|
||||
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||||
super.writeExternal(out);
|
||||
out.writeLong(key);
|
||||
out.writeObject(value);
|
||||
}//writeExternal()//
|
||||
public int createKeyHash() {
|
||||
return (int) 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 ILongIterator {
|
||||
public KeyIterator(LongObjectHashMap hashMap) {
|
||||
super(hashMap);
|
||||
}//KeyIterator()//
|
||||
public long next() {
|
||||
return ((Entry) nextEntry()).key;
|
||||
}//next()//
|
||||
public long previous() {
|
||||
return ((Entry) previousEntry()).key;
|
||||
}//previous()//
|
||||
}//KeyIterator//
|
||||
|
||||
public static class ValueIterator extends Iterator implements IReversableIterator {
|
||||
public ValueIterator(LongObjectHashMap hashMap) {
|
||||
super(hashMap);
|
||||
}//ValueIterator()//
|
||||
public Object next() {
|
||||
return ((Entry) nextEntry()).value;
|
||||
}//next()//
|
||||
public Object previous() {
|
||||
return ((Entry) previousEntry()).value;
|
||||
}//previous()//
|
||||
}//ValueIterator//
|
||||
/**
|
||||
* LongObjectHashMap constructor.
|
||||
*/
|
||||
public LongObjectHashMap() {
|
||||
this(DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, DEFAULT_VALUE_COMPARATOR);
|
||||
}//LongObjectHashMap()//
|
||||
/**
|
||||
* LongObjectHashMap 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 LongObjectHashMap(int initialCapacity) {
|
||||
this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_VALUE_COMPARATOR);
|
||||
}//LongObjectHashMap()//
|
||||
/**
|
||||
* LongObjectHashMap 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 LongObjectHashMap(int initialCapacity, float loadFactor) {
|
||||
this(initialCapacity, loadFactor, DEFAULT_VALUE_COMPARATOR);
|
||||
}//LongObjectHashMap()//
|
||||
/**
|
||||
* LongObjectHashMap 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 LongObjectHashMap(int initialCapacity, float loadFactor, IComparator valueComparator) {
|
||||
super(initialCapacity, loadFactor, null, valueComparator);
|
||||
}//LongObjectHashMap()//
|
||||
/**
|
||||
* LongObjectHashMap 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 LongObjectHashMap(int initialCapacity, IComparator valueComparator) {
|
||||
this(initialCapacity, DEFAULT_LOAD_FACTOR, valueComparator);
|
||||
}//LongObjectHashMap()//
|
||||
/**
|
||||
* @see ILongObjectHashMap.containsKey(long)
|
||||
*/
|
||||
public boolean containsKey(long key) {
|
||||
return get(key) != null;
|
||||
}//containsKey()//
|
||||
/**
|
||||
* Creates an entry object of the specific type used by this map.
|
||||
* @return An entry object that can be filled and passed to the addEntry method.
|
||||
*/
|
||||
protected IBasicEntry createEntry() {
|
||||
return new Entry();
|
||||
}//createEntry()//
|
||||
/**
|
||||
* @see ILongObjectHashMap.get(long)
|
||||
*/
|
||||
public Object get(long key) {
|
||||
IBasicEntry[] entries = getEntries();
|
||||
int hash = (int) 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 long 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 ILongObjectHashMap.keyIterator()
|
||||
*/
|
||||
public ILongIterator keyIterator() {
|
||||
return new KeyIterator(this);
|
||||
}//keyIterator()//
|
||||
/**
|
||||
* @see ILongObjectHashMap.put(long, Object)
|
||||
*/
|
||||
public Object put(long 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 = (int) 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) {
|
||||
long[] temp = new long[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 long[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 ILongObjectHashMap.remove(long)
|
||||
*/
|
||||
public Object remove(long key) {
|
||||
IBasicEntry[] entries = getEntries();
|
||||
int hash = (int) 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 ILongObjectHashMap.valueIterator()
|
||||
*/
|
||||
public IIterator valueIterator() {
|
||||
return new ValueIterator(this);
|
||||
}//valueIterator()//
|
||||
}//LongObjectHashMap//
|
||||
Reference in New Issue
Block a user