Remove FastArrayList, FastHashMap, FastTreeMap
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/branches/collections_jdk5_branch@471163 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
cda4ce8d78
commit
dacbc93ded
|
@ -28,6 +28,13 @@ Changes from commons-collections
|
|||
--------------------------------
|
||||
- Removed all deprecated classes and methods
|
||||
|
||||
- Removed FastArrayList
|
||||
- use CopyOnWriteList
|
||||
- Removed FastHashMap
|
||||
- use ConcurrentHashMap, but beware null keys and values
|
||||
- Removed FastTreeSet
|
||||
- no direct replacement - use ConcurrentHashMap or synchronized TreeMap
|
||||
|
||||
|
||||
Feedback
|
||||
--------
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,715 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.collections;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>A customized implementation of <code>java.util.HashMap</code> designed
|
||||
* to operate in a multithreaded environment where the large majority of
|
||||
* method calls are read-only, instead of structural changes. When operating
|
||||
* in "fast" mode, read calls are non-synchronized and write calls perform the
|
||||
* following steps:</p>
|
||||
* <ul>
|
||||
* <li>Clone the existing collection
|
||||
* <li>Perform the modification on the clone
|
||||
* <li>Replace the existing collection with the (modified) clone
|
||||
* </ul>
|
||||
* <p>When first created, objects of this class default to "slow" mode, where
|
||||
* all accesses of any type are synchronized but no cloning takes place. This
|
||||
* is appropriate for initially populating the collection, followed by a switch
|
||||
* to "fast" mode (by calling <code>setFast(true)</code>) after initialization
|
||||
* is complete.</p>
|
||||
*
|
||||
* <p><strong>NOTE</strong>: If you are creating and accessing a
|
||||
* <code>HashMap</code> only within a single thread, you should use
|
||||
* <code>java.util.HashMap</code> directly (with no synchronization), for
|
||||
* maximum performance.</p>
|
||||
*
|
||||
* <p><strong>NOTE</strong>: <i>This class is not cross-platform.
|
||||
* Using it may cause unexpected failures on some architectures.</i>
|
||||
* It suffers from the same problems as the double-checked locking idiom.
|
||||
* In particular, the instruction that clones the internal collection and the
|
||||
* instruction that sets the internal reference to the clone can be executed
|
||||
* or perceived out-of-order. This means that any read operation might fail
|
||||
* unexpectedly, as it may be reading the state of the internal collection
|
||||
* before the internal collection is fully formed.
|
||||
* For more information on the double-checked locking idiom, see the
|
||||
* <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">
|
||||
* Double-Checked Locking Idiom Is Broken Declaration</a>.</p>
|
||||
*
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public class FastHashMap extends HashMap {
|
||||
|
||||
/**
|
||||
* The underlying map we are managing.
|
||||
*/
|
||||
protected HashMap map = null;
|
||||
|
||||
/**
|
||||
* Are we currently operating in "fast" mode?
|
||||
*/
|
||||
protected boolean fast = false;
|
||||
|
||||
// Constructors
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Construct an empty map.
|
||||
*/
|
||||
public FastHashMap() {
|
||||
super();
|
||||
this.map = new HashMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty map with the specified capacity.
|
||||
*
|
||||
* @param capacity the initial capacity of the empty map
|
||||
*/
|
||||
public FastHashMap(int capacity) {
|
||||
super();
|
||||
this.map = new HashMap(capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty map with the specified capacity and load factor.
|
||||
*
|
||||
* @param capacity the initial capacity of the empty map
|
||||
* @param factor the load factor of the new map
|
||||
*/
|
||||
public FastHashMap(int capacity, float factor) {
|
||||
super();
|
||||
this.map = new HashMap(capacity, factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new map with the same mappings as the specified map.
|
||||
*
|
||||
* @param map the map whose mappings are to be copied
|
||||
*/
|
||||
public FastHashMap(Map map) {
|
||||
super();
|
||||
this.map = new HashMap(map);
|
||||
}
|
||||
|
||||
|
||||
// Property access
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if this map is operating in fast mode.
|
||||
*
|
||||
* @return true if this map is operating in fast mode
|
||||
*/
|
||||
public boolean getFast() {
|
||||
return (this.fast);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this map is operating in fast mode.
|
||||
*
|
||||
* @param fast true if this map should operate in fast mode
|
||||
*/
|
||||
public void setFast(boolean fast) {
|
||||
this.fast = fast;
|
||||
}
|
||||
|
||||
|
||||
// Map access
|
||||
// ----------------------------------------------------------------------
|
||||
// These methods can forward straight to the wrapped Map in 'fast' mode.
|
||||
// (because they are query methods)
|
||||
|
||||
/**
|
||||
* Return the value to which this map maps the specified key. Returns
|
||||
* <code>null</code> if the map contains no mapping for this key, or if
|
||||
* there is a mapping with a value of <code>null</code>. Use the
|
||||
* <code>containsKey()</code> method to disambiguate these cases.
|
||||
*
|
||||
* @param key the key whose value is to be returned
|
||||
* @return the value mapped to that key, or null
|
||||
*/
|
||||
public Object get(Object key) {
|
||||
if (fast) {
|
||||
return (map.get(key));
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of key-value mappings in this map.
|
||||
*
|
||||
* @return the current size of the map
|
||||
*/
|
||||
public int size() {
|
||||
if (fast) {
|
||||
return (map.size());
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if this map contains no mappings.
|
||||
*
|
||||
* @return is the map currently empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
if (fast) {
|
||||
return (map.isEmpty());
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.isEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if this map contains a mapping for the
|
||||
* specified key.
|
||||
*
|
||||
* @param key the key to be searched for
|
||||
* @return true if the map contains the key
|
||||
*/
|
||||
public boolean containsKey(Object key) {
|
||||
if (fast) {
|
||||
return (map.containsKey(key));
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.containsKey(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if this map contains one or more keys mapping
|
||||
* to the specified value.
|
||||
*
|
||||
* @param value the value to be searched for
|
||||
* @return true if the map contains the value
|
||||
*/
|
||||
public boolean containsValue(Object value) {
|
||||
if (fast) {
|
||||
return (map.containsValue(value));
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.containsValue(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Map modification
|
||||
// ----------------------------------------------------------------------
|
||||
// These methods perform special behaviour in 'fast' mode.
|
||||
// The map is cloned, updated and then assigned back.
|
||||
// See the comments at the top as to why this won't always work.
|
||||
|
||||
/**
|
||||
* Associate the specified value with the specified key in this map.
|
||||
* If the map previously contained a mapping for this key, the old
|
||||
* value is replaced and returned.
|
||||
*
|
||||
* @param key the key with which the value is to be associated
|
||||
* @param value the value to be associated with this key
|
||||
* @return the value previously mapped to the key, or null
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
if (fast) {
|
||||
synchronized (this) {
|
||||
HashMap temp = (HashMap) map.clone();
|
||||
Object result = temp.put(key, value);
|
||||
map = temp;
|
||||
return (result);
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.put(key, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all of the mappings from the specified map to this one, replacing
|
||||
* any mappings with the same keys.
|
||||
*
|
||||
* @param in the map whose mappings are to be copied
|
||||
*/
|
||||
public void putAll(Map in) {
|
||||
if (fast) {
|
||||
synchronized (this) {
|
||||
HashMap temp = (HashMap) map.clone();
|
||||
temp.putAll(in);
|
||||
map = temp;
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
map.putAll(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any mapping for this key, and return any previously
|
||||
* mapped value.
|
||||
*
|
||||
* @param key the key whose mapping is to be removed
|
||||
* @return the value removed, or null
|
||||
*/
|
||||
public Object remove(Object key) {
|
||||
if (fast) {
|
||||
synchronized (this) {
|
||||
HashMap temp = (HashMap) map.clone();
|
||||
Object result = temp.remove(key);
|
||||
map = temp;
|
||||
return (result);
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.remove(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all mappings from this map.
|
||||
*/
|
||||
public void clear() {
|
||||
if (fast) {
|
||||
synchronized (this) {
|
||||
map = new HashMap();
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
map.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Basic object methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compare the specified object with this list for equality. This
|
||||
* implementation uses exactly the code that is used to define the
|
||||
* list equals function in the documentation for the
|
||||
* <code>Map.equals</code> method.
|
||||
*
|
||||
* @param o the object to be compared to this list
|
||||
* @return true if the two maps are equal
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
// Simple tests that require no synchronization
|
||||
if (o == this) {
|
||||
return (true);
|
||||
} else if (!(o instanceof Map)) {
|
||||
return (false);
|
||||
}
|
||||
Map mo = (Map) o;
|
||||
|
||||
// Compare the two maps for equality
|
||||
if (fast) {
|
||||
if (mo.size() != map.size()) {
|
||||
return (false);
|
||||
}
|
||||
Iterator i = map.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Map.Entry e = (Map.Entry) i.next();
|
||||
Object key = e.getKey();
|
||||
Object value = e.getValue();
|
||||
if (value == null) {
|
||||
if (!(mo.get(key) == null && mo.containsKey(key))) {
|
||||
return (false);
|
||||
}
|
||||
} else {
|
||||
if (!value.equals(mo.get(key))) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
|
||||
} else {
|
||||
synchronized (map) {
|
||||
if (mo.size() != map.size()) {
|
||||
return (false);
|
||||
}
|
||||
Iterator i = map.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Map.Entry e = (Map.Entry) i.next();
|
||||
Object key = e.getKey();
|
||||
Object value = e.getValue();
|
||||
if (value == null) {
|
||||
if (!(mo.get(key) == null && mo.containsKey(key))) {
|
||||
return (false);
|
||||
}
|
||||
} else {
|
||||
if (!value.equals(mo.get(key))) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash code value for this map. This implementation uses
|
||||
* exactly the code that is used to define the list hash function in the
|
||||
* documentation for the <code>Map.hashCode</code> method.
|
||||
*
|
||||
* @return suitable integer hash code
|
||||
*/
|
||||
public int hashCode() {
|
||||
if (fast) {
|
||||
int h = 0;
|
||||
Iterator i = map.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
h += i.next().hashCode();
|
||||
}
|
||||
return (h);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
int h = 0;
|
||||
Iterator i = map.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
h += i.next().hashCode();
|
||||
}
|
||||
return (h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a shallow copy of this <code>FastHashMap</code> instance.
|
||||
* The keys and values themselves are not copied.
|
||||
*
|
||||
* @return a clone of this map
|
||||
*/
|
||||
public Object clone() {
|
||||
FastHashMap results = null;
|
||||
if (fast) {
|
||||
results = new FastHashMap(map);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
results = new FastHashMap(map);
|
||||
}
|
||||
}
|
||||
results.setFast(getFast());
|
||||
return (results);
|
||||
}
|
||||
|
||||
// Map views
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return a collection view of the mappings contained in this map. Each
|
||||
* element in the returned collection is a <code>Map.Entry</code>.
|
||||
*/
|
||||
public Set entrySet() {
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a set view of the keys contained in this map.
|
||||
*/
|
||||
public Set keySet() {
|
||||
return new KeySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a collection view of the values contained in this map.
|
||||
*/
|
||||
public Collection values() {
|
||||
return new Values();
|
||||
}
|
||||
|
||||
// Map view inner classes
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Abstract collection implementation shared by keySet(), values() and entrySet().
|
||||
*/
|
||||
private abstract class CollectionView implements Collection {
|
||||
|
||||
public CollectionView() {
|
||||
}
|
||||
|
||||
protected abstract Collection get(Map map);
|
||||
protected abstract Object iteratorNext(Map.Entry entry);
|
||||
|
||||
|
||||
public void clear() {
|
||||
if (fast) {
|
||||
synchronized (FastHashMap.this) {
|
||||
map = new HashMap();
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
get(map).clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
if (fast) {
|
||||
synchronized (FastHashMap.this) {
|
||||
HashMap temp = (HashMap) map.clone();
|
||||
boolean r = get(temp).remove(o);
|
||||
map = temp;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).remove(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection o) {
|
||||
if (fast) {
|
||||
synchronized (FastHashMap.this) {
|
||||
HashMap temp = (HashMap) map.clone();
|
||||
boolean r = get(temp).removeAll(o);
|
||||
map = temp;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).removeAll(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection o) {
|
||||
if (fast) {
|
||||
synchronized (FastHashMap.this) {
|
||||
HashMap temp = (HashMap) map.clone();
|
||||
boolean r = get(temp).retainAll(o);
|
||||
map = temp;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).retainAll(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
if (fast) {
|
||||
return get(map).size();
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isEmpty() {
|
||||
if (fast) {
|
||||
return get(map).isEmpty();
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
if (fast) {
|
||||
return get(map).contains(o);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).contains(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection o) {
|
||||
if (fast) {
|
||||
return get(map).containsAll(o);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).containsAll(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object[] toArray(Object[] o) {
|
||||
if (fast) {
|
||||
return get(map).toArray(o);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).toArray(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
if (fast) {
|
||||
return get(map).toArray();
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (fast) {
|
||||
return get(map).equals(o);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).equals(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
if (fast) {
|
||||
return get(map).hashCode();
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean add(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean addAll(Collection c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new CollectionViewIterator();
|
||||
}
|
||||
|
||||
private class CollectionViewIterator implements Iterator {
|
||||
|
||||
private Map expected;
|
||||
private Map.Entry lastReturned = null;
|
||||
private Iterator iterator;
|
||||
|
||||
public CollectionViewIterator() {
|
||||
this.expected = map;
|
||||
this.iterator = expected.entrySet().iterator();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
if (expected != map) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (expected != map) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
lastReturned = (Map.Entry)iterator.next();
|
||||
return iteratorNext(lastReturned);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (lastReturned == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (fast) {
|
||||
synchronized (FastHashMap.this) {
|
||||
if (expected != map) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
FastHashMap.this.remove(lastReturned.getKey());
|
||||
lastReturned = null;
|
||||
expected = map;
|
||||
}
|
||||
} else {
|
||||
iterator.remove();
|
||||
lastReturned = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set implementation over the keys of the FastHashMap
|
||||
*/
|
||||
private class KeySet extends CollectionView implements Set {
|
||||
|
||||
protected Collection get(Map map) {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
protected Object iteratorNext(Map.Entry entry) {
|
||||
return entry.getKey();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection implementation over the values of the FastHashMap
|
||||
*/
|
||||
private class Values extends CollectionView {
|
||||
|
||||
protected Collection get(Map map) {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
protected Object iteratorNext(Map.Entry entry) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set implementation over the entries of the FastHashMap
|
||||
*/
|
||||
private class EntrySet extends CollectionView implements Set {
|
||||
|
||||
protected Collection get(Map map) {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
protected Object iteratorNext(Map.Entry entry) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,824 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.collections;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* <p>A customized implementation of <code>java.util.TreeMap</code> designed
|
||||
* to operate in a multithreaded environment where the large majority of
|
||||
* method calls are read-only, instead of structural changes. When operating
|
||||
* in "fast" mode, read calls are non-synchronized and write calls perform the
|
||||
* following steps:</p>
|
||||
* <ul>
|
||||
* <li>Clone the existing collection
|
||||
* <li>Perform the modification on the clone
|
||||
* <li>Replace the existing collection with the (modified) clone
|
||||
* </ul>
|
||||
* <p>When first created, objects of this class default to "slow" mode, where
|
||||
* all accesses of any type are synchronized but no cloning takes place. This
|
||||
* is appropriate for initially populating the collection, followed by a switch
|
||||
* to "fast" mode (by calling <code>setFast(true)</code>) after initialization
|
||||
* is complete.</p>
|
||||
*
|
||||
* <p><strong>NOTE</strong>: If you are creating and accessing a
|
||||
* <code>TreeMap</code> only within a single thread, you should use
|
||||
* <code>java.util.TreeMap</code> directly (with no synchronization), for
|
||||
* maximum performance.</p>
|
||||
*
|
||||
* <p><strong>NOTE</strong>: <i>This class is not cross-platform.
|
||||
* Using it may cause unexpected failures on some architectures.</i>
|
||||
* It suffers from the same problems as the double-checked locking idiom.
|
||||
* In particular, the instruction that clones the internal collection and the
|
||||
* instruction that sets the internal reference to the clone can be executed
|
||||
* or perceived out-of-order. This means that any read operation might fail
|
||||
* unexpectedly, as it may be reading the state of the internal collection
|
||||
* before the internal collection is fully formed.
|
||||
* For more information on the double-checked locking idiom, see the
|
||||
* <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">
|
||||
* Double-Checked Locking Idiom Is Broken Declaration</a>.</p>
|
||||
*
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public class FastTreeMap extends TreeMap {
|
||||
|
||||
/**
|
||||
* The underlying map we are managing.
|
||||
*/
|
||||
protected TreeMap map = null;
|
||||
|
||||
/**
|
||||
* Are we operating in "fast" mode?
|
||||
*/
|
||||
protected boolean fast = false;
|
||||
|
||||
|
||||
// Constructors
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Construct a an empty map.
|
||||
*/
|
||||
public FastTreeMap() {
|
||||
super();
|
||||
this.map = new TreeMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty map with the specified comparator.
|
||||
*
|
||||
* @param comparator the comparator to use for ordering tree elements
|
||||
*/
|
||||
public FastTreeMap(Comparator comparator) {
|
||||
super();
|
||||
this.map = new TreeMap(comparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new map with the same mappings as the specified map,
|
||||
* sorted according to the keys's natural order
|
||||
*
|
||||
* @param map the map whose mappings are to be copied
|
||||
*/
|
||||
public FastTreeMap(Map map) {
|
||||
super();
|
||||
this.map = new TreeMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new map with the same mappings as the specified map,
|
||||
* sorted according to the same ordering
|
||||
*
|
||||
* @param map the map whose mappings are to be copied
|
||||
*/
|
||||
public FastTreeMap(SortedMap map) {
|
||||
super();
|
||||
this.map = new TreeMap(map);
|
||||
}
|
||||
|
||||
|
||||
// Property access
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if this map is operating in fast mode.
|
||||
*
|
||||
* @return true if this map is operating in fast mode
|
||||
*/
|
||||
public boolean getFast() {
|
||||
return (this.fast);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this map is operating in fast mode.
|
||||
*
|
||||
* @param fast true if this map should operate in fast mode
|
||||
*/
|
||||
public void setFast(boolean fast) {
|
||||
this.fast = fast;
|
||||
}
|
||||
|
||||
|
||||
// Map access
|
||||
// ----------------------------------------------------------------------
|
||||
// These methods can forward straight to the wrapped Map in 'fast' mode.
|
||||
// (because they are query methods)
|
||||
|
||||
/**
|
||||
* Return the value to which this map maps the specified key. Returns
|
||||
* <code>null</code> if the map contains no mapping for this key, or if
|
||||
* there is a mapping with a value of <code>null</code>. Use the
|
||||
* <code>containsKey()</code> method to disambiguate these cases.
|
||||
*
|
||||
* @param key the key whose value is to be returned
|
||||
* @return the value mapped to that key, or null
|
||||
*/
|
||||
public Object get(Object key) {
|
||||
if (fast) {
|
||||
return (map.get(key));
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of key-value mappings in this map.
|
||||
*
|
||||
* @return the current size of the map
|
||||
*/
|
||||
public int size() {
|
||||
if (fast) {
|
||||
return (map.size());
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if this map contains no mappings.
|
||||
*
|
||||
* @return is the map currently empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
if (fast) {
|
||||
return (map.isEmpty());
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.isEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if this map contains a mapping for the
|
||||
* specified key.
|
||||
*
|
||||
* @param key the key to be searched for
|
||||
* @return true if the map contains the key
|
||||
*/
|
||||
public boolean containsKey(Object key) {
|
||||
if (fast) {
|
||||
return (map.containsKey(key));
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.containsKey(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if this map contains one or more keys mapping
|
||||
* to the specified value.
|
||||
*
|
||||
* @param value the value to be searched for
|
||||
* @return true if the map contains the value
|
||||
*/
|
||||
public boolean containsValue(Object value) {
|
||||
if (fast) {
|
||||
return (map.containsValue(value));
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.containsValue(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the comparator used to order this map, or <code>null</code>
|
||||
* if this map uses its keys' natural order.
|
||||
*
|
||||
* @return the comparator used to order the map, or null if natural order
|
||||
*/
|
||||
public Comparator comparator() {
|
||||
if (fast) {
|
||||
return (map.comparator());
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.comparator());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first (lowest) key currently in this sorted map.
|
||||
*
|
||||
* @return the first key in the map
|
||||
*/
|
||||
public Object firstKey() {
|
||||
if (fast) {
|
||||
return (map.firstKey());
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.firstKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last (highest) key currently in this sorted map.
|
||||
*
|
||||
* @return the last key in the map
|
||||
*/
|
||||
public Object lastKey() {
|
||||
if (fast) {
|
||||
return (map.lastKey());
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.lastKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Map modification
|
||||
// ----------------------------------------------------------------------
|
||||
// These methods perform special behaviour in 'fast' mode.
|
||||
// The map is cloned, updated and then assigned back.
|
||||
// See the comments at the top as to why this won't always work.
|
||||
|
||||
/**
|
||||
* Associate the specified value with the specified key in this map.
|
||||
* If the map previously contained a mapping for this key, the old
|
||||
* value is replaced and returned.
|
||||
*
|
||||
* @param key the key with which the value is to be associated
|
||||
* @param value the value to be associated with this key
|
||||
* @return the value previously mapped to the key, or null
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
if (fast) {
|
||||
synchronized (this) {
|
||||
TreeMap temp = (TreeMap) map.clone();
|
||||
Object result = temp.put(key, value);
|
||||
map = temp;
|
||||
return (result);
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.put(key, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all of the mappings from the specified map to this one, replacing
|
||||
* any mappings with the same keys.
|
||||
*
|
||||
* @param in the map whose mappings are to be copied
|
||||
*/
|
||||
public void putAll(Map in) {
|
||||
if (fast) {
|
||||
synchronized (this) {
|
||||
TreeMap temp = (TreeMap) map.clone();
|
||||
temp.putAll(in);
|
||||
map = temp;
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
map.putAll(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any mapping for this key, and return any previously
|
||||
* mapped value.
|
||||
*
|
||||
* @param key the key whose mapping is to be removed
|
||||
* @return the value removed, or null
|
||||
*/
|
||||
public Object remove(Object key) {
|
||||
if (fast) {
|
||||
synchronized (this) {
|
||||
TreeMap temp = (TreeMap) map.clone();
|
||||
Object result = temp.remove(key);
|
||||
map = temp;
|
||||
return (result);
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.remove(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all mappings from this map.
|
||||
*/
|
||||
public void clear() {
|
||||
if (fast) {
|
||||
synchronized (this) {
|
||||
map = new TreeMap();
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
map.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Basic object methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compare the specified object with this list for equality. This
|
||||
* implementation uses exactly the code that is used to define the
|
||||
* list equals function in the documentation for the
|
||||
* <code>Map.equals</code> method.
|
||||
*
|
||||
* @param o the object to be compared to this list
|
||||
* @return true if the two maps are equal
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
// Simple tests that require no synchronization
|
||||
if (o == this) {
|
||||
return (true);
|
||||
} else if (!(o instanceof Map)) {
|
||||
return (false);
|
||||
}
|
||||
Map mo = (Map) o;
|
||||
|
||||
// Compare the two maps for equality
|
||||
if (fast) {
|
||||
if (mo.size() != map.size()) {
|
||||
return (false);
|
||||
}
|
||||
Iterator i = map.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Map.Entry e = (Map.Entry) i.next();
|
||||
Object key = e.getKey();
|
||||
Object value = e.getValue();
|
||||
if (value == null) {
|
||||
if (!(mo.get(key) == null && mo.containsKey(key))) {
|
||||
return (false);
|
||||
}
|
||||
} else {
|
||||
if (!value.equals(mo.get(key))) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
if (mo.size() != map.size()) {
|
||||
return (false);
|
||||
}
|
||||
Iterator i = map.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Map.Entry e = (Map.Entry) i.next();
|
||||
Object key = e.getKey();
|
||||
Object value = e.getValue();
|
||||
if (value == null) {
|
||||
if (!(mo.get(key) == null && mo.containsKey(key))) {
|
||||
return (false);
|
||||
}
|
||||
} else {
|
||||
if (!value.equals(mo.get(key))) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash code value for this map. This implementation uses
|
||||
* exactly the code that is used to define the list hash function in the
|
||||
* documentation for the <code>Map.hashCode</code> method.
|
||||
*
|
||||
* @return a suitable integer hash code
|
||||
*/
|
||||
public int hashCode() {
|
||||
if (fast) {
|
||||
int h = 0;
|
||||
Iterator i = map.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
h += i.next().hashCode();
|
||||
}
|
||||
return (h);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
int h = 0;
|
||||
Iterator i = map.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
h += i.next().hashCode();
|
||||
}
|
||||
return (h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a shallow copy of this <code>FastTreeMap</code> instance.
|
||||
* The keys and values themselves are not copied.
|
||||
*
|
||||
* @return a clone of this map
|
||||
*/
|
||||
public Object clone() {
|
||||
FastTreeMap results = null;
|
||||
if (fast) {
|
||||
results = new FastTreeMap(map);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
results = new FastTreeMap(map);
|
||||
}
|
||||
}
|
||||
results.setFast(getFast());
|
||||
return (results);
|
||||
}
|
||||
|
||||
|
||||
// Sub map views
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return a view of the portion of this map whose keys are strictly
|
||||
* less than the specified key.
|
||||
*
|
||||
* @param key Key higher than any in the returned map
|
||||
* @return a head map
|
||||
*/
|
||||
public SortedMap headMap(Object key) {
|
||||
if (fast) {
|
||||
return (map.headMap(key));
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.headMap(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a view of the portion of this map whose keys are in the
|
||||
* range fromKey (inclusive) to toKey (exclusive).
|
||||
*
|
||||
* @param fromKey Lower limit of keys for the returned map
|
||||
* @param toKey Upper limit of keys for the returned map
|
||||
* @return a sub map
|
||||
*/
|
||||
public SortedMap subMap(Object fromKey, Object toKey) {
|
||||
if (fast) {
|
||||
return (map.subMap(fromKey, toKey));
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.subMap(fromKey, toKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a view of the portion of this map whose keys are greater than
|
||||
* or equal to the specified key.
|
||||
*
|
||||
* @param key Key less than or equal to any in the returned map
|
||||
* @return a tail map
|
||||
*/
|
||||
public SortedMap tailMap(Object key) {
|
||||
if (fast) {
|
||||
return (map.tailMap(key));
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return (map.tailMap(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Map views
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return a collection view of the mappings contained in this map. Each
|
||||
* element in the returned collection is a <code>Map.Entry</code>.
|
||||
*/
|
||||
public Set entrySet() {
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a set view of the keys contained in this map.
|
||||
*/
|
||||
public Set keySet() {
|
||||
return new KeySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a collection view of the values contained in this map.
|
||||
*/
|
||||
public Collection values() {
|
||||
return new Values();
|
||||
}
|
||||
|
||||
// Map view inner classes
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Abstract collection implementation shared by keySet(), values() and entrySet().
|
||||
*/
|
||||
private abstract class CollectionView implements Collection {
|
||||
|
||||
public CollectionView() {
|
||||
}
|
||||
|
||||
protected abstract Collection get(Map map);
|
||||
protected abstract Object iteratorNext(Map.Entry entry);
|
||||
|
||||
|
||||
public void clear() {
|
||||
if (fast) {
|
||||
synchronized (FastTreeMap.this) {
|
||||
map = new TreeMap();
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
get(map).clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
if (fast) {
|
||||
synchronized (FastTreeMap.this) {
|
||||
TreeMap temp = (TreeMap) map.clone();
|
||||
boolean r = get(temp).remove(o);
|
||||
map = temp;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).remove(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection o) {
|
||||
if (fast) {
|
||||
synchronized (FastTreeMap.this) {
|
||||
TreeMap temp = (TreeMap) map.clone();
|
||||
boolean r = get(temp).removeAll(o);
|
||||
map = temp;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).removeAll(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection o) {
|
||||
if (fast) {
|
||||
synchronized (FastTreeMap.this) {
|
||||
TreeMap temp = (TreeMap) map.clone();
|
||||
boolean r = get(temp).retainAll(o);
|
||||
map = temp;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).retainAll(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
if (fast) {
|
||||
return get(map).size();
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isEmpty() {
|
||||
if (fast) {
|
||||
return get(map).isEmpty();
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
if (fast) {
|
||||
return get(map).contains(o);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).contains(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection o) {
|
||||
if (fast) {
|
||||
return get(map).containsAll(o);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).containsAll(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object[] toArray(Object[] o) {
|
||||
if (fast) {
|
||||
return get(map).toArray(o);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).toArray(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
if (fast) {
|
||||
return get(map).toArray();
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (fast) {
|
||||
return get(map).equals(o);
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).equals(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
if (fast) {
|
||||
return get(map).hashCode();
|
||||
} else {
|
||||
synchronized (map) {
|
||||
return get(map).hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean add(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean addAll(Collection c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new CollectionViewIterator();
|
||||
}
|
||||
|
||||
private class CollectionViewIterator implements Iterator {
|
||||
|
||||
private Map expected;
|
||||
private Map.Entry lastReturned = null;
|
||||
private Iterator iterator;
|
||||
|
||||
public CollectionViewIterator() {
|
||||
this.expected = map;
|
||||
this.iterator = expected.entrySet().iterator();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
if (expected != map) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (expected != map) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
lastReturned = (Map.Entry)iterator.next();
|
||||
return iteratorNext(lastReturned);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (lastReturned == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (fast) {
|
||||
synchronized (FastTreeMap.this) {
|
||||
if (expected != map) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
FastTreeMap.this.remove(lastReturned.getKey());
|
||||
lastReturned = null;
|
||||
expected = map;
|
||||
}
|
||||
} else {
|
||||
iterator.remove();
|
||||
lastReturned = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set implementation over the keys of the FastTreeMap
|
||||
*/
|
||||
private class KeySet extends CollectionView implements Set {
|
||||
|
||||
protected Collection get(Map map) {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
protected Object iteratorNext(Map.Entry entry) {
|
||||
return entry.getKey();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection implementation over the values of the FastTreeMap
|
||||
*/
|
||||
private class Values extends CollectionView {
|
||||
|
||||
protected Collection get(Map map) {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
protected Object iteratorNext(Map.Entry entry) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set implementation over the entries of the FastTreeMap
|
||||
*/
|
||||
private class EntrySet extends CollectionView implements Set {
|
||||
|
||||
protected Collection get(Map map) {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
|
||||
protected Object iteratorNext(Map.Entry entry) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -52,7 +52,7 @@ public class MapPerformance {
|
|||
Map flatMap = new Flat3Map(hashMap);
|
||||
System.out.println(flatMap);
|
||||
Map unmodHashMap = Collections.unmodifiableMap(new HashMap(hashMap));
|
||||
Map fastHashMap = new FastHashMap(hashMap);
|
||||
// Map fastHashMap = new FastHashMap(hashMap);
|
||||
Map treeMap = new TreeMap(hashMap);
|
||||
// Map linkedMap = new LinkedHashMap(hashMap);
|
||||
// Map syncMap = Collections.unmodifiableMap(new HashMap(hashMap));
|
||||
|
|
|
@ -50,15 +50,9 @@ public class TestAll extends TestCase {
|
|||
|
||||
suite.addTest(TestArrayStack.suite());
|
||||
suite.addTest(TestExtendedProperties.suite());
|
||||
suite.addTest(TestFastArrayList.suite());
|
||||
suite.addTest(TestFastArrayList1.suite());
|
||||
suite.addTest(TestFastHashMap.suite());
|
||||
suite.addTest(TestFastHashMap1.suite());
|
||||
suite.addTest(TestFastTreeMap.suite());
|
||||
suite.addTest(TestFastTreeMap1.suite());
|
||||
return suite;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestAll.class.getName() };
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Test FastArrayList.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Jason van Zyl
|
||||
*/
|
||||
public class TestFastArrayList extends TestArrayList {
|
||||
|
||||
public TestFastArrayList(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestFastArrayList.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestFastArrayList.class.getName()};
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
list = (ArrayList) makeEmptyList();
|
||||
}
|
||||
|
||||
public List makeEmptyList() {
|
||||
FastArrayList fal = new FastArrayList();
|
||||
fal.setFast(false);
|
||||
return (fal);
|
||||
}
|
||||
|
||||
public void testConcurrentModification_alwaysFast() {
|
||||
FastArrayList list = new FastArrayList();
|
||||
list.setFast(true);
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
ListIterator iter = list.listIterator();
|
||||
assertEquals("a", iter.next());
|
||||
assertEquals("b", iter.next());
|
||||
iter.remove(); // checking for no ConcurrentModificationException
|
||||
assertEquals("c", iter.next());
|
||||
assertEquals(false, iter.hasNext());
|
||||
assertEquals("c", iter.previous());
|
||||
assertEquals("a", iter.previous());
|
||||
assertEquals(false, iter.hasPrevious());
|
||||
}
|
||||
|
||||
public void testConcurrentModification_alwaysFastModError() {
|
||||
FastArrayList list = new FastArrayList();
|
||||
list.setFast(true);
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
ListIterator iter = list.listIterator();
|
||||
assertEquals("a", iter.next());
|
||||
assertEquals("b", iter.next());
|
||||
list.remove(1);
|
||||
try {
|
||||
iter.remove();
|
||||
} catch (ConcurrentModificationException ex) {
|
||||
// expected
|
||||
}
|
||||
// iterator state now invalid
|
||||
}
|
||||
|
||||
public void testConcurrentModification_delayedFast() {
|
||||
FastArrayList list = new FastArrayList();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
ListIterator iter = list.listIterator();
|
||||
assertEquals("a", iter.next());
|
||||
assertEquals("b", iter.next());
|
||||
list.setFast(true);
|
||||
iter.remove(); // checking for no ConcurrentModificationException
|
||||
assertEquals("c", iter.next());
|
||||
assertEquals(false, iter.hasNext());
|
||||
assertEquals("c", iter.previous());
|
||||
assertEquals("a", iter.previous());
|
||||
assertEquals(false, iter.hasPrevious());
|
||||
}
|
||||
|
||||
public void testConcurrentModification_delayedFastModError() {
|
||||
FastArrayList list = new FastArrayList();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
ListIterator iter = list.listIterator();
|
||||
assertEquals("a", iter.next());
|
||||
assertEquals("b", iter.next());
|
||||
list.setFast(true);
|
||||
list.remove(1);
|
||||
try {
|
||||
iter.remove();
|
||||
} catch (ConcurrentModificationException ex) {
|
||||
// expected
|
||||
}
|
||||
// iterator state now invalid
|
||||
}
|
||||
|
||||
public void testConcurrentModification_alwaysFastPrevious() {
|
||||
FastArrayList list = new FastArrayList();
|
||||
list.setFast(true);
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
ListIterator iter = list.listIterator();
|
||||
assertEquals("a", iter.next());
|
||||
assertEquals("b", iter.next());
|
||||
assertEquals("b", iter.previous());
|
||||
iter.remove(); // checking for no ConcurrentModificationException
|
||||
assertEquals("c", iter.next());
|
||||
assertEquals(false, iter.hasNext());
|
||||
assertEquals("c", iter.previous());
|
||||
assertEquals("a", iter.previous());
|
||||
assertEquals(false, iter.hasPrevious());
|
||||
}
|
||||
|
||||
public void testConcurrentModification_alwaysFastModErrorPrevious() {
|
||||
FastArrayList list = new FastArrayList();
|
||||
list.setFast(true);
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
ListIterator iter = list.listIterator();
|
||||
assertEquals("a", iter.next());
|
||||
assertEquals("b", iter.next());
|
||||
assertEquals("b", iter.previous());
|
||||
list.remove(1);
|
||||
try {
|
||||
iter.remove();
|
||||
} catch (ConcurrentModificationException ex) {
|
||||
// expected
|
||||
}
|
||||
// iterator state now invalid
|
||||
}
|
||||
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Test FastArrayList implementation in <strong>fast</strong> mode.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Jason van Zyl
|
||||
*/
|
||||
public class TestFastArrayList1 extends TestFastArrayList {
|
||||
|
||||
public TestFastArrayList1(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestFastArrayList1.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestFastArrayList1.class.getName()};
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
list = (ArrayList) makeEmptyList();
|
||||
}
|
||||
|
||||
public List makeEmptyList() {
|
||||
FastArrayList fal = new FastArrayList();
|
||||
fal.setFast(true);
|
||||
return (fal);
|
||||
}
|
||||
|
||||
public void testIterateModify1() {
|
||||
List list = makeEmptyList();
|
||||
list.add("A");
|
||||
list.add("B");
|
||||
list.add("C");
|
||||
assertEquals(3, list.size());
|
||||
|
||||
Iterator it = list.iterator();
|
||||
assertEquals("A", it.next());
|
||||
assertEquals(3, list.size());
|
||||
list.add(1, "Z");
|
||||
assertEquals(4, list.size());
|
||||
assertEquals("B", it.next());
|
||||
assertEquals("C", it.next());
|
||||
assertEquals(false, it.hasNext());
|
||||
}
|
||||
|
||||
public void testIterateModify2() {
|
||||
List list = makeEmptyList();
|
||||
list.add("A");
|
||||
list.add("B");
|
||||
list.add("C");
|
||||
assertEquals(3, list.size());
|
||||
|
||||
ListIterator it = list.listIterator();
|
||||
assertEquals("A", it.next());
|
||||
it.add("M"); // change via Iterator interface
|
||||
assertEquals(4, list.size());
|
||||
list.add(2, "Z"); // change via List interface
|
||||
assertEquals(5, list.size());
|
||||
assertEquals("B", it.next());
|
||||
try {
|
||||
it.set("N"); // fails as previously changed via List interface
|
||||
fail();
|
||||
} catch (ConcurrentModificationException ex) {}
|
||||
try {
|
||||
it.remove();
|
||||
fail();
|
||||
} catch (ConcurrentModificationException ex) {}
|
||||
try {
|
||||
it.add("N");
|
||||
fail();
|
||||
} catch (ConcurrentModificationException ex) {}
|
||||
assertEquals("C", it.next());
|
||||
assertEquals(false, it.hasNext());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.collections;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.apache.commons.collections.map.AbstractTestMap;
|
||||
|
||||
/**
|
||||
* Tests FastHashMap.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Jason van Zyl
|
||||
*/
|
||||
public class TestFastHashMap extends AbstractTestMap {
|
||||
|
||||
public TestFastHashMap(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestFastHashMap.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestFastHashMap.class.getName()};
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
FastHashMap fhm = new FastHashMap();
|
||||
fhm.setFast(false);
|
||||
return (fhm);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.collections;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Test FastHashMap in <strong>fast</strong> mode.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Jason van Zyl
|
||||
*/
|
||||
public class TestFastHashMap1 extends TestFastHashMap {
|
||||
|
||||
public TestFastHashMap1(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestFastHashMap1.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestFastHashMap1.class.getName()};
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
FastHashMap fhm = new FastHashMap();
|
||||
fhm.setFast(true);
|
||||
return (fhm);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
map = (HashMap) makeEmptyMap();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.collections;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Tests FastTreeMap.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Jason van Zyl
|
||||
*/
|
||||
public class TestFastTreeMap extends TestTreeMap {
|
||||
|
||||
public TestFastTreeMap(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestFastTreeMap.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestFastTreeMap.class.getName()};
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
FastTreeMap ftm = new FastTreeMap();
|
||||
ftm.setFast(false);
|
||||
return (ftm);
|
||||
}
|
||||
|
||||
public Map makeConfirmedEmptyMap() {
|
||||
return new TreeMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* The comparator for the fast tree map does not support null keys.
|
||||
**/
|
||||
public boolean isAllowNullKey() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
map = (TreeMap) makeEmptyMap();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.collections;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Test FastTreeMap in <strong>fast</strong> mode.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
|
||||
*/
|
||||
public class TestFastTreeMap1 extends TestFastTreeMap {
|
||||
|
||||
public TestFastTreeMap1(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestFastTreeMap1.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestFastTreeMap1.class.getName()};
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
FastTreeMap ftm = new FastTreeMap();
|
||||
ftm.setFast(true);
|
||||
return (ftm);
|
||||
}
|
||||
|
||||
public void setUp() {
|
||||
map = (TreeMap) makeEmptyMap();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue