Initial commit from SVN.

This commit is contained in:
wcrisman
2014-05-30 10:31:51 -07:00
commit b45e56b890
1968 changed files with 370949 additions and 0 deletions

View File

@@ -0,0 +1,580 @@
/*
* 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;
import com.common.comparison.*;
/**
* A map collection that maps values by a key so that they may be looked up by that key.
* <p><b>Warning:</b> This class is NOT thread safe. To use it in a multi threaded environment all access to the map should by in a synchronization block.
*/
public class LiteHashMap extends Map implements IHashMap {
/** A reusable always empty map. */
public static final LiteHashMap EMPTY_MAP = new LiteHashMap(1);
static {
EMPTY_MAP.isChangeable(false);
}//static//
private LiteList keys = null;
/** Whether the map should maintain the counter for each map entry. If this is true then items added more than once to the map (same key/value pair) will increment the count, and removes will decrement the count. */
private boolean maintainCount = false;
/**
* The Entry wrappers the key/value pair.
*/
protected static class Entry extends BasicEntry {
protected Object key = null;
protected Object value = null;
protected int count = 1;
public Entry() {
super();
}//Entry()//
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
super.readExternal(in);
key = in.readObject();
value = in.readObject();
count = in.readInt();
//Ensure that null keys are valid.//
if(key == null) {
key = NULL_KEY;
}//if//
}//readExternal()//
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
super.writeExternal(out);
out.writeObject(key == NULL_KEY ? null : key);
out.writeObject(value);
out.writeInt(count);
}//writeExternal()//
public int createKeyHash() {
return key.hashCode();
}//createKeyHash()//
public String toString() {
return super.toString() + "\r\n\tKey: " + (key == NULL_KEY ? "null" : key.toString()) + "\r\n\tValue: " + value + (next != null ? "\r\n\t" + next.toString() : "");
}//toString()//
}//Entry//
public static class KeyIterator extends Iterator implements IReversableIterator {
public KeyIterator(LiteHashMap hashMap) {
super(hashMap);
}//KeyIterator()//
public Object next() {
Object result = ((Entry) nextEntry()).key;
if(result == NULL_KEY) {
result = null;
}//if//
return result;
}//next()//
public Object previous() {
Object result = ((Entry) previousEntry()).key;
if(result == NULL_KEY) {
result = null;
}//if//
return result;
}//previous()//
}//KeyIterator//
public static class ValueIterator extends Iterator implements IIterator {
public ValueIterator(LiteHashMap hashMap) {
super(hashMap);
}//ValueIterator()//
public Object next() {
return ((Entry) nextEntry()).value;
}//next()//
public Object previous() {
return ((Entry) previousEntry()).value;
}//previous()//
}//ValueIterator//
/**
* LiteHashMap constructor.
* <p>This constructor is private because is not advisable to use the default initial size because it will not be optimal for most applications.
*/
public LiteHashMap() {
super();
}//LiteHashMap()//
/**
* LiteHashMap 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 LiteHashMap(int initialCapacity) {
super(initialCapacity);
}//LiteHashMap()//
/**
* LiteHashMap 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 maintainCount Whether the map should maintain the counter for each map entry. If this is true then items added more than once to the map (same key/value pair) will increment the count, and removes will decrement the count.
*/
public LiteHashMap(int initialCapacity, boolean maintainCount) {
super(initialCapacity);
this.maintainCount = maintainCount;
}//LiteHashMap()//
/**
* LiteHashMap 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 LiteHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
}//LiteHashMap()//
/**
* LiteHashMap 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 maintainCount Whether the map should maintain the counter for each map entry. If this is true then items added more than once to the map (same key/value pair) will increment the count, and removes will decrement the count.
*/
public LiteHashMap(int initialCapacity, float loadFactor, boolean maintainCount) {
super(initialCapacity, loadFactor);
this.maintainCount = maintainCount;
}//LiteHashMap()//
/**
* LiteHashMap 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 keyComparator The comparator used to compare key objects.
* @param valueComparator The comparator used to compare value objects.
*/
public LiteHashMap(int initialCapacity, float loadFactor, IComparator keyComparator, IComparator valueComparator) {
super(initialCapacity, loadFactor, keyComparator, valueComparator);
}//LiteHashMap()//
/**
* LiteHashMap 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 keyComparator The comparator used to compare key objects.
* @param valueComparator The comparator used to compare value objects.
* @param maintainCount Whether the map should maintain the counter for each map entry. If this is true then items added more than once to the map (same key/value pair) will increment the count, and removes will decrement the count.
*/
public LiteHashMap(int initialCapacity, float loadFactor, IComparator keyComparator, IComparator valueComparator, boolean maintainCount) {
super(initialCapacity, loadFactor, keyComparator, valueComparator);
this.maintainCount = maintainCount;
}//LiteHashMap()//
/**
* LiteHashMap 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 keyComparator The comparator used to compare key objects.
* @param valueComparator The comparator used to compare value objects.
*/
public LiteHashMap(int initialCapacity, IComparator keyComparator, IComparator valueComparator) {
super(initialCapacity, keyComparator, valueComparator);
}//LiteHashMap()//
/**
* LiteHashMap constructor.
* @param keyComparator The comparator used to compare key objects.
* @param valueComparator The comparator used to compare value objects.
*/
public LiteHashMap(IComparator keyComparator, IComparator valueComparator) {
super(keyComparator, valueComparator);
}//LiteHashMap()//
/**
* LiteHashMap constructor.
* This constructor will copy an existing IHashMap.
* @param map A map to copy.
*/
public LiteHashMap(IHashMap map) {
super(map.getSize() > 10 ? map.getSize() : 10, map.getLoadFactor());
IIterator iterator = map.keyIterator();
//Iterate over the existing map's keys and put the key value pairs in this map.//
while(iterator.hasNext()) {
Object key = iterator.next();
Object value = map.get(key);
put(key, value);
}//while//
}//LiteHashMap()//
/**
* LiteHashMap constructor.
* This constructor will copy an existing IHashMap.
* @param map A map to copy.
*/
public LiteHashMap(LiteHashMap map) {
super(map.getSize() > 10 ? map.getSize() : 10, map.getLoadFactor(), map.getKeyComparator(), map.getValueComparator());
IIterator iterator = map.keyIterator();
//Iterate over the existing map's keys and put the key value pairs in this map.//
while(iterator.hasNext()) {
Object key = iterator.next();
Object value = map.get(key);
put(key, value);
}//while//
}//LiteHashMap()//
/**
* LiteHashMap constructor.
* @param initialSize The initial size of the map.
* @param initialKeyValuePairs The initial key/value pairs to be placed in the map. This should be an array of arrays where the inner array consists of a key object and a value object, no more, no less.
*/
public LiteHashMap(int initialSize, Object[][] initialKeyValuePairs) {
this(initialSize);
for(int index = 0; index < initialKeyValuePairs.length; index++) {
if(initialKeyValuePairs[index].length == 2) {
Object key = initialKeyValuePairs[index][0];
Object value = initialKeyValuePairs[index][1];
put(key, value);
}//if//
}//for//
}//LiteHashMap()//
/**
* LiteHashMap 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 keyComparator The comparator used to compare key objects.
* @param valueComparator The comparator used to compare value objects.
* @param keys The keys, or null if the value index is used.
* @param values The values, or null if the key index is used. If both values and keys are null then nothing is added to the map.
* @param isChangeable Whether the map is changeable after initialization.
*/
public LiteHashMap(int initialSize, float loadFactor, IComparator keyComparator, IComparator valueComparator, Object[] keys, Object[] values, boolean isChangeable) {
this(initialSize, loadFactor, keyComparator, valueComparator);
if(keys != null && values != null) {
for(int index = 0, max = Math.min(keys.length, values.length); index < max; index++) {
put(keys[index], values[index]);
}//for//
}//if//
else if(keys != null) {
for(int index = 0; index < keys.length; index++) {
put(keys[index], new Integer(index));
}//for//
}//else if//
else if(values != null) {
for(int index = 0; index < values.length; index++) {
put(new Integer(index), values[index]);
}//for//
}//else if//
}//LiteHashMap()//
/**
* Determines whether the key exists in the map.
* @param key The key to look for.
* @return Will be <code>true</code> if the key is already in the map.
*/
public boolean containsKey(Object 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()//
/**
* Gets the first key in the map.
* @return The first accessable key in the mapping.
*/
public Object getFirstKey() {
if(getSize() > 0) {
IBasicEntry[] entries = getEntries();
Object result = null;
for(int index = 0; (result == null) && (index < entries.length); index++) {
if(entries[index] != null) {
result = ((Entry) entries[index]).key;
}//if//
}//for//
return result;
}//if//
else {
throw new RuntimeException("No keys in the mapping.");
}//else//
}//getFirstKey()//
/**
* Gets an object in the map by its' key.
* @param key The key whose value should be retieved.
* @return The value associated with the key. A <code>null</code> value will be returned only if the key was not found.
*/
public Object get(Object key) {
//Ensure that null keys are valid.//
if(key == null) {
key = NULL_KEY;
}//if//
IBasicEntry[] entries = getEntries();
int hash = getKeyComparator().hash(key);
int index = (hash & 0x7FFFFFFF) % entries.length;
for(Entry entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
if((entry.hash == hash) && (Comparator.isEqual(getKeyComparator().compare(entry.key, key)))) {
return entry.value;
}//if//
}//for//
return null;
}//get()//
/**
* Gets the reference count for the map entry identified by the given key.
* @param key The map entry's key.
* @return The number of times the map entry (same exact key/value pair) has been added to the mapping.
*/
public int getCount(Object key) {
//Ensure that null keys are valid.//
if(key == null) {
key = NULL_KEY;
}//if//
IBasicEntry[] entries = getEntries();
int hash = getKeyComparator().hash(key);
int index = (hash & 0x7FFFFFFF) % entries.length;
for(Entry entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
if((entry.hash == hash) && (Comparator.isEqual(getKeyComparator().compare(entry.key, key)))) {
return entry.count;
}//if//
}//for//
return 0;
}//getCount()//
/**
* Gets 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 Object getKey(int index) {
if(keys == null) {
refreshKeys();
}//if//
return keys.get(index);
}//getKey()//
/**
* Gets the collection of all keys in the map.
* @param keys A collection that will contain the keys.
* @return The collection with the keys in it. This will be the same collection as the one passed if it is non-null.
*/
public IList getKeys(IList keys) {
if(this.keys == null) {
refreshKeys();
}//if//
if(keys == null) {
keys = new LiteList(this.keys.getSize(), 10);
}//if//
keys.addAll(this.keys);
return keys;
}//getKeys()//
/**
* Gets the collection of all keys in the map.
* @param array An array where key values will be placed.
* @return The count of keys placed in the array.
*/
public int getKeys(Object array) {
return getKeys(array, 0);
}//getKeys()//
/**
* Gets the collection of all keys in the map.
* @param array An array where key values will be placed.
* @param outputOffset The offset in the array where the first key value will be placed.
* @return The count of keys placed in the array.
*/
public int getKeys(Object array, int outputOffset) {
if(keys == null) {
refreshKeys();
}//if//
return keys.toArray(array, outputOffset);
}//getKeys()//
/**
* Invalidates 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;
}//invalidateKeys()//
/**
* Gets an iterator over the keys contained in this collection.
* @return An iterator over the map keys.
*/
public IIterator keyIterator() {
return new KeyIterator(this);
}//keyIterator()//
/**
* Places a key/value pair in the map.
* The value can be retrieved later with the given key.
* @param key The key that will be used to map the value.
* @param value The value stored in map. A <code>null</code> value will remove the key from the mapping.
* @return The value previously associated with the key.
*/
public Object put(Object key, Object value) {
Object result = null;
//Verify that the collection can be modified.//
verifyIsChangeable();
//Ensure that null keys are valid.//
if(key == null) {
key = NULL_KEY;
}//if//
if(value == null) {
//Remove the key if it exists because you cannot associate a key with a null value.//
result = remove(key);
}//if//
else {
IBasicEntry[] entries = getEntries();
int hash = getKeyComparator().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) && (Comparator.isEqual(getKeyComparator().compare(entry.key, key)))) {
if(maintainCount) {
if(getValueComparator().compare(entry.value, value) == Comparator.EQUAL) {
entry.count++;
}//if//
else {
throw new RuntimeException("Cannot replace one value with another in a map when maintaining a count.");
}//else//
}//if//
else {
Object oldValue = entry.value;
entry.value = value;
return oldValue;
}//else//
}//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) {
keys.add(key); //Just add the key instead of invalidating the keys collection.//
}//if//
}//else//
return result;
}//put()//
/**
* Recreates the collection of keys.
*/
protected void refreshKeys() {
IBasicEntry[] entries = getEntries();
int index;
Entry entry;
keys = new LiteList(getSize(), 20);
for(index = 0; index < entries.length; index++) {
for(entry = (Entry) entries[index]; entry != null; entry = (Entry) entry.next) {
Object key = entry.key;
//Ensure that null keys are valid.//
if(key == NULL_KEY) {
key = null;
}//if//
keys.add(key);
}//for//
}//for//
}//refreshKeys()//
/**
* Optimizes the collection of Entry objects to improve access time.
* @param arrayLength The new length of the entry array.
*/
protected void rehash(int arrayLength) {
super.rehash(arrayLength);
//Invalidate the list of keys.//
invalidateKeys();
}//rehash()//
/**
* Removes a key/value pair from the map.
* @param key The key that should be removed (with its' value) from the map.
* @return Will be the value removed from map. A <code>null</code> value is returned if the key was not found.
*/
public Object remove(Object key) {
//Verify that the collection can be modified.//
verifyIsChangeable();
//Ensure that null keys are valid.//
if(key == null) {
key = NULL_KEY;
}//if//
IBasicEntry[] entries = getEntries();
int hash = getKeyComparator().hash(key);
int index = (hash & 0x7FFFFFFF) % entries.length;
Entry previousEntry = null;
Entry entry = null;
Object result = null;
//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) && (Comparator.isEqual(getKeyComparator().compare(entry.key, key)))) {
//Save the removed value.//
result = entry.value;
if(--entry.count == 0) {
//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();
}//if//
//Break from the loop so we can exit.//
break;
}//if//
previousEntry = entry;
}//for//
return result;
}//remove()//
/**
* Removes all key/value pairs from the map.
*/
public void removeAll() {
//Verify that the collection can be modified.//
verifyIsChangeable();
invalidateKeys();
removeAllEntries();
}//removeAll()//
/**
* Gets the collection of all keys in the map.
* @param keys An array of the necessary type to old the key values.
* @return The collection with the keys in it. This will be the same collection as the one passed if it is non-null.
*/
public int toKeyArray(Object keyArray) {
if(keys == null) {
refreshKeys();
}//if//
return keys.toArray(keyArray);
}//toKeyArray()//
/**
* Gets an iterator over the values contained in this collection.
* @return An iterator over the map values.
*/
public IIterator valueIterator() {
return new ValueIterator(this);
}//valueIterator()//
}//HashMap//