Merging from -r468106:814127 of collections_jdk5_branch - namely where this code was generified; mostly in r738956.

Also see the following revisions:

    ------------------------------------------------------------------------
    r813954 | sebb | 2009-09-11 10:50:42 -0700 (Fri, 11 Sep 2009) | 2 lines
    
    Make private immutable variables final
    Add missing @Override markers and fix some raw types
    ------------------------------------------------------------------------
    r740150 | mbenson | 2009-02-02 15:24:00 -0800 (Mon, 02 Feb 2009) | 1 line
    
    make all [collections] maps implement IterableMap
    ------------------------------------------------------------------------


git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@815083 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Henri Yandell 2009-09-15 05:56:15 +00:00
parent 8d92a78bb6
commit 480b6ed7b7
1 changed files with 82 additions and 71 deletions

View File

@ -101,14 +101,14 @@ import org.apache.commons.collections.KeyValue;
* @author Janek Bogucki * @author Janek Bogucki
* @author Kazuya Ujihara * @author Kazuya Ujihara
*/ */
public final class StaticBucketMap implements Map { public final class StaticBucketMap<K, V> extends AbstractIterableMap<K, V> {
/** The default number of buckets to use */ /** The default number of buckets to use */
private static final int DEFAULT_BUCKETS = 255; private static final int DEFAULT_BUCKETS = 255;
/** The array of buckets, where the actual data is held */ /** The array of buckets, where the actual data is held */
private Node[] buckets; private final Node<K, V>[] buckets;
/** The matching array of locks */ /** The matching array of locks */
private Lock[] locks; private final Lock[] locks;
/** /**
* Initializes the map with the default number of buckets (255). * Initializes the map with the default number of buckets (255).
@ -127,6 +127,7 @@ public final class StaticBucketMap implements Map {
* *
* @param numBuckets the number of buckets for this map * @param numBuckets the number of buckets for this map
*/ */
@SuppressWarnings("unchecked")
public StaticBucketMap(int numBuckets) { public StaticBucketMap(int numBuckets) {
int size = Math.max(17, numBuckets); int size = Math.max(17, numBuckets);
@ -202,11 +203,11 @@ public final class StaticBucketMap implements Map {
* @param key the key to retrieve * @param key the key to retrieve
* @return the associated value * @return the associated value
*/ */
public Object get(final Object key) { public V get(final Object key) {
int hash = getHash(key); int hash = getHash(key);
synchronized (locks[hash]) { synchronized (locks[hash]) {
Node n = buckets[hash]; Node<K, V> n = buckets[hash];
while (n != null) { while (n != null) {
if (n.key == key || (n.key != null && n.key.equals(key))) { if (n.key == key || (n.key != null && n.key.equals(key))) {
@ -229,7 +230,7 @@ public final class StaticBucketMap implements Map {
int hash = getHash(key); int hash = getHash(key);
synchronized (locks[hash]) { synchronized (locks[hash]) {
Node n = buckets[hash]; Node<K, V> n = buckets[hash];
while (n != null) { while (n != null) {
if (n.key == key || (n.key != null && n.key.equals(key))) { if (n.key == key || (n.key != null && n.key.equals(key))) {
@ -251,7 +252,7 @@ public final class StaticBucketMap implements Map {
public boolean containsValue(final Object value) { public boolean containsValue(final Object value) {
for (int i = 0; i < buckets.length; i++) { for (int i = 0; i < buckets.length; i++) {
synchronized (locks[i]) { synchronized (locks[i]) {
Node n = buckets[i]; Node<K, V> n = buckets[i];
while (n != null) { while (n != null) {
if (n.value == value || (n.value != null && n.value.equals(value))) { if (n.value == value || (n.value != null && n.value.equals(value))) {
@ -273,14 +274,14 @@ public final class StaticBucketMap implements Map {
* @param value the value to use * @param value the value to use
* @return the previous mapping for the key * @return the previous mapping for the key
*/ */
public Object put(final Object key, final Object value) { public V put(final K key, final V value) {
int hash = getHash(key); int hash = getHash(key);
synchronized (locks[hash]) { synchronized (locks[hash]) {
Node n = buckets[hash]; Node<K, V> n = buckets[hash];
if (n == null) { if (n == null) {
n = new Node(); n = new Node<K, V>();
n.key = key; n.key = key;
n.value = value; n.value = value;
buckets[hash] = n; buckets[hash] = n;
@ -291,11 +292,11 @@ public final class StaticBucketMap implements Map {
// Set n to the last node in the linked list. Check each key along the way // Set n to the last node in the linked list. Check each key along the way
// If the key is found, then change the value of that node and return // If the key is found, then change the value of that node and return
// the old value. // the old value.
for (Node next = n; next != null; next = next.next) { for (Node<K, V> next = n; next != null; next = next.next) {
n = next; n = next;
if (n.key == key || (n.key != null && n.key.equals(key))) { if (n.key == key || (n.key != null && n.key.equals(key))) {
Object returnVal = n.value; V returnVal = n.value;
n.value = value; n.value = value;
return returnVal; return returnVal;
} }
@ -303,7 +304,7 @@ public final class StaticBucketMap implements Map {
// The key was not found in the current list of nodes, add it to the end // The key was not found in the current list of nodes, add it to the end
// in a new node. // in a new node.
Node newNode = new Node(); Node<K, V> newNode = new Node<K, V>();
newNode.key = key; newNode.key = key;
newNode.value = value; newNode.value = value;
n.next = newNode; n.next = newNode;
@ -318,12 +319,12 @@ public final class StaticBucketMap implements Map {
* @param key the key to remove * @param key the key to remove
* @return the previous value at this key * @return the previous value at this key
*/ */
public Object remove(Object key) { public V remove(Object key) {
int hash = getHash(key); int hash = getHash(key);
synchronized (locks[hash]) { synchronized (locks[hash]) {
Node n = buckets[hash]; Node<K, V> n = buckets[hash];
Node prev = null; Node<K, V> prev = null;
while (n != null) { while (n != null) {
if (n.key == key || (n.key != null && n.key.equals(key))) { if (n.key == key || (n.key != null && n.key.equals(key))) {
@ -352,7 +353,7 @@ public final class StaticBucketMap implements Map {
* *
* @return the key set * @return the key set
*/ */
public Set keySet() { public Set<K> keySet() {
return new KeySet(); return new KeySet();
} }
@ -361,7 +362,7 @@ public final class StaticBucketMap implements Map {
* *
* @return the values * @return the values
*/ */
public Collection values() { public Collection<V> values() {
return new Values(); return new Values();
} }
@ -370,7 +371,7 @@ public final class StaticBucketMap implements Map {
* *
* @return the entry set * @return the entry set
*/ */
public Set entrySet() { public Set<Map.Entry<K, V>> entrySet() {
return new EntrySet(); return new EntrySet();
} }
@ -381,11 +382,8 @@ public final class StaticBucketMap implements Map {
* *
* @param map the map of entries to add * @param map the map of entries to add
*/ */
public void putAll(Map map) { public void putAll(Map<? extends K, ? extends V> map) {
Iterator i = map.entrySet().iterator(); for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
while (i.hasNext()) {
Map.Entry entry = (Entry) i.next();
put(entry.getKey(), entry.getValue()); put(entry.getKey(), entry.getValue());
} }
} }
@ -409,14 +407,15 @@ public final class StaticBucketMap implements Map {
* @param obj the object to compare to * @param obj the object to compare to
* @return true if equal * @return true if equal
*/ */
@Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == this) { if (obj == this) {
return true; return true;
} }
if (obj instanceof Map == false) { if (obj instanceof Map<?, ?> == false) {
return false; return false;
} }
Map other = (Map) obj; Map<?, ?> other = (Map<?, ?>) obj;
return entrySet().equals(other.entrySet()); return entrySet().equals(other.entrySet());
} }
@ -425,12 +424,13 @@ public final class StaticBucketMap implements Map {
* *
* @return the hash code * @return the hash code
*/ */
@Override
public int hashCode() { public int hashCode() {
int hashCode = 0; int hashCode = 0;
for (int i = 0; i < buckets.length; i++) { for (int i = 0; i < buckets.length; i++) {
synchronized (locks[i]) { synchronized (locks[i]) {
Node n = buckets[i]; Node<K, V> n = buckets[i];
while (n != null) { while (n != null) {
hashCode += n.hashCode(); hashCode += n.hashCode();
@ -445,46 +445,47 @@ public final class StaticBucketMap implements Map {
/** /**
* The Map.Entry for the StaticBucketMap. * The Map.Entry for the StaticBucketMap.
*/ */
private static final class Node implements Map.Entry, KeyValue { private static final class Node<K, V> implements Map.Entry<K, V>, KeyValue<K, V> {
protected Object key; protected K key;
protected Object value; protected V value;
protected Node next; protected Node<K, V> next;
public Object getKey() { public K getKey() {
return key; return key;
} }
public Object getValue() { public V getValue() {
return value; return value;
} }
@Override
public int hashCode() { public int hashCode() {
return ((key == null ? 0 : key.hashCode()) ^ return ((key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode())); (value == null ? 0 : value.hashCode()));
} }
@Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == this) { if (obj == this) {
return true; return true;
} }
if (obj instanceof Map.Entry == false) { if (obj instanceof Map.Entry<?, ?> == false) {
return false; return false;
} }
Map.Entry e2 = (Map.Entry) obj; Map.Entry<?, ?> e2 = (Map.Entry<?, ?>) obj;
return ( return (
(key == null ? e2.getKey() == null : key.equals(e2.getKey())) && (key == null ? e2.getKey() == null : key.equals(e2.getKey())) &&
(value == null ? e2.getValue() == null : value.equals(e2.getValue()))); (value == null ? e2.getValue() == null : value.equals(e2.getValue())));
} }
public Object setValue(Object obj) { public V setValue(V obj) {
Object retVal = value; V retVal = value;
value = obj; value = obj;
return retVal; return retVal;
} }
} }
/** /**
* The lock object, which also includes a count of the nodes in this lock. * The lock object, which also includes a count of the nodes in this lock.
*/ */
@ -492,20 +493,17 @@ public final class StaticBucketMap implements Map {
public int size; public int size;
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
private class EntryIterator implements Iterator { private class BaseIterator {
private ArrayList<Map.Entry<K, V>> current = new ArrayList<Map.Entry<K,V>>();
private ArrayList current = new ArrayList();
private int bucket; private int bucket;
private Map.Entry last; private Map.Entry<K, V> last;
public boolean hasNext() { public boolean hasNext() {
if (current.size() > 0) return true; if (current.size() > 0) return true;
while (bucket < buckets.length) { while (bucket < buckets.length) {
synchronized (locks[bucket]) { synchronized (locks[bucket]) {
Node n = buckets[bucket]; Node<K, V> n = buckets[bucket];
while (n != null) { while (n != null) {
current.add(n); current.add(n);
n = n.next; n = n.next;
@ -517,73 +515,81 @@ public final class StaticBucketMap implements Map {
return false; return false;
} }
protected Map.Entry nextEntry() { protected Map.Entry<K, V> nextEntry() {
if (!hasNext()) throw new NoSuchElementException(); if (!hasNext()) throw new NoSuchElementException();
last = (Map.Entry)current.remove(current.size() - 1); last = current.remove(current.size() - 1);
return last; return last;
} }
public Object next() {
return nextEntry();
}
public void remove() { public void remove() {
if (last == null) throw new IllegalStateException(); if (last == null) throw new IllegalStateException();
StaticBucketMap.this.remove(last.getKey()); StaticBucketMap.this.remove(last.getKey());
last = null; last = null;
} }
}
private class EntryIterator extends BaseIterator implements Iterator<Map.Entry<K, V>> {
public Map.Entry<K, V> next() {
return nextEntry();
}
} }
private class ValueIterator extends EntryIterator { private class ValueIterator extends BaseIterator implements Iterator<V> {
public Object next() { public V next() {
return nextEntry().getValue(); return nextEntry().getValue();
} }
} }
private class KeyIterator extends EntryIterator { private class KeyIterator extends BaseIterator implements Iterator<K> {
public Object next() { public K next() {
return nextEntry().getKey(); return nextEntry().getKey();
} }
} }
private class EntrySet extends AbstractSet { private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
@Override
public int size() { public int size() {
return StaticBucketMap.this.size(); return StaticBucketMap.this.size();
} }
@Override
public void clear() { public void clear() {
StaticBucketMap.this.clear(); StaticBucketMap.this.clear();
} }
public Iterator iterator() { @Override
public Iterator<Map.Entry<K, V>> iterator() {
return new EntryIterator(); return new EntryIterator();
} }
@Override
public boolean contains(Object obj) { public boolean contains(Object obj) {
Map.Entry entry = (Map.Entry) obj; Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
int hash = getHash(entry.getKey()); int hash = getHash(entry.getKey());
synchronized (locks[hash]) { synchronized (locks[hash]) {
for (Node n = buckets[hash]; n != null; n = n.next) { for (Node<K, V> n = buckets[hash]; n != null; n = n.next) {
if (n.equals(entry)) return true; if (n.equals(entry)) return true;
} }
} }
return false; return false;
} }
@Override
public boolean remove(Object obj) { public boolean remove(Object obj) {
if (obj instanceof Map.Entry == false) { if (obj instanceof Map.Entry<?, ?> == false) {
return false; return false;
} }
Map.Entry entry = (Map.Entry) obj; Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
int hash = getHash(entry.getKey()); int hash = getHash(entry.getKey());
synchronized (locks[hash]) { synchronized (locks[hash]) {
for (Node n = buckets[hash]; n != null; n = n.next) { for (Node<K, V> n = buckets[hash]; n != null; n = n.next) {
if (n.equals(entry)) { if (n.equals(entry)) {
StaticBucketMap.this.remove(n.getKey()); StaticBucketMap.this.remove(n.getKey());
return true; return true;
@ -595,29 +601,33 @@ public final class StaticBucketMap implements Map {
} }
private class KeySet extends AbstractSet<K> {
private class KeySet extends AbstractSet { @Override
public int size() { public int size() {
return StaticBucketMap.this.size(); return StaticBucketMap.this.size();
} }
@Override
public void clear() { public void clear() {
StaticBucketMap.this.clear(); StaticBucketMap.this.clear();
} }
public Iterator iterator() { @Override
public Iterator<K> iterator() {
return new KeyIterator(); return new KeyIterator();
} }
@Override
public boolean contains(Object obj) { public boolean contains(Object obj) {
return StaticBucketMap.this.containsKey(obj); return StaticBucketMap.this.containsKey(obj);
} }
@Override
public boolean remove(Object obj) { public boolean remove(Object obj) {
int hash = getHash(obj); int hash = getHash(obj);
synchronized (locks[hash]) { synchronized (locks[hash]) {
for (Node n = buckets[hash]; n != null; n = n.next) { for (Node<K, V> n = buckets[hash]; n != null; n = n.next) {
Object k = n.getKey(); Object k = n.getKey();
if ((k == obj) || ((k != null) && k.equals(obj))) { if ((k == obj) || ((k != null) && k.equals(obj))) {
StaticBucketMap.this.remove(k); StaticBucketMap.this.remove(k);
@ -626,29 +636,30 @@ public final class StaticBucketMap implements Map {
} }
} }
return false; return false;
} }
} }
private class Values extends AbstractCollection { private class Values extends AbstractCollection<V> {
@Override
public int size() { public int size() {
return StaticBucketMap.this.size(); return StaticBucketMap.this.size();
} }
@Override
public void clear() { public void clear() {
StaticBucketMap.this.clear(); StaticBucketMap.this.clear();
} }
public Iterator iterator() { @Override
public Iterator<V> iterator() {
return new ValueIterator(); return new ValueIterator();
} }
} }
/** /**
* Prevents any operations from occurring on this map while the * Prevents any operations from occurring on this map while the
* given {@link Runnable} executes. This method can be used, for * given {@link Runnable} executes. This method can be used, for