Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2014 Guidewire Software, Inc.
*/
package gw.util;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
/**
*/
public abstract class DerivedKeyHashMap implements Map {
private Object[] _table;
private int _size;
public DerivedKeyHashMap() {
_table = new Object[16];
_size = 0;
}
public DerivedKeyHashMap(Collection values) {
_table = new Object[(int) (values.size() / loadFactor())];
_size = 0;
for (V value : values) {
V existingValue = putImpl(getKeyForValue(value), value, _table, false);
if (existingValue != null) {
_size++;
}
}
}
// ----------------- Methods that subclasses can or must override -----------------
protected int hash(Object key) {
return key.hashCode();
}
protected abstract boolean keyMatches(Object key, V value);
protected abstract K getKeyForValue(V value);
protected abstract double loadFactor();
// ----------------- Map methods -----------------
public int size() {
return _size;
}
public boolean isEmpty() {
return size() == 0;
}
public boolean containsKey(Object key) {
if (key == null) {
throw new NullPointerException("containsKey on a DerivedKeyHashMap cannot be called with a null key");
} else {
return findValueWithMatchingKeyInChain(key, _table[bucket(key, _table.length)]) != null;
}
}
public V get(Object key) {
if (key == null) {
throw new NullPointerException("get on a DerivedKeyHashMap cannot be called with a null key");
} else {
return findValueWithMatchingKeyInChain(key, _table[bucket(key, _table.length)]);
}
}
@Override
public boolean containsValue(Object value) {
if (value == null) {
throw new NullPointerException("containsValue on a DerivedKeyHashMap cannot be called with a null argument");
}
for (int i = 0; i < _table.length; i++) {
if (hasMatchingValueInChain(value, _table[i])) {
return true;
}
}
return false;
}
@Override
public V put(K key, V value) {
if (value == null) {
throw new IllegalArgumentException("DerivedKeyHashMaps cannot currently be used with null values");
}
if (!getKeyForValue(value).equals(key)) {
throw new IllegalArgumentException("The derived key [" + getKeyForValue(value) + "] for value [" + value + "] does not match the supplied key [" + key + "]");
}
V existingValue = putImpl(key, value, _table, true);
if (existingValue == null) {
_size++;
}
return existingValue;
}
@Override
public V remove(Object key) {
if (key == null) {
return null;
}
V priorValue = null;
int bucket = bucket(key, _table.length);
if (_table[bucket] == null) {
// Nothing to do
} else if (_table[bucket] instanceof ChainedEntry) {
// The front of the bucket is a ChainedEntry, so we need to walk the chain and splice out the link
ChainedEntry previousLink = null;
ChainedEntry currentLink = (ChainedEntry) _table[bucket];
while (true) {
if (keyMatches(key, currentLink._entry)) {
// We have a match, so splice out the link
priorValue = currentLink._entry;
if (previousLink == null) {
// There's no prior link, so pull the next object directly into the table
_table[bucket] = currentLink._next;
} else {
// There's a prior link, so just splice out the current one
previousLink._next = currentLink._next;
}
break;
} else if (currentLink._next instanceof ChainedEntry) {
// Just
previousLink = currentLink;
currentLink = (ChainedEntry) currentLink._next;
} else {
// The next link in the chain is a direct entry. If it matches the key we're looking
// for, we need to remove the current link, as it's no longer necessary, and set
// the _next pointer (if any) of the prior link to point directly to the current link's
// entry
if (keyMatches(key, (V) currentLink._next)) {
priorValue = (V)currentLink._next;
if (previousLink == null) {
_table[bucket] = currentLink._entry;
} else {
previousLink._next = currentLink._entry;
}
}
break;
}
}
} else {
// The entry is directly in _table, so just null it out
priorValue = (V) _table[bucket];
_table[bucket] = null;
}
if (priorValue != null) {
_size--;
}
return priorValue;
}
@Override
public void putAll(Map extends K, ? extends V> m) {
// We want to validate all the values/entries BEFORE we make any modifications to the map, for the sake of consistency
for (Map.Entry extends K, ? extends V> entry : m.entrySet()) {
if (entry.getKey() == null) {
throw new IllegalArgumentException("Cannot add a value with a null key to a DerivedKeyHashMap");
} else if (entry.getValue() == null) {
throw new IllegalArgumentException("Cannot add a null value to a DerivedKeyHashMap");
} else if (!getKeyForValue(entry.getValue()).equals(entry.getKey())) {
throw new IllegalArgumentException("The derived key [" + getKeyForValue(entry.getValue()) + "] for value [" + entry.getValue() + "] does not match the supplied key [" + entry.getKey() + "]");
}
}
for (Map.Entry extends K, ? extends V> entry : m.entrySet()) {
V existingValue = putImpl(entry.getKey(), entry.getValue(), _table, false);
if (existingValue == null) {
_size++;
}
}
}
@Override
public void clear() {
_table = new Object[16];
_size = 0;
}
@Override
public Set> entrySet() {
return null;
}
public Set keySet() {
return new KeySet();
}
public Collection values() {
List values = new ArrayList();
for (int i = 0; i < _table.length; i++) {
if (_table[i] != null) {
if (_table[i] instanceof ChainedEntry) {
ChainedEntry entry = (ChainedEntry) _table[i];
values.add(entry._entry);
while (entry._next instanceof ChainedEntry) {
entry = (ChainedEntry) entry._next;
values.add(entry._entry);
}
values.add((V) entry._next);
} else {
values.add((V)_table[i]);
}
}
}
return values;
}
private V findValueWithMatchingKeyInChain(Object key, Object entry) {
if (entry == null) {
return null;
} else if (entry instanceof ChainedEntry) {
ChainedEntry chainedEntry = (ChainedEntry) entry;
if (keyMatches(key, chainedEntry._entry)) {
return chainedEntry._entry;
} else {
return findValueWithMatchingKeyInChain(key, chainedEntry._next);
}
} else {
if (keyMatches(key, (V) entry)) {
return (V) entry;
} else {
return null;
}
}
}
private boolean hasMatchingValueInChain(Object value, Object entry) {
if (entry == null) {
return false;
} else if (entry instanceof ChainedEntry) {
ChainedEntry chainedEntry = (ChainedEntry) entry;
if (chainedEntry._entry.equals(value)) {
return true;
} else {
return hasMatchingValueInChain(value, chainedEntry._next);
}
} else {
return entry.equals(value);
}
}
private int bucket(Object key, int tableLength) {
// This assumes that the hash codes will be evenly distributed with respect to all bytes;
// if the hash code doesn't have much entropy in the lower-order bits, this won't work out so well
return Math.abs(hash(key) % (tableLength));
}
public V putImpl(K key, V value, Object[] table, boolean resizeIfNecessary) {
if (key == null) {
throw new IllegalArgumentException("Cannot add a value with a null key to a DerivedKeyHashMap");
}
if (value == null) {
throw new IllegalArgumentException("Cannot add a null value to a DerivedKeyHashMap");
}
V priorValue = null;
int bucket = bucket(key, table.length);
if (table[bucket] == null) {
table[bucket] = value;
} else if (table[bucket] instanceof ChainedEntry) {
// The front of the bucket is a ChainedEntry, so we need to walk the chain
ChainedEntry lastChain = (ChainedEntry) table[bucket];
while (true) {
if (keyMatches(key, lastChain._entry)) {
// If the entry of the chain directly matches our value's key, then update it in place
priorValue = lastChain._entry;
lastChain._entry = value;
break;
} else if (lastChain._next instanceof ChainedEntry) {
// If the entry doesn't match and the next object is another chain entry, keep walking the chain
lastChain = (ChainedEntry) lastChain._next;
} else {
// If the next link in the chain isn't another chain link, either update the value pointer directly,
// if it matches this value's key, or
if (keyMatches(key, (V) lastChain._next)) {
priorValue = (V) lastChain._next;
lastChain._next = value;
} else {
ChainedEntry newChain = new ChainedEntry((V)lastChain._next, value);
lastChain._next = newChain;
}
break;
}
}
} else {
// The entry is directly in _table, so if the existing value there matches this key, overwrite it
// Otherwise, chain the new value in
if (keyMatches(key, (V) table[bucket])) {
priorValue = (V) table[bucket];
table[bucket] = value;
} else {
table[bucket] = new ChainedEntry((V)table[bucket], value);
}
}
return priorValue;
}
private void resize(int newTableSize) {
Object[] newTable = new Object[newTableSize];
for (V value : values()) {
putImpl(getKeyForValue(value), value, newTable, false);
}
_table = newTable;
}
private static class ChainedEntry {
private V _entry;
private Object _next;
private ChainedEntry(V entry, Object next) {
_entry = entry;
_next = next;
}
}
private class ValueIterator implements Iterator {
private int _bucket;
private Object _entry;
private ValueIterator() {
_bucket = -1;
_entry = null;
advanceIterator();
}
@Override
public boolean hasNext() {
return _entry != null;
}
@Override
public V next() {
V result;
if (_entry == null) {
throw new NoSuchElementException();
} else if (_entry instanceof ChainedEntry) {
result = ((ChainedEntry) _entry)._entry;
} else {
result = (V) _entry;
}
advanceIterator();
return result;
}
@Override
public void remove() {
//To change body of implemented methods use File | Settings | File Templates.
}
private void advanceIterator() {
if (_entry instanceof ChainedEntry) {
_entry = ((ChainedEntry) _entry)._next;
} else {
_entry = null;
for (int i = _bucket + 1; i < _table.length; i++) {
if (_table[i] != null) {
_bucket = i;
_entry = _table[i];
break;
}
}
}
}
}
private class KeyIterator implements Iterator {
private ValueIterator _valueIterator;
private KeyIterator() {
_valueIterator = new ValueIterator();
}
@Override
public boolean hasNext() {
return _valueIterator.hasNext();
}
@Override
public K next() {
return getKeyForValue(_valueIterator.next());
}
@Override
public void remove() {
_valueIterator.remove();
}
}
private class KeySet extends AbstractSet {
private KeySet() {
}
@Override
public int size() {
return DerivedKeyHashMap.this.size();
}
@Override
public boolean contains(Object o) {
return DerivedKeyHashMap.this.containsKey(o);
}
@Override
public Iterator iterator() {
return new KeyIterator();
}
@Override
public boolean add(K k) {
throw new UnsupportedOperationException("You cannot add directly to the key set for a Map; you must use put() on the Map instead");
}
@Override
public boolean remove(Object o) {
return DerivedKeyHashMap.this.remove(o) != null;
}
@Override
public boolean containsAll(Collection> c) {
if (c == null) {
throw new NullPointerException("containsAll(Collection) cannot be called with a null argument");
}
return super.containsAll(c);
}
@Override
public boolean addAll(Collection extends K> c) {
throw new UnsupportedOperationException("You cannot add directly to the key set for a Map; you must use put() on the Map instead");
}
@Override
public boolean retainAll(Collection> c) {
if (c == null) {
throw new NullPointerException("retainAll(Collection) cannot be called with a null argument");
}
for (Object o : c) {
if (o == null) {
throw new NullPointerException("The elements within the argument to retainAll(Collection) on the key set of a DerivedKeyHashMap cannot be null");
}
}
return super.retainAll(c);
}
@Override
public boolean removeAll(Collection> c) {
if (c == null) {
throw new NullPointerException("removeAll(Collection) cannot be called with a null argument");
}
for (Object o : c) {
if (o == null) {
throw new NullPointerException("The elements within the argument to removeAll(Collection) on the key set of a DerivedKeyHashMap cannot be null");
}
}
return super.removeAll(c);
}
@Override
public void clear() {
DerivedKeyHashMap.this.clear();
}
}
}