COLLECTIONS-229 - Remove deprecated classes and code
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/branches/collections_jdk5_branch@468687 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c5a502a084
commit
efd41aff47
|
@ -1,70 +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.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>RELEASE NOTES: COLLECTIONS GENERICS X.X</title>
|
||||
</head>
|
||||
<body>
|
||||
<center><h2>RELEASE NOTES: COLLECTIONS GENERICS X.X</h2></center>
|
||||
|
||||
<p>
|
||||
Commons collections is a project to develop and maintain collection classes
|
||||
based on and inspired by the JDK collection framework.
|
||||
This project is JDK1.2 compatible, and does not use JDK1.5 generics.
|
||||
</p>
|
||||
<p>
|
||||
This release adds various new classes and fixes a number of bugs.
|
||||
All feedback should be directed to commons-user at jakarta.apache.org.
|
||||
</p>
|
||||
<hr />
|
||||
|
||||
<center><h3>COMPATIBILITY</h3></center>
|
||||
<p>
|
||||
This release is fully source and binary compatible with v3.2.
|
||||
(Checks performed using JDiff and Clirr, thanks).
|
||||
Please check the bug fixes to ensure you weren't relying on the behaviour of a bug.
|
||||
</p>
|
||||
<p>
|
||||
There are xxxxxxxxxxxxxxxxxxx new <i>deprecations</i>:<br />
|
||||
If this causes major headaches to anyone please contact commons-dev at jakarta.apache.org.
|
||||
</p>
|
||||
|
||||
<center><h3>NEW CLASSES</h3></center>
|
||||
<ul>
|
||||
<li>xxxxxxxxxxxxxx</li>
|
||||
</ul>
|
||||
|
||||
<center><h3>ENHANCEMENTS</h3></center>
|
||||
<ul>
|
||||
<li>xxxxxxxxxxxxxx</li>
|
||||
</ul>
|
||||
|
||||
<center><h3>BUG FIXES</h3></center>
|
||||
<ul>
|
||||
<li>Flat3Map - Fix setValue in MapIterator and EntrySetIterator to work correctly [COLLECTIONS-217]</li>
|
||||
<li>ExtendedProperties - Include property name had confused static/instance semantics [COLLECTIONS-214]</li>
|
||||
<li>CollectionUtils - Fix removeAll() method which was completely broken [COLLECTIONS-219]</li>
|
||||
</ul>
|
||||
|
||||
<center><h3>JAVADOC</h3></center>
|
||||
<ul>
|
||||
<li>IteratorChain - Clarify constructor behaviour</li>
|
||||
<li>MuliKey - Spelling [COLLECTIONS-216]</li>
|
||||
<li>DefaultedMap - Clarify transformer behaviour [COLLECTIONS-215]</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
Commons Collections Generics Package
|
||||
Version X.X
|
||||
Release Notes
|
||||
|
||||
|
||||
INTRODUCTION:
|
||||
|
||||
Commons collections is a project to develop and maintain collection classes
|
||||
based on and inspired by the JDK collection framework.
|
||||
This version uses the generics features of JDK1.5 and is not compatible with
|
||||
earlier JDK versions.
|
||||
|
||||
The process of generifying an API is complex.
|
||||
For commons-collections, we have chosen to break the API in various ways.
|
||||
The aim behind this is to provide an API design that better suits generics.
|
||||
We have also removed all deprecated classes and fixed oddities in the previous
|
||||
API that we couldn't fix due to backwards compatability restrictions.
|
||||
|
||||
As such, this release should not be considered to be a simple, drop-in, replacement
|
||||
for commons-collections. You will probably receive compile errors, and you will
|
||||
certainly have generification warnings to solve. These release notes will try
|
||||
to guide you in the process of upgrading, however you should remember that this
|
||||
is a new API based on the original, so some concepts have changed.
|
||||
|
||||
|
||||
Changes from commons-collections
|
||||
--------------------------------
|
||||
- Removed all deprecated classes and methods
|
||||
|
||||
|
||||
Feedback
|
||||
--------
|
||||
Open source works best when you give feedback:
|
||||
http://jakarta.apache.org/commons/collections/
|
||||
|
||||
Please direct all bug reports to JIRA
|
||||
http://issues.apache.org/jira/browse/COLLECTIONS
|
||||
|
||||
Or subscribe to the commons-user mailing list (prefix emails by [collections])
|
||||
http://jakarta.apache.org/site/mail.html
|
||||
|
||||
The Commons-Collections-Generics Team
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,804 +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.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.collections.list.UnmodifiableList;
|
||||
import org.apache.commons.collections.keyvalue.AbstractMapEntry;
|
||||
import org.apache.commons.collections.set.UnmodifiableSet;
|
||||
|
||||
/**
|
||||
* An implementation of Map for JavaBeans which uses introspection to
|
||||
* get and put properties in the bean.
|
||||
* <p>
|
||||
* If an exception occurs during attempts to get or set a property then the
|
||||
* property is considered non existent in the Map
|
||||
*
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author James Strachan
|
||||
* @author Stephen Colebourne
|
||||
* @author Dimiter Dimitrov
|
||||
*
|
||||
* @deprecated Identical class now available in commons-beanutils (full jar version).
|
||||
* This version is due to be removed in collections v4.0.
|
||||
*/
|
||||
public class BeanMap extends AbstractMap implements Cloneable {
|
||||
|
||||
private transient Object bean;
|
||||
|
||||
private transient HashMap readMethods = new HashMap();
|
||||
private transient HashMap writeMethods = new HashMap();
|
||||
private transient HashMap types = new HashMap();
|
||||
|
||||
/**
|
||||
* An empty array. Used to invoke accessors via reflection.
|
||||
*/
|
||||
public static final Object[] NULL_ARGUMENTS = {};
|
||||
|
||||
/**
|
||||
* Maps primitive Class types to transformers. The transformer
|
||||
* transform strings into the appropriate primitive wrapper.
|
||||
*/
|
||||
public static HashMap defaultTransformers = new HashMap();
|
||||
|
||||
static {
|
||||
defaultTransformers.put(
|
||||
Boolean.TYPE,
|
||||
new Transformer() {
|
||||
public Object transform( Object input ) {
|
||||
return Boolean.valueOf( input.toString() );
|
||||
}
|
||||
}
|
||||
);
|
||||
defaultTransformers.put(
|
||||
Character.TYPE,
|
||||
new Transformer() {
|
||||
public Object transform( Object input ) {
|
||||
return new Character( input.toString().charAt( 0 ) );
|
||||
}
|
||||
}
|
||||
);
|
||||
defaultTransformers.put(
|
||||
Byte.TYPE,
|
||||
new Transformer() {
|
||||
public Object transform( Object input ) {
|
||||
return Byte.valueOf( input.toString() );
|
||||
}
|
||||
}
|
||||
);
|
||||
defaultTransformers.put(
|
||||
Short.TYPE,
|
||||
new Transformer() {
|
||||
public Object transform( Object input ) {
|
||||
return Short.valueOf( input.toString() );
|
||||
}
|
||||
}
|
||||
);
|
||||
defaultTransformers.put(
|
||||
Integer.TYPE,
|
||||
new Transformer() {
|
||||
public Object transform( Object input ) {
|
||||
return Integer.valueOf( input.toString() );
|
||||
}
|
||||
}
|
||||
);
|
||||
defaultTransformers.put(
|
||||
Long.TYPE,
|
||||
new Transformer() {
|
||||
public Object transform( Object input ) {
|
||||
return Long.valueOf( input.toString() );
|
||||
}
|
||||
}
|
||||
);
|
||||
defaultTransformers.put(
|
||||
Float.TYPE,
|
||||
new Transformer() {
|
||||
public Object transform( Object input ) {
|
||||
return Float.valueOf( input.toString() );
|
||||
}
|
||||
}
|
||||
);
|
||||
defaultTransformers.put(
|
||||
Double.TYPE,
|
||||
new Transformer() {
|
||||
public Object transform( Object input ) {
|
||||
return Double.valueOf( input.toString() );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Constructors
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new empty <code>BeanMap</code>.
|
||||
*/
|
||||
public BeanMap() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>BeanMap</code> that operates on the
|
||||
* specified bean. If the given bean is <code>null</code>, then
|
||||
* this map will be empty.
|
||||
*
|
||||
* @param bean the bean for this map to operate on
|
||||
*/
|
||||
public BeanMap(Object bean) {
|
||||
this.bean = bean;
|
||||
initialise();
|
||||
}
|
||||
|
||||
// Map interface
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
public String toString() {
|
||||
return "BeanMap<" + String.valueOf(bean) + ">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone this bean map using the following process:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If there is no underlying bean, return a cloned BeanMap without a
|
||||
* bean.
|
||||
*
|
||||
* <li>Since there is an underlying bean, try to instantiate a new bean of
|
||||
* the same type using Class.newInstance().
|
||||
*
|
||||
* <li>If the instantiation fails, throw a CloneNotSupportedException
|
||||
*
|
||||
* <li>Clone the bean map and set the newly instantiated bean as the
|
||||
* underlying bean for the bean map.
|
||||
*
|
||||
* <li>Copy each property that is both readable and writable from the
|
||||
* existing object to a cloned bean map.
|
||||
*
|
||||
* <li>If anything fails along the way, throw a
|
||||
* CloneNotSupportedException.
|
||||
*
|
||||
* <ul>
|
||||
*/
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
BeanMap newMap = (BeanMap)super.clone();
|
||||
|
||||
if(bean == null) {
|
||||
// no bean, just an empty bean map at the moment. return a newly
|
||||
// cloned and empty bean map.
|
||||
return newMap;
|
||||
}
|
||||
|
||||
Object newBean = null;
|
||||
Class beanClass = null;
|
||||
try {
|
||||
beanClass = bean.getClass();
|
||||
newBean = beanClass.newInstance();
|
||||
} catch (Exception e) {
|
||||
// unable to instantiate
|
||||
throw new CloneNotSupportedException
|
||||
("Unable to instantiate the underlying bean \"" +
|
||||
beanClass.getName() + "\": " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
newMap.setBean(newBean);
|
||||
} catch (Exception exception) {
|
||||
throw new CloneNotSupportedException
|
||||
("Unable to set bean in the cloned bean map: " +
|
||||
exception);
|
||||
}
|
||||
|
||||
try {
|
||||
// copy only properties that are readable and writable. If its
|
||||
// not readable, we can't get the value from the old map. If
|
||||
// its not writable, we can't write a value into the new map.
|
||||
Iterator readableKeys = readMethods.keySet().iterator();
|
||||
while(readableKeys.hasNext()) {
|
||||
Object key = readableKeys.next();
|
||||
if(getWriteMethod(key) != null) {
|
||||
newMap.put(key, get(key));
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
throw new CloneNotSupportedException
|
||||
("Unable to copy bean values to cloned bean map: " +
|
||||
exception);
|
||||
}
|
||||
|
||||
return newMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts all of the writable properties from the given BeanMap into this
|
||||
* BeanMap. Read-only and Write-only properties will be ignored.
|
||||
*
|
||||
* @param map the BeanMap whose properties to put
|
||||
*/
|
||||
public void putAllWriteable(BeanMap map) {
|
||||
Iterator readableKeys = map.readMethods.keySet().iterator();
|
||||
while (readableKeys.hasNext()) {
|
||||
Object key = readableKeys.next();
|
||||
if (getWriteMethod(key) != null) {
|
||||
this.put(key, map.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method reinitializes the bean map to have default values for the
|
||||
* bean's properties. This is accomplished by constructing a new instance
|
||||
* of the bean which the map uses as its underlying data source. This
|
||||
* behavior for <code>clear()</code> differs from the Map contract in that
|
||||
* the mappings are not actually removed from the map (the mappings for a
|
||||
* BeanMap are fixed).
|
||||
*/
|
||||
public void clear() {
|
||||
if(bean == null) return;
|
||||
|
||||
Class beanClass = null;
|
||||
try {
|
||||
beanClass = bean.getClass();
|
||||
bean = beanClass.newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new UnsupportedOperationException( "Could not create new instance of class: " + beanClass );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the bean defines a property with the given name.
|
||||
* <p>
|
||||
* The given name must be a <code>String</code>; if not, this method
|
||||
* returns false. This method will also return false if the bean
|
||||
* does not define a property with that name.
|
||||
* <p>
|
||||
* Write-only properties will not be matched as the test operates against
|
||||
* property read methods.
|
||||
*
|
||||
* @param name the name of the property to check
|
||||
* @return false if the given name is null or is not a <code>String</code>;
|
||||
* false if the bean does not define a property with that name; or
|
||||
* true if the bean does define a property with that name
|
||||
*/
|
||||
public boolean containsKey(Object name) {
|
||||
Method method = getReadMethod(name);
|
||||
return method != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the bean defines a property whose current value is
|
||||
* the given object.
|
||||
*
|
||||
* @param value the value to check
|
||||
* @return false true if the bean has at least one property whose
|
||||
* current value is that object, false otherwise
|
||||
*/
|
||||
public boolean containsValue(Object value) {
|
||||
// use default implementation
|
||||
return super.containsValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the bean's property with the given name.
|
||||
* <p>
|
||||
* The given name must be a {@link String} and must not be
|
||||
* null; otherwise, this method returns <code>null</code>.
|
||||
* If the bean defines a property with the given name, the value of
|
||||
* that property is returned. Otherwise, <code>null</code> is
|
||||
* returned.
|
||||
* <p>
|
||||
* Write-only properties will not be matched as the test operates against
|
||||
* property read methods.
|
||||
*
|
||||
* @param name the name of the property whose value to return
|
||||
* @return the value of the property with that name
|
||||
*/
|
||||
public Object get(Object name) {
|
||||
if ( bean != null ) {
|
||||
Method method = getReadMethod( name );
|
||||
if ( method != null ) {
|
||||
try {
|
||||
return method.invoke( bean, NULL_ARGUMENTS );
|
||||
}
|
||||
catch ( IllegalAccessException e ) {
|
||||
logWarn( e );
|
||||
}
|
||||
catch ( IllegalArgumentException e ) {
|
||||
logWarn( e );
|
||||
}
|
||||
catch ( InvocationTargetException e ) {
|
||||
logWarn( e );
|
||||
}
|
||||
catch ( NullPointerException e ) {
|
||||
logWarn( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bean property with the given name to the given value.
|
||||
*
|
||||
* @param name the name of the property to set
|
||||
* @param value the value to set that property to
|
||||
* @return the previous value of that property
|
||||
* @throws IllegalArgumentException if the given name is null;
|
||||
* if the given name is not a {@link String}; if the bean doesn't
|
||||
* define a property with that name; or if the bean property with
|
||||
* that name is read-only
|
||||
*/
|
||||
public Object put(Object name, Object value) throws IllegalArgumentException, ClassCastException {
|
||||
if ( bean != null ) {
|
||||
Object oldValue = get( name );
|
||||
Method method = getWriteMethod( name );
|
||||
if ( method == null ) {
|
||||
throw new IllegalArgumentException( "The bean of type: "+ bean.getClass().getName() + " has no property called: " + name );
|
||||
}
|
||||
try {
|
||||
Object[] arguments = createWriteMethodArguments( method, value );
|
||||
method.invoke( bean, arguments );
|
||||
|
||||
Object newValue = get( name );
|
||||
firePropertyChange( name, oldValue, newValue );
|
||||
}
|
||||
catch ( InvocationTargetException e ) {
|
||||
logInfo( e );
|
||||
throw new IllegalArgumentException( e.getMessage() );
|
||||
}
|
||||
catch ( IllegalAccessException e ) {
|
||||
logInfo( e );
|
||||
throw new IllegalArgumentException( e.getMessage() );
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of properties defined by the bean.
|
||||
*
|
||||
* @return the number of properties defined by the bean
|
||||
*/
|
||||
public int size() {
|
||||
return readMethods.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the keys for this BeanMap.
|
||||
* <p>
|
||||
* Write-only properties are <b>not</b> included in the returned set of
|
||||
* property names, although it is possible to set their value and to get
|
||||
* their type.
|
||||
*
|
||||
* @return BeanMap keys. The Set returned by this method is not
|
||||
* modifiable.
|
||||
*/
|
||||
public Set keySet() {
|
||||
return UnmodifiableSet.decorate(readMethods.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Set of MapEntry objects that are the mappings for this BeanMap.
|
||||
* <p>
|
||||
* Each MapEntry can be set but not removed.
|
||||
*
|
||||
* @return the unmodifiable set of mappings
|
||||
*/
|
||||
public Set entrySet() {
|
||||
return UnmodifiableSet.decorate(new AbstractSet() {
|
||||
public Iterator iterator() {
|
||||
return entryIterator();
|
||||
}
|
||||
public int size() {
|
||||
return BeanMap.this.readMethods.size();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the values for the BeanMap.
|
||||
*
|
||||
* @return values for the BeanMap. The returned collection is not
|
||||
* modifiable.
|
||||
*/
|
||||
public Collection values() {
|
||||
ArrayList answer = new ArrayList( readMethods.size() );
|
||||
for ( Iterator iter = valueIterator(); iter.hasNext(); ) {
|
||||
answer.add( iter.next() );
|
||||
}
|
||||
return UnmodifiableList.decorate(answer);
|
||||
}
|
||||
|
||||
|
||||
// Helper methods
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the type of the property with the given name.
|
||||
*
|
||||
* @param name the name of the property
|
||||
* @return the type of the property, or <code>null</code> if no such
|
||||
* property exists
|
||||
*/
|
||||
public Class getType(String name) {
|
||||
return (Class) types.get( name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for getting an iterator over the keys.
|
||||
* <p>
|
||||
* Write-only properties will not be returned in the iterator.
|
||||
*
|
||||
* @return an iterator over the keys
|
||||
*/
|
||||
public Iterator keyIterator() {
|
||||
return readMethods.keySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for getting an iterator over the values.
|
||||
*
|
||||
* @return an iterator over the values
|
||||
*/
|
||||
public Iterator valueIterator() {
|
||||
final Iterator iter = keyIterator();
|
||||
return new Iterator() {
|
||||
public boolean hasNext() {
|
||||
return iter.hasNext();
|
||||
}
|
||||
public Object next() {
|
||||
Object key = iter.next();
|
||||
return get(key);
|
||||
}
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException( "remove() not supported for BeanMap" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for getting an iterator over the entries.
|
||||
*
|
||||
* @return an iterator over the entries
|
||||
*/
|
||||
public Iterator entryIterator() {
|
||||
final Iterator iter = keyIterator();
|
||||
return new Iterator() {
|
||||
public boolean hasNext() {
|
||||
return iter.hasNext();
|
||||
}
|
||||
public Object next() {
|
||||
Object key = iter.next();
|
||||
Object value = get(key);
|
||||
return new MyMapEntry( BeanMap.this, key, value );
|
||||
}
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException( "remove() not supported for BeanMap" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Properties
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the bean currently being operated on. The return value may
|
||||
* be null if this map is empty.
|
||||
*
|
||||
* @return the bean being operated on by this map
|
||||
*/
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bean to be operated on by this map. The given value may
|
||||
* be null, in which case this map will be empty.
|
||||
*
|
||||
* @param newBean the new bean to operate on
|
||||
*/
|
||||
public void setBean( Object newBean ) {
|
||||
bean = newBean;
|
||||
reinitialise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the accessor for the property with the given name.
|
||||
*
|
||||
* @param name the name of the property
|
||||
* @return the accessor method for the property, or null
|
||||
*/
|
||||
public Method getReadMethod(String name) {
|
||||
return (Method) readMethods.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mutator for the property with the given name.
|
||||
*
|
||||
* @param name the name of the property
|
||||
* @return the mutator method for the property, or null
|
||||
*/
|
||||
public Method getWriteMethod(String name) {
|
||||
return (Method) writeMethods.get(name);
|
||||
}
|
||||
|
||||
|
||||
// Implementation methods
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the accessor for the property with the given name.
|
||||
*
|
||||
* @param name the name of the property
|
||||
* @return null if the name is null; null if the name is not a
|
||||
* {@link String}; null if no such property exists; or the accessor
|
||||
* method for that property
|
||||
*/
|
||||
protected Method getReadMethod( Object name ) {
|
||||
return (Method) readMethods.get( name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mutator for the property with the given name.
|
||||
*
|
||||
* @param name the name of the
|
||||
* @return null if the name is null; null if the name is not a
|
||||
* {@link String}; null if no such property exists; null if the
|
||||
* property is read-only; or the mutator method for that property
|
||||
*/
|
||||
protected Method getWriteMethod( Object name ) {
|
||||
return (Method) writeMethods.get( name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinitializes this bean. Called during {@link #setBean(Object)}.
|
||||
* Does introspection to find properties.
|
||||
*/
|
||||
protected void reinitialise() {
|
||||
readMethods.clear();
|
||||
writeMethods.clear();
|
||||
types.clear();
|
||||
initialise();
|
||||
}
|
||||
|
||||
private void initialise() {
|
||||
if(getBean() == null) return;
|
||||
|
||||
Class beanClass = getBean().getClass();
|
||||
try {
|
||||
//BeanInfo beanInfo = Introspector.getBeanInfo( bean, null );
|
||||
BeanInfo beanInfo = Introspector.getBeanInfo( beanClass );
|
||||
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
|
||||
if ( propertyDescriptors != null ) {
|
||||
for ( int i = 0; i < propertyDescriptors.length; i++ ) {
|
||||
PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
|
||||
if ( propertyDescriptor != null ) {
|
||||
String name = propertyDescriptor.getName();
|
||||
Method readMethod = propertyDescriptor.getReadMethod();
|
||||
Method writeMethod = propertyDescriptor.getWriteMethod();
|
||||
Class aType = propertyDescriptor.getPropertyType();
|
||||
|
||||
if ( readMethod != null ) {
|
||||
readMethods.put( name, readMethod );
|
||||
}
|
||||
if ( writeMethod != null ) {
|
||||
writeMethods.put( name, writeMethod );
|
||||
}
|
||||
types.put( name, aType );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( IntrospectionException e ) {
|
||||
logWarn( e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during a successful {@link #put(Object,Object)} operation.
|
||||
* Default implementation does nothing. Override to be notified of
|
||||
* property changes in the bean caused by this map.
|
||||
*
|
||||
* @param key the name of the property that changed
|
||||
* @param oldValue the old value for that property
|
||||
* @param newValue the new value for that property
|
||||
*/
|
||||
protected void firePropertyChange( Object key, Object oldValue, Object newValue ) {
|
||||
}
|
||||
|
||||
// Implementation classes
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Map entry used by {@link BeanMap}.
|
||||
*/
|
||||
protected static class MyMapEntry extends AbstractMapEntry {
|
||||
private BeanMap owner;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>MyMapEntry</code>.
|
||||
*
|
||||
* @param owner the BeanMap this entry belongs to
|
||||
* @param key the key for this entry
|
||||
* @param value the value for this entry
|
||||
*/
|
||||
protected MyMapEntry( BeanMap owner, Object key, Object value ) {
|
||||
super( key, value );
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*
|
||||
* @param value the new value for the entry
|
||||
* @return the old value for the entry
|
||||
*/
|
||||
public Object setValue(Object value) {
|
||||
Object key = getKey();
|
||||
Object oldValue = owner.get( key );
|
||||
|
||||
owner.put( key, value );
|
||||
Object newValue = owner.get( key );
|
||||
super.setValue( newValue );
|
||||
return oldValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of parameters to pass to the given mutator method.
|
||||
* If the given object is not the right type to pass to the method
|
||||
* directly, it will be converted using {@link #convertType(Class,Object)}.
|
||||
*
|
||||
* @param method the mutator method
|
||||
* @param value the value to pass to the mutator method
|
||||
* @return an array containing one object that is either the given value
|
||||
* or a transformed value
|
||||
* @throws IllegalAccessException if {@link #convertType(Class,Object)}
|
||||
* raises it
|
||||
* @throws IllegalArgumentException if any other exception is raised
|
||||
* by {@link #convertType(Class,Object)}
|
||||
*/
|
||||
protected Object[] createWriteMethodArguments( Method method, Object value ) throws IllegalAccessException, ClassCastException {
|
||||
try {
|
||||
if ( value != null ) {
|
||||
Class[] types = method.getParameterTypes();
|
||||
if ( types != null && types.length > 0 ) {
|
||||
Class paramType = types[0];
|
||||
if ( ! paramType.isAssignableFrom( value.getClass() ) ) {
|
||||
value = convertType( paramType, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
Object[] answer = { value };
|
||||
return answer;
|
||||
}
|
||||
catch ( InvocationTargetException e ) {
|
||||
logInfo( e );
|
||||
throw new IllegalArgumentException( e.getMessage() );
|
||||
}
|
||||
catch ( InstantiationException e ) {
|
||||
logInfo( e );
|
||||
throw new IllegalArgumentException( e.getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given value to the given type. First, reflection is
|
||||
* is used to find a public constructor declared by the given class
|
||||
* that takes one argument, which must be the precise type of the
|
||||
* given value. If such a constructor is found, a new object is
|
||||
* created by passing the given value to that constructor, and the
|
||||
* newly constructed object is returned.<P>
|
||||
*
|
||||
* If no such constructor exists, and the given type is a primitive
|
||||
* type, then the given value is converted to a string using its
|
||||
* {@link Object#toString() toString()} method, and that string is
|
||||
* parsed into the correct primitive type using, for instance,
|
||||
* {@link Integer#valueOf(String)} to convert the string into an
|
||||
* <code>int</code>.<P>
|
||||
*
|
||||
* If no special constructor exists and the given type is not a
|
||||
* primitive type, this method returns the original value.
|
||||
*
|
||||
* @param newType the type to convert the value to
|
||||
* @param value the value to convert
|
||||
* @return the converted value
|
||||
* @throws NumberFormatException if newType is a primitive type, and
|
||||
* the string representation of the given value cannot be converted
|
||||
* to that type
|
||||
* @throws InstantiationException if the constructor found with
|
||||
* reflection raises it
|
||||
* @throws InvocationTargetException if the constructor found with
|
||||
* reflection raises it
|
||||
* @throws IllegalAccessException never
|
||||
* @throws IllegalArgumentException never
|
||||
*/
|
||||
protected Object convertType( Class newType, Object value )
|
||||
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
|
||||
// try call constructor
|
||||
Class[] types = { value.getClass() };
|
||||
try {
|
||||
Constructor constructor = newType.getConstructor( types );
|
||||
Object[] arguments = { value };
|
||||
return constructor.newInstance( arguments );
|
||||
}
|
||||
catch ( NoSuchMethodException e ) {
|
||||
// try using the transformers
|
||||
Transformer transformer = getTypeTransformer( newType );
|
||||
if ( transformer != null ) {
|
||||
return transformer.transform( value );
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a transformer for the given primitive type.
|
||||
*
|
||||
* @param aType the primitive type whose transformer to return
|
||||
* @return a transformer that will convert strings into that type,
|
||||
* or null if the given type is not a primitive type
|
||||
*/
|
||||
protected Transformer getTypeTransformer( Class aType ) {
|
||||
return (Transformer) defaultTransformers.get( aType );
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given exception to <code>System.out</code>. Used to display
|
||||
* warnings while accessing/mutating the bean.
|
||||
*
|
||||
* @param ex the exception to log
|
||||
*/
|
||||
protected void logInfo(Exception ex) {
|
||||
// Deliberately do not use LOG4J or Commons Logging to avoid dependencies
|
||||
System.out.println( "INFO: Exception: " + ex );
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given exception to <code>System.err</code>. Used to display
|
||||
* errors while accessing/mutating the bean.
|
||||
*
|
||||
* @param ex the exception to log
|
||||
*/
|
||||
protected void logWarn(Exception ex) {
|
||||
// Deliberately do not use LOG4J or Commons Logging to avoid dependencies
|
||||
System.out.println( "WARN: Exception: " + ex );
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
|
@ -1,565 +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.AbstractCollection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Binary heap implementation of <code>PriorityQueue</code>.
|
||||
* <p>
|
||||
* The <code>PriorityQueue</code> interface has now been replaced for most uses
|
||||
* by the <code>Buffer</code> interface. This class and the interface are
|
||||
* retained for backwards compatibility. The intended replacement is
|
||||
* {@link org.apache.commons.collections.buffer.PriorityBuffer PriorityBuffer}.
|
||||
* <p>
|
||||
* The removal order of a binary heap is based on either the natural sort
|
||||
* order of its elements or a specified {@link Comparator}. The
|
||||
* {@link #pop()} method always returns the first element as determined
|
||||
* by the sort order. (The <code>isMinHeap</code> flag in the constructors
|
||||
* can be used to reverse the sort order, in which case {@link #pop()}
|
||||
* will always remove the last element.) The removal order is
|
||||
* <i>not</i> the same as the order of iteration; elements are
|
||||
* returned by the iterator in no particular order.
|
||||
* <p>
|
||||
* The {@link #insert(Object)} and {@link #pop()} operations perform
|
||||
* in logarithmic time. The {@link #peek()} operation performs in constant
|
||||
* time. All other operations perform in linear time or worse.
|
||||
* <p>
|
||||
* Note that this implementation is not synchronized. Use SynchronizedPriorityQueue
|
||||
* to provide synchronized access to a <code>BinaryHeap</code>:
|
||||
*
|
||||
* <pre>
|
||||
* PriorityQueue heap = new SynchronizedPriorityQueue(new BinaryHeap());
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated Replaced by PriorityBuffer in buffer subpackage.
|
||||
* Due to be removed in v4.0.
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Peter Donald
|
||||
* @author Ram Chidambaram
|
||||
* @author Michael A. Smith
|
||||
* @author Paul Jack
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public final class BinaryHeap extends AbstractCollection
|
||||
implements PriorityQueue, Buffer {
|
||||
|
||||
/**
|
||||
* The default capacity for a binary heap.
|
||||
*/
|
||||
private final static int DEFAULT_CAPACITY = 13;
|
||||
/**
|
||||
* The number of elements currently in this heap.
|
||||
*/
|
||||
int m_size; // package scoped for testing
|
||||
/**
|
||||
* The elements in this heap.
|
||||
*/
|
||||
Object[] m_elements; // package scoped for testing
|
||||
/**
|
||||
* If true, the first element as determined by the sort order will
|
||||
* be returned. If false, the last element as determined by the
|
||||
* sort order will be returned.
|
||||
*/
|
||||
boolean m_isMinHeap; // package scoped for testing
|
||||
/**
|
||||
* The comparator used to order the elements
|
||||
*/
|
||||
Comparator m_comparator; // package scoped for testing
|
||||
|
||||
/**
|
||||
* Constructs a new minimum binary heap.
|
||||
*/
|
||||
public BinaryHeap() {
|
||||
this(DEFAULT_CAPACITY, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>BinaryHeap</code> that will use the given
|
||||
* comparator to order its elements.
|
||||
*
|
||||
* @param comparator the comparator used to order the elements, null
|
||||
* means use natural order
|
||||
*/
|
||||
public BinaryHeap(Comparator comparator) {
|
||||
this();
|
||||
m_comparator = comparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new minimum binary heap with the specified initial capacity.
|
||||
*
|
||||
* @param capacity The initial capacity for the heap. This value must
|
||||
* be greater than zero.
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>capacity</code> is <= <code>0</code>
|
||||
*/
|
||||
public BinaryHeap(int capacity) {
|
||||
this(capacity, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>BinaryHeap</code>.
|
||||
*
|
||||
* @param capacity the initial capacity for the heap
|
||||
* @param comparator the comparator used to order the elements, null
|
||||
* means use natural order
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>capacity</code> is <= <code>0</code>
|
||||
*/
|
||||
public BinaryHeap(int capacity, Comparator comparator) {
|
||||
this(capacity);
|
||||
m_comparator = comparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new minimum or maximum binary heap
|
||||
*
|
||||
* @param isMinHeap if <code>true</code> the heap is created as a
|
||||
* minimum heap; otherwise, the heap is created as a maximum heap
|
||||
*/
|
||||
public BinaryHeap(boolean isMinHeap) {
|
||||
this(DEFAULT_CAPACITY, isMinHeap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>BinaryHeap</code>.
|
||||
*
|
||||
* @param isMinHeap true to use the order imposed by the given
|
||||
* comparator; false to reverse that order
|
||||
* @param comparator the comparator used to order the elements, null
|
||||
* means use natural order
|
||||
*/
|
||||
public BinaryHeap(boolean isMinHeap, Comparator comparator) {
|
||||
this(isMinHeap);
|
||||
m_comparator = comparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new minimum or maximum binary heap with the specified
|
||||
* initial capacity.
|
||||
*
|
||||
* @param capacity the initial capacity for the heap. This value must
|
||||
* be greater than zero.
|
||||
* @param isMinHeap if <code>true</code> the heap is created as a
|
||||
* minimum heap; otherwise, the heap is created as a maximum heap.
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>capacity</code> is <code><= 0</code>
|
||||
*/
|
||||
public BinaryHeap(int capacity, boolean isMinHeap) {
|
||||
if (capacity <= 0) {
|
||||
throw new IllegalArgumentException("invalid capacity");
|
||||
}
|
||||
m_isMinHeap = isMinHeap;
|
||||
|
||||
//+1 as 0 is noop
|
||||
m_elements = new Object[capacity + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>BinaryHeap</code>.
|
||||
*
|
||||
* @param capacity the initial capacity for the heap
|
||||
* @param isMinHeap true to use the order imposed by the given
|
||||
* comparator; false to reverse that order
|
||||
* @param comparator the comparator used to order the elements, null
|
||||
* means use natural order
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>capacity</code> is <code><= 0</code>
|
||||
*/
|
||||
public BinaryHeap(int capacity, boolean isMinHeap, Comparator comparator) {
|
||||
this(capacity, isMinHeap);
|
||||
m_comparator = comparator;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Clears all elements from queue.
|
||||
*/
|
||||
public void clear() {
|
||||
m_elements = new Object[m_elements.length]; // for gc
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if queue is empty.
|
||||
*
|
||||
* @return <code>true</code> if queue is empty; <code>false</code>
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if queue is full.
|
||||
*
|
||||
* @return <code>true</code> if queue is full; <code>false</code>
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isFull() {
|
||||
//+1 as element 0 is noop
|
||||
return m_elements.length == m_size + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an element into queue.
|
||||
*
|
||||
* @param element the element to be inserted
|
||||
*/
|
||||
public void insert(Object element) {
|
||||
if (isFull()) {
|
||||
grow();
|
||||
}
|
||||
//percolate element to it's place in tree
|
||||
if (m_isMinHeap) {
|
||||
percolateUpMinHeap(element);
|
||||
} else {
|
||||
percolateUpMaxHeap(element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element on top of heap but don't remove it.
|
||||
*
|
||||
* @return the element at top of heap
|
||||
* @throws NoSuchElementException if <code>isEmpty() == true</code>
|
||||
*/
|
||||
public Object peek() throws NoSuchElementException {
|
||||
if (isEmpty()) {
|
||||
throw new NoSuchElementException();
|
||||
} else {
|
||||
return m_elements[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element on top of heap and remove it.
|
||||
*
|
||||
* @return the element at top of heap
|
||||
* @throws NoSuchElementException if <code>isEmpty() == true</code>
|
||||
*/
|
||||
public Object pop() throws NoSuchElementException {
|
||||
final Object result = peek();
|
||||
m_elements[1] = m_elements[m_size--];
|
||||
|
||||
// set the unused element to 'null' so that the garbage collector
|
||||
// can free the object if not used anywhere else.(remove reference)
|
||||
m_elements[m_size + 1] = null;
|
||||
|
||||
if (m_size != 0) {
|
||||
// percolate top element to it's place in tree
|
||||
if (m_isMinHeap) {
|
||||
percolateDownMinHeap(1);
|
||||
} else {
|
||||
percolateDownMaxHeap(1);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Percolates element down heap from the position given by the index.
|
||||
* <p>
|
||||
* Assumes it is a minimum heap.
|
||||
*
|
||||
* @param index the index for the element
|
||||
*/
|
||||
protected void percolateDownMinHeap(final int index) {
|
||||
final Object element = m_elements[index];
|
||||
int hole = index;
|
||||
|
||||
while ((hole * 2) <= m_size) {
|
||||
int child = hole * 2;
|
||||
|
||||
// if we have a right child and that child can not be percolated
|
||||
// up then move onto other child
|
||||
if (child != m_size && compare(m_elements[child + 1], m_elements[child]) < 0) {
|
||||
child++;
|
||||
}
|
||||
|
||||
// if we found resting place of bubble then terminate search
|
||||
if (compare(m_elements[child], element) >= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
m_elements[hole] = m_elements[child];
|
||||
hole = child;
|
||||
}
|
||||
|
||||
m_elements[hole] = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Percolates element down heap from the position given by the index.
|
||||
* <p>
|
||||
* Assumes it is a maximum heap.
|
||||
*
|
||||
* @param index the index of the element
|
||||
*/
|
||||
protected void percolateDownMaxHeap(final int index) {
|
||||
final Object element = m_elements[index];
|
||||
int hole = index;
|
||||
|
||||
while ((hole * 2) <= m_size) {
|
||||
int child = hole * 2;
|
||||
|
||||
// if we have a right child and that child can not be percolated
|
||||
// up then move onto other child
|
||||
if (child != m_size && compare(m_elements[child + 1], m_elements[child]) > 0) {
|
||||
child++;
|
||||
}
|
||||
|
||||
// if we found resting place of bubble then terminate search
|
||||
if (compare(m_elements[child], element) <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
m_elements[hole] = m_elements[child];
|
||||
hole = child;
|
||||
}
|
||||
|
||||
m_elements[hole] = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Percolates element up heap from the position given by the index.
|
||||
* <p>
|
||||
* Assumes it is a minimum heap.
|
||||
*
|
||||
* @param index the index of the element to be percolated up
|
||||
*/
|
||||
protected void percolateUpMinHeap(final int index) {
|
||||
int hole = index;
|
||||
Object element = m_elements[hole];
|
||||
while (hole > 1 && compare(element, m_elements[hole / 2]) < 0) {
|
||||
// save element that is being pushed down
|
||||
// as the element "bubble" is percolated up
|
||||
final int next = hole / 2;
|
||||
m_elements[hole] = m_elements[next];
|
||||
hole = next;
|
||||
}
|
||||
m_elements[hole] = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Percolates a new element up heap from the bottom.
|
||||
* <p>
|
||||
* Assumes it is a minimum heap.
|
||||
*
|
||||
* @param element the element
|
||||
*/
|
||||
protected void percolateUpMinHeap(final Object element) {
|
||||
m_elements[++m_size] = element;
|
||||
percolateUpMinHeap(m_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Percolates element up heap from from the position given by the index.
|
||||
* <p>
|
||||
* Assume it is a maximum heap.
|
||||
*
|
||||
* @param index the index of the element to be percolated up
|
||||
*/
|
||||
protected void percolateUpMaxHeap(final int index) {
|
||||
int hole = index;
|
||||
Object element = m_elements[hole];
|
||||
|
||||
while (hole > 1 && compare(element, m_elements[hole / 2]) > 0) {
|
||||
// save element that is being pushed down
|
||||
// as the element "bubble" is percolated up
|
||||
final int next = hole / 2;
|
||||
m_elements[hole] = m_elements[next];
|
||||
hole = next;
|
||||
}
|
||||
|
||||
m_elements[hole] = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Percolates a new element up heap from the bottom.
|
||||
* <p>
|
||||
* Assume it is a maximum heap.
|
||||
*
|
||||
* @param element the element
|
||||
*/
|
||||
protected void percolateUpMaxHeap(final Object element) {
|
||||
m_elements[++m_size] = element;
|
||||
percolateUpMaxHeap(m_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two objects using the comparator if specified, or the
|
||||
* natural order otherwise.
|
||||
*
|
||||
* @param a the first object
|
||||
* @param b the second object
|
||||
* @return -ve if a less than b, 0 if they are equal, +ve if a greater than b
|
||||
*/
|
||||
private int compare(Object a, Object b) {
|
||||
if (m_comparator != null) {
|
||||
return m_comparator.compare(a, b);
|
||||
} else {
|
||||
return ((Comparable) a).compareTo(b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the size of the heap to support additional elements
|
||||
*/
|
||||
protected void grow() {
|
||||
final Object[] elements = new Object[m_elements.length * 2];
|
||||
System.arraycopy(m_elements, 0, elements, 0, m_elements.length);
|
||||
m_elements = elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this heap. The returned string
|
||||
* is similar to those produced by standard JDK collections.
|
||||
*
|
||||
* @return a string representation of this heap
|
||||
*/
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
|
||||
sb.append("[ ");
|
||||
|
||||
for (int i = 1; i < m_size + 1; i++) {
|
||||
if (i != 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(m_elements[i]);
|
||||
}
|
||||
|
||||
sb.append(" ]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator over this heap's elements.
|
||||
*
|
||||
* @return an iterator over this heap's elements
|
||||
*/
|
||||
public Iterator iterator() {
|
||||
return new Iterator() {
|
||||
|
||||
private int index = 1;
|
||||
private int lastReturnedIndex = -1;
|
||||
|
||||
public boolean hasNext() {
|
||||
return index <= m_size;
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
lastReturnedIndex = index;
|
||||
index++;
|
||||
return m_elements[lastReturnedIndex];
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (lastReturnedIndex == -1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
m_elements[ lastReturnedIndex ] = m_elements[ m_size ];
|
||||
m_elements[ m_size ] = null;
|
||||
m_size--;
|
||||
if( m_size != 0 && lastReturnedIndex <= m_size) {
|
||||
int compareToParent = 0;
|
||||
if (lastReturnedIndex > 1) {
|
||||
compareToParent = compare(m_elements[lastReturnedIndex],
|
||||
m_elements[lastReturnedIndex / 2]);
|
||||
}
|
||||
if (m_isMinHeap) {
|
||||
if (lastReturnedIndex > 1 && compareToParent < 0) {
|
||||
percolateUpMinHeap(lastReturnedIndex);
|
||||
} else {
|
||||
percolateDownMinHeap(lastReturnedIndex);
|
||||
}
|
||||
} else { // max heap
|
||||
if (lastReturnedIndex > 1 && compareToParent > 0) {
|
||||
percolateUpMaxHeap(lastReturnedIndex);
|
||||
} else {
|
||||
percolateDownMaxHeap(lastReturnedIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
index--;
|
||||
lastReturnedIndex = -1;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an object to this heap. Same as {@link #insert(Object)}.
|
||||
*
|
||||
* @param object the object to add
|
||||
* @return true, always
|
||||
*/
|
||||
public boolean add(Object object) {
|
||||
insert(object);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the priority element. Same as {@link #peek()}.
|
||||
*
|
||||
* @return the priority element
|
||||
* @throws BufferUnderflowException if this heap is empty
|
||||
*/
|
||||
public Object get() {
|
||||
try {
|
||||
return peek();
|
||||
} catch (NoSuchElementException e) {
|
||||
throw new BufferUnderflowException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the priority element. Same as {@link #pop()}.
|
||||
*
|
||||
* @return the removed priority element
|
||||
* @throws BufferUnderflowException if this heap is empty
|
||||
*/
|
||||
public Object remove() {
|
||||
try {
|
||||
return pop();
|
||||
} catch (NoSuchElementException e) {
|
||||
throw new BufferUnderflowException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this heap.
|
||||
*
|
||||
* @return the number of elements in this heap
|
||||
*/
|
||||
public int size() {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,311 +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.AbstractCollection;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* The BoundedFifoBuffer is a very efficient implementation of
|
||||
* Buffer that does not alter the size of the buffer at runtime.
|
||||
* <p>
|
||||
* The removal order of a <code>BoundedFifoBuffer</code> is based on the
|
||||
* insertion order; elements are removed in the same order in which they
|
||||
* were added. The iteration order is the same as the removal order.
|
||||
* <p>
|
||||
* The {@link #add(Object)}, {@link #remove()} and {@link #get()} operations
|
||||
* all perform in constant time. All other operations perform in linear
|
||||
* time or worse.
|
||||
* <p>
|
||||
* Note that this implementation is not synchronized. The following can be
|
||||
* used to provide synchronized access to your <code>BoundedFifoBuffer</code>:
|
||||
* <pre>
|
||||
* Buffer fifo = BufferUtils.synchronizedBuffer(new BoundedFifoBuffer());
|
||||
* </pre>
|
||||
* <p>
|
||||
* This buffer prevents null objects from being added.
|
||||
*
|
||||
* @deprecated Moved to buffer subpackage. Due to be removed in v4.0.
|
||||
* @since 2.1
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Avalon
|
||||
* @author Berin Loritsch
|
||||
* @author Paul Jack
|
||||
* @author Stephen Colebourne
|
||||
* @author Herve Quiroz
|
||||
*/
|
||||
public class BoundedFifoBuffer extends AbstractCollection
|
||||
implements Buffer, BoundedCollection {
|
||||
|
||||
private final Object[] m_elements;
|
||||
private int m_start = 0;
|
||||
private int m_end = 0;
|
||||
private boolean m_full = false;
|
||||
private final int maxElements;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>BoundedFifoBuffer</code> big enough to hold
|
||||
* 32 elements.
|
||||
*/
|
||||
public BoundedFifoBuffer() {
|
||||
this(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>BoundedFifoBuffer</code> big enough to hold
|
||||
* the specified number of elements.
|
||||
*
|
||||
* @param size the maximum number of elements for this fifo
|
||||
* @throws IllegalArgumentException if the size is less than 1
|
||||
*/
|
||||
public BoundedFifoBuffer(int size) {
|
||||
if (size <= 0) {
|
||||
throw new IllegalArgumentException("The size must be greater than 0");
|
||||
}
|
||||
m_elements = new Object[size];
|
||||
maxElements = m_elements.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>BoundedFifoBuffer</code> big enough to hold all
|
||||
* of the elements in the specified collection. That collection's
|
||||
* elements will also be added to the buffer.
|
||||
*
|
||||
* @param coll the collection whose elements to add, may not be null
|
||||
* @throws NullPointerException if the collection is null
|
||||
*/
|
||||
public BoundedFifoBuffer(Collection coll) {
|
||||
this(coll.size());
|
||||
addAll(coll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements stored in the buffer.
|
||||
*
|
||||
* @return this buffer's size
|
||||
*/
|
||||
public int size() {
|
||||
int size = 0;
|
||||
|
||||
if (m_end < m_start) {
|
||||
size = maxElements - m_start + m_end;
|
||||
} else if (m_end == m_start) {
|
||||
size = (m_full ? maxElements : 0);
|
||||
} else {
|
||||
size = m_end - m_start;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this buffer is empty; false otherwise.
|
||||
*
|
||||
* @return true if this buffer is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this collection is full and no new elements can be added.
|
||||
*
|
||||
* @return <code>true</code> if the collection is full
|
||||
*/
|
||||
public boolean isFull() {
|
||||
return size() == maxElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum size of the collection (the bound).
|
||||
*
|
||||
* @return the maximum number of elements the collection can hold
|
||||
*/
|
||||
public int maxSize() {
|
||||
return maxElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears this buffer.
|
||||
*/
|
||||
public void clear() {
|
||||
m_full = false;
|
||||
m_start = 0;
|
||||
m_end = 0;
|
||||
Arrays.fill(m_elements, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given element to this buffer.
|
||||
*
|
||||
* @param element the element to add
|
||||
* @return true, always
|
||||
* @throws NullPointerException if the given element is null
|
||||
* @throws BufferOverflowException if this buffer is full
|
||||
*/
|
||||
public boolean add(Object element) {
|
||||
if (null == element) {
|
||||
throw new NullPointerException("Attempted to add null object to buffer");
|
||||
}
|
||||
|
||||
if (m_full) {
|
||||
throw new BufferOverflowException("The buffer cannot hold more than " + maxElements + " objects.");
|
||||
}
|
||||
|
||||
m_elements[m_end++] = element;
|
||||
|
||||
if (m_end >= maxElements) {
|
||||
m_end = 0;
|
||||
}
|
||||
|
||||
if (m_end == m_start) {
|
||||
m_full = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the least recently inserted element in this buffer.
|
||||
*
|
||||
* @return the least recently inserted element
|
||||
* @throws BufferUnderflowException if the buffer is empty
|
||||
*/
|
||||
public Object get() {
|
||||
if (isEmpty()) {
|
||||
throw new BufferUnderflowException("The buffer is already empty");
|
||||
}
|
||||
|
||||
return m_elements[m_start];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the least recently inserted element from this buffer.
|
||||
*
|
||||
* @return the least recently inserted element
|
||||
* @throws BufferUnderflowException if the buffer is empty
|
||||
*/
|
||||
public Object remove() {
|
||||
if (isEmpty()) {
|
||||
throw new BufferUnderflowException("The buffer is already empty");
|
||||
}
|
||||
|
||||
Object element = m_elements[m_start];
|
||||
|
||||
if (null != element) {
|
||||
m_elements[m_start++] = null;
|
||||
|
||||
if (m_start >= maxElements) {
|
||||
m_start = 0;
|
||||
}
|
||||
|
||||
m_full = false;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the internal index.
|
||||
*
|
||||
* @param index the index to increment
|
||||
* @return the updated index
|
||||
*/
|
||||
private int increment(int index) {
|
||||
index++;
|
||||
if (index >= maxElements) {
|
||||
index = 0;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the internal index.
|
||||
*
|
||||
* @param index the index to decrement
|
||||
* @return the updated index
|
||||
*/
|
||||
private int decrement(int index) {
|
||||
index--;
|
||||
if (index < 0) {
|
||||
index = maxElements - 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over this buffer's elements.
|
||||
*
|
||||
* @return an iterator over this buffer's elements
|
||||
*/
|
||||
public Iterator iterator() {
|
||||
return new Iterator() {
|
||||
|
||||
private int index = m_start;
|
||||
private int lastReturnedIndex = -1;
|
||||
private boolean isFirst = m_full;
|
||||
|
||||
public boolean hasNext() {
|
||||
return isFirst || (index != m_end);
|
||||
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
isFirst = false;
|
||||
lastReturnedIndex = index;
|
||||
index = increment(index);
|
||||
return m_elements[lastReturnedIndex];
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (lastReturnedIndex == -1) throw new IllegalStateException();
|
||||
|
||||
// First element can be removed quickly
|
||||
if (lastReturnedIndex == m_start) {
|
||||
BoundedFifoBuffer.this.remove();
|
||||
lastReturnedIndex = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Other elements require us to shift the subsequent elements
|
||||
int i = lastReturnedIndex + 1;
|
||||
while (i != m_end) {
|
||||
if (i >= maxElements) {
|
||||
m_elements[i - 1] = m_elements[0];
|
||||
i = 0;
|
||||
} else {
|
||||
m_elements[i - 1] = m_elements[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
lastReturnedIndex = -1;
|
||||
m_end = decrement(m_end);
|
||||
m_elements[m_end] = null;
|
||||
m_full = false;
|
||||
index = decrement(index);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,455 +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.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.collections.set.UnmodifiableSet;
|
||||
|
||||
/**
|
||||
* A skeletal implementation of the {@link Bag}
|
||||
* interface to minimize the effort required for target implementations.
|
||||
* Subclasses need only to call <code>setMap(Map)</code> in their constructor
|
||||
* (or invoke the Map constructor) specifying a map instance that will be used
|
||||
* to store the contents of the bag.
|
||||
* <p>
|
||||
* The map will be used to map bag elements to a number; the number represents
|
||||
* the number of occurrences of that element in the bag.
|
||||
*
|
||||
* @deprecated Moved to bag subpackage as AbstractMapBag. Due to be removed in v4.0.
|
||||
* @since Commons Collections 2.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Chuck Burdick
|
||||
* @author Michael A. Smith
|
||||
* @author Stephen Colebourne
|
||||
* @author Janek Bogucki
|
||||
*/
|
||||
public abstract class DefaultMapBag implements Bag {
|
||||
private Map _map = null;
|
||||
private int _total = 0;
|
||||
private int _mods = 0;
|
||||
|
||||
/**
|
||||
* No-argument constructor.
|
||||
* Subclasses should invoke <code>setMap(Map)</code> in
|
||||
* their constructors.
|
||||
*/
|
||||
public DefaultMapBag() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that assigns the specified Map as the backing store.
|
||||
* The map must be empty.
|
||||
*
|
||||
* @param map the map to assign
|
||||
*/
|
||||
protected DefaultMapBag(Map map) {
|
||||
setMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new element to the bag by incrementing its count in the
|
||||
* underlying map.
|
||||
*
|
||||
* @param object the object to add
|
||||
* @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
|
||||
*/
|
||||
public boolean add(Object object) {
|
||||
return add(object, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new element to the bag by incrementing its count in the map.
|
||||
*
|
||||
* @param object the object to search for
|
||||
* @param nCopies the number of copies to add
|
||||
* @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
|
||||
*/
|
||||
public boolean add(Object object, int nCopies) {
|
||||
_mods++;
|
||||
if (nCopies > 0) {
|
||||
int count = (nCopies + getCount(object));
|
||||
_map.put(object, new Integer(count));
|
||||
_total += nCopies;
|
||||
return (count == nCopies);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link #add(Object)} for each element in the given collection.
|
||||
*
|
||||
* @param coll the collection to add
|
||||
* @return <code>true</code> if this call changed the bag
|
||||
*/
|
||||
public boolean addAll(Collection coll) {
|
||||
boolean changed = false;
|
||||
Iterator i = coll.iterator();
|
||||
while (i.hasNext()) {
|
||||
boolean added = add(i.next());
|
||||
changed = changed || added;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the bag by clearing the underlying map.
|
||||
*/
|
||||
public void clear() {
|
||||
_mods++;
|
||||
_map.clear();
|
||||
_total = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the bag contains the given element by checking if the
|
||||
* underlying map contains the element as a key.
|
||||
*
|
||||
* @param object the object to search for
|
||||
* @return true if the bag contains the given element
|
||||
*/
|
||||
public boolean contains(Object object) {
|
||||
return _map.containsKey(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the bag contains the given elements.
|
||||
*
|
||||
* @param coll the collection to check against
|
||||
* @return <code>true</code> if the Bag contains all the collection
|
||||
*/
|
||||
public boolean containsAll(Collection coll) {
|
||||
return containsAll(new HashBag(coll));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the bag contains all elements in
|
||||
* the given collection, respecting cardinality.
|
||||
*
|
||||
* @param other the bag to check against
|
||||
* @return <code>true</code> if the Bag contains all the collection
|
||||
*/
|
||||
public boolean containsAll(Bag other) {
|
||||
boolean result = true;
|
||||
Iterator i = other.uniqueSet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Object current = i.next();
|
||||
boolean contains = getCount(current) >= other.getCount(current);
|
||||
result = result && contains;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given object is not null, has the precise type
|
||||
* of this bag, and contains the same number of occurrences of all the
|
||||
* same elements.
|
||||
*
|
||||
* @param object the object to test for equality
|
||||
* @return true if that object equals this bag
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
if (object == this) {
|
||||
return true;
|
||||
}
|
||||
if (object instanceof Bag == false) {
|
||||
return false;
|
||||
}
|
||||
Bag other = (Bag) object;
|
||||
if (other.size() != size()) {
|
||||
return false;
|
||||
}
|
||||
for (Iterator it = _map.keySet().iterator(); it.hasNext();) {
|
||||
Object element = it.next();
|
||||
if (other.getCount(element) != getCount(element)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code of the underlying map.
|
||||
*
|
||||
* @return the hash code of the underlying map
|
||||
*/
|
||||
public int hashCode() {
|
||||
return _map.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the underlying map is empty.
|
||||
*
|
||||
* @return true if there are no elements in this bag
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return _map.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new BagIterator(this, extractList().iterator());
|
||||
}
|
||||
|
||||
static class BagIterator implements Iterator {
|
||||
private DefaultMapBag _parent = null;
|
||||
private Iterator _support = null;
|
||||
private Object _current = null;
|
||||
private int _mods = 0;
|
||||
|
||||
public BagIterator(DefaultMapBag parent, Iterator support) {
|
||||
_parent = parent;
|
||||
_support = support;
|
||||
_current = null;
|
||||
_mods = parent.modCount();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return _support.hasNext();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (_parent.modCount() != _mods) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
_current = _support.next();
|
||||
return _current;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (_parent.modCount() != _mods) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
_support.remove();
|
||||
_parent.remove(_current, 1);
|
||||
_mods++;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remove(Object object) {
|
||||
return remove(object, getCount(object));
|
||||
}
|
||||
|
||||
public boolean remove(Object object, int nCopies) {
|
||||
_mods++;
|
||||
boolean result = false;
|
||||
int count = getCount(object);
|
||||
if (nCopies <= 0) {
|
||||
result = false;
|
||||
} else if (count > nCopies) {
|
||||
_map.put(object, new Integer(count - nCopies));
|
||||
result = true;
|
||||
_total -= nCopies;
|
||||
} else { // count > 0 && count <= i
|
||||
// need to remove all
|
||||
result = (_map.remove(object) != null);
|
||||
_total -= count;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection coll) {
|
||||
boolean result = false;
|
||||
if (coll != null) {
|
||||
Iterator i = coll.iterator();
|
||||
while (i.hasNext()) {
|
||||
boolean changed = remove(i.next(), 1);
|
||||
result = result || changed;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any members of the bag that are not in the given
|
||||
* bag, respecting cardinality.
|
||||
*
|
||||
* @param coll the collection to retain
|
||||
* @return true if this call changed the collection
|
||||
*/
|
||||
public boolean retainAll(Collection coll) {
|
||||
return retainAll(new HashBag(coll));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any members of the bag that are not in the given
|
||||
* bag, respecting cardinality.
|
||||
* @see #retainAll(Collection)
|
||||
*
|
||||
* @param other the bag to retain
|
||||
* @return <code>true</code> if this call changed the collection
|
||||
*/
|
||||
public boolean retainAll(Bag other) {
|
||||
boolean result = false;
|
||||
Bag excess = new HashBag();
|
||||
Iterator i = uniqueSet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Object current = i.next();
|
||||
int myCount = getCount(current);
|
||||
int otherCount = other.getCount(current);
|
||||
if (1 <= otherCount && otherCount <= myCount) {
|
||||
excess.add(current, myCount - otherCount);
|
||||
} else {
|
||||
excess.add(current, myCount);
|
||||
}
|
||||
}
|
||||
if (!excess.isEmpty()) {
|
||||
result = removeAll(excess);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all of this bag's elements.
|
||||
*
|
||||
* @return an array of all of this bag's elements
|
||||
*/
|
||||
public Object[] toArray() {
|
||||
return extractList().toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all of this bag's elements.
|
||||
*
|
||||
* @param array the array to populate
|
||||
* @return an array of all of this bag's elements
|
||||
*/
|
||||
public Object[] toArray(Object[] array) {
|
||||
return extractList().toArray(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of occurrence of the given element in this bag
|
||||
* by looking up its count in the underlying map.
|
||||
*
|
||||
* @param object the object to search for
|
||||
* @return the number of occurrences of the object, zero if not found
|
||||
*/
|
||||
public int getCount(Object object) {
|
||||
int result = 0;
|
||||
Integer count = MapUtils.getInteger(_map, object);
|
||||
if (count != null) {
|
||||
result = count.intValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view of the underlying map's key set.
|
||||
*
|
||||
* @return the set of unique elements in this bag
|
||||
*/
|
||||
public Set uniqueSet() {
|
||||
return UnmodifiableSet.decorate(_map.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this bag.
|
||||
*
|
||||
* @return the number of elements in this bag
|
||||
*/
|
||||
public int size() {
|
||||
return _total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually walks the bag to make sure the count is correct and
|
||||
* resets the running total
|
||||
*
|
||||
* @return the current total size
|
||||
*/
|
||||
protected int calcTotalSize() {
|
||||
_total = extractList().size();
|
||||
return _total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for implementations to set the map that backs
|
||||
* this bag. Not intended for interactive use outside of
|
||||
* subclasses.
|
||||
*/
|
||||
protected void setMap(Map map) {
|
||||
if (map == null || map.isEmpty() == false) {
|
||||
throw new IllegalArgumentException("The map must be non-null and empty");
|
||||
}
|
||||
_map = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for implementations to access the map that backs
|
||||
* this bag. Not intended for interactive use outside of
|
||||
* subclasses.
|
||||
*/
|
||||
protected Map getMap() {
|
||||
return _map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list for use in iteration, etc.
|
||||
*/
|
||||
private List extractList() {
|
||||
List result = new ArrayList();
|
||||
Iterator i = uniqueSet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Object current = i.next();
|
||||
for (int index = getCount(current); index > 0; index--) {
|
||||
result.add(current);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of modifications for iterator.
|
||||
*
|
||||
* @return the modification count
|
||||
*/
|
||||
private int modCount() {
|
||||
return _mods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement a toString() method suitable for debugging.
|
||||
*
|
||||
* @return a debugging toString
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("[");
|
||||
Iterator i = uniqueSet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Object current = i.next();
|
||||
int count = getCount(current);
|
||||
buf.append(count);
|
||||
buf.append(":");
|
||||
buf.append(current);
|
||||
if (i.hasNext()) {
|
||||
buf.append(",");
|
||||
}
|
||||
}
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,163 +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;
|
||||
|
||||
/**
|
||||
* A default implementation of {@link java.util.Map.Entry}
|
||||
*
|
||||
* @deprecated Use the version in the keyvalue subpackage. Will be removed in v4.0
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author James Strachan
|
||||
* @author Michael A. Smith
|
||||
* @author Neil O'Toole
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public class DefaultMapEntry implements Map.Entry, KeyValue {
|
||||
|
||||
/** The key */
|
||||
private Object key;
|
||||
/** The value */
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>DefaultMapEntry</code> with a null key
|
||||
* and null value.
|
||||
*/
|
||||
public DefaultMapEntry() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>DefaultMapEntry</code> with the given
|
||||
* key and given value.
|
||||
*
|
||||
* @param entry the entry to copy, must not be null
|
||||
* @throws NullPointerException if the entry is null
|
||||
*/
|
||||
public DefaultMapEntry(Map.Entry entry) {
|
||||
super();
|
||||
this.key = entry.getKey();
|
||||
this.value = entry.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>DefaultMapEntry</code> with the given
|
||||
* key and given value.
|
||||
*
|
||||
* @param key the key for the entry, may be null
|
||||
* @param value the value for the entry, may be null
|
||||
*/
|
||||
public DefaultMapEntry(Object key, Object value) {
|
||||
super();
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
// Map.Entry interface
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the key from the Map Entry.
|
||||
*
|
||||
* @return the key
|
||||
*/
|
||||
public Object getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key stored in this Map Entry.
|
||||
* <p>
|
||||
* This Map Entry is not connected to a Map, so only the local data is changed.
|
||||
*
|
||||
* @param key the new key
|
||||
*/
|
||||
public void setKey(Object key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value from the Map Entry.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value stored in this Map Entry.
|
||||
* <p>
|
||||
* This Map Entry is not connected to a Map, so only the local data is changed.
|
||||
*
|
||||
* @param value the new value
|
||||
* @return the previous value
|
||||
*/
|
||||
public Object setValue(Object value) {
|
||||
Object answer = this.value;
|
||||
this.value = value;
|
||||
return answer;
|
||||
}
|
||||
|
||||
// Basics
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this Map Entry with another Map Entry.
|
||||
* <p>
|
||||
* Implemented per API documentation of {@link java.util.Map.Entry#equals(Object)}
|
||||
*
|
||||
* @param obj the object to compare to
|
||||
* @return true if equal key and value
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Map.Entry == false) {
|
||||
return false;
|
||||
}
|
||||
Map.Entry other = (Map.Entry) obj;
|
||||
return
|
||||
(getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) &&
|
||||
(getValue() == null ? other.getValue() == null : getValue().equals(other.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hashCode compatible with the equals method.
|
||||
* <p>
|
||||
* Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
public int hashCode() {
|
||||
return (getKey() == null ? 0 : getKey().hashCode()) ^
|
||||
(getValue() == null ? 0 : getValue().hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Written to match the output of the Map.Entry's used in
|
||||
* a {@link java.util.HashMap}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public String toString() {
|
||||
return ""+getKey()+"="+getValue();
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -176,16 +176,7 @@ public class ExtendedProperties extends Hashtable {
|
|||
* This is the name of the property that can point to other
|
||||
* properties file for including other properties files.
|
||||
*/
|
||||
private String includePropertyName = null;
|
||||
|
||||
/**
|
||||
* This is the default name of the property that can point to other
|
||||
* properties file for including other properties files.
|
||||
*
|
||||
* @deprecated Use getInclude() and setInclude() methods which operate
|
||||
* on an instance variable from v3.3. Due to be removed in v4.0.
|
||||
*/
|
||||
protected static String include = "include";
|
||||
private String includePropertyName = "include";
|
||||
|
||||
/**
|
||||
* These are the keys in the order they listed
|
||||
|
@ -501,41 +492,20 @@ public class ExtendedProperties extends Hashtable {
|
|||
/**
|
||||
* Gets the property value for including other properties files.
|
||||
* By default it is "include".
|
||||
* <p>
|
||||
* NOTE: Prior to v3.3 this method accessed a static variable.
|
||||
* It now accesses an instance variable. For compatability, if the
|
||||
* instance variable has not been set then the previous static
|
||||
* variable is then accessed. However, the protected static variable
|
||||
* can now only be set by subclasses.
|
||||
* In v4.0, the static variable will be removed.
|
||||
*
|
||||
* @return the property name which includes another property
|
||||
*/
|
||||
public String getInclude() {
|
||||
if (includePropertyName == null) {
|
||||
return include; // backwards compatability
|
||||
}
|
||||
if ("".equals(includePropertyName)) {
|
||||
return null; // hack to allow backwards compatability
|
||||
}
|
||||
return includePropertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property value for including other properties files.
|
||||
* By default it is "include".
|
||||
* <p>
|
||||
* NOTE: Prior to v3.3 this method set a static variable and affected all
|
||||
* users of the class. It now sets an instance variable.
|
||||
* An empty string is also now converted to null internally.
|
||||
* In v4.0, the static variable will be removed.
|
||||
*
|
||||
* @param inc the property name which includes another property, empty converted to null
|
||||
*/
|
||||
public void setInclude(String inc) {
|
||||
if (inc == null) {
|
||||
inc = ""; // hack to allow backwards compatability
|
||||
}
|
||||
includePropertyName = inc;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,51 +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.HashMap;
|
||||
|
||||
/**
|
||||
* A {@link Bag} that is backed by a {@link HashMap}.
|
||||
*
|
||||
* @deprecated Moved to bag subpackage and rewritten internally. Due to be removed in v4.0.
|
||||
* @since Commons Collections 2.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Chuck Burdick
|
||||
*/
|
||||
public class HashBag extends DefaultMapBag implements Bag {
|
||||
|
||||
/**
|
||||
* Constructs an empty <Code>HashBag</Code>.
|
||||
*/
|
||||
public HashBag() {
|
||||
super(new HashMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link Bag} containing all the members of the given
|
||||
* collection.
|
||||
*
|
||||
* @param coll a collection to copy into this bag
|
||||
*/
|
||||
public HashBag(Collection coll) {
|
||||
this();
|
||||
addAll(coll);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,207 +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.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An implementation of a Map which has a maximum size and uses a Least Recently Used
|
||||
* algorithm to remove items from the Map when the maximum size is reached and new items are added.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A synchronized version can be obtained with:
|
||||
* <code>Collections.synchronizedMap( theMapToSynchronize )</code>
|
||||
* If it will be accessed by multiple threads, you _must_ synchronize access
|
||||
* to this Map. Even concurrent get(Object) operations produce indeterminate
|
||||
* behaviour.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Unlike the Collections 1.0 version, this version of LRUMap does use a true
|
||||
* LRU algorithm. The keys for all gets and puts are moved to the front of
|
||||
* the list. LRUMap is now a subclass of SequencedHashMap, and the "LRU"
|
||||
* key is now equivalent to LRUMap.getFirst().
|
||||
* </p>
|
||||
*
|
||||
* @deprecated Moved to map subpackage. Due to be removed in v4.0.
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
|
||||
* @author <a href="mailto:morgand@apache.org">Morgan Delagrange</a>
|
||||
*/
|
||||
public class LRUMap extends SequencedHashMap implements Externalizable {
|
||||
|
||||
private int maximumSize = 0;
|
||||
|
||||
/**
|
||||
* Default constructor, primarily for the purpose of
|
||||
* de-externalization. This constructors sets a default
|
||||
* LRU limit of 100 keys, but this value may be overridden
|
||||
* internally as a result of de-externalization.
|
||||
*/
|
||||
public LRUMap() {
|
||||
this( 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new LRUMap with a maximum capacity of <i>i</i>.
|
||||
* Once <i>i</i> capacity is achieved, subsequent gets
|
||||
* and puts will push keys out of the map. See .
|
||||
*
|
||||
* @param i Maximum capacity of the LRUMap
|
||||
*/
|
||||
public LRUMap(int i) {
|
||||
super( i );
|
||||
maximumSize = i;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the value for a key from the Map. The key
|
||||
* will be promoted to the Most Recently Used position.
|
||||
* Note that get(Object) operations will modify
|
||||
* the underlying Collection. Calling get(Object)
|
||||
* inside of an iteration over keys, values, etc. is
|
||||
* currently unsupported.</p>
|
||||
*
|
||||
* @param key Key to retrieve
|
||||
* @return Returns the value. Returns null if the key has a
|
||||
* null value <i>or</i> if the key has no value.
|
||||
*/
|
||||
public Object get(Object key) {
|
||||
if(!containsKey(key)) return null;
|
||||
|
||||
Object value = remove(key);
|
||||
super.put(key,value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Removes the key and its Object from the Map.</p>
|
||||
*
|
||||
* <p>(Note: this may result in the "Least Recently Used"
|
||||
* object being removed from the Map. In that case,
|
||||
* the removeLRU() method is called. See javadoc for
|
||||
* removeLRU() for more details.)</p>
|
||||
*
|
||||
* @param key Key of the Object to add.
|
||||
* @param value Object to add
|
||||
* @return Former value of the key
|
||||
*/
|
||||
public Object put( Object key, Object value ) {
|
||||
|
||||
int mapSize = size();
|
||||
Object retval = null;
|
||||
|
||||
if ( mapSize >= maximumSize ) {
|
||||
|
||||
// don't retire LRU if you are just
|
||||
// updating an existing key
|
||||
if (!containsKey(key)) {
|
||||
// lets retire the least recently used item in the cache
|
||||
removeLRU();
|
||||
}
|
||||
}
|
||||
|
||||
retval = super.put(key,value);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used internally by the class for
|
||||
* finding and removing the LRU Object.
|
||||
*/
|
||||
protected void removeLRU() {
|
||||
Object key = getFirstKey();
|
||||
// be sure to call super.get(key), or you're likely to
|
||||
// get infinite promotion recursion
|
||||
Object value = super.get(key);
|
||||
|
||||
remove(key);
|
||||
|
||||
processRemovedLRU(key,value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses of LRUMap may hook into this method to
|
||||
* provide specialized actions whenever an Object is
|
||||
* automatically removed from the cache. By default,
|
||||
* this method does nothing.
|
||||
*
|
||||
* @param key key that was removed
|
||||
* @param value value of that key (can be null)
|
||||
*/
|
||||
protected void processRemovedLRU(Object key, Object value) {
|
||||
}
|
||||
|
||||
// Externalizable interface
|
||||
//-------------------------------------------------------------------------
|
||||
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException {
|
||||
maximumSize = in.readInt();
|
||||
int size = in.readInt();
|
||||
|
||||
for( int i = 0; i < size; i++ ) {
|
||||
Object key = in.readObject();
|
||||
Object value = in.readObject();
|
||||
put(key,value);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeExternal( ObjectOutput out ) throws IOException {
|
||||
out.writeInt( maximumSize );
|
||||
out.writeInt( size() );
|
||||
for( Iterator iterator = keySet().iterator(); iterator.hasNext(); ) {
|
||||
Object key = iterator.next();
|
||||
out.writeObject( key );
|
||||
// be sure to call super.get(key), or you're likely to
|
||||
// get infinite promotion recursion
|
||||
Object value = super.get( key );
|
||||
out.writeObject( value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Properties
|
||||
//-------------------------------------------------------------------------
|
||||
/** Getter for property maximumSize.
|
||||
* @return Value of property maximumSize.
|
||||
*/
|
||||
public int getMaximumSize() {
|
||||
return maximumSize;
|
||||
}
|
||||
/** Setter for property maximumSize.
|
||||
* @param maximumSize New value of property maximumSize.
|
||||
*/
|
||||
public void setMaximumSize(int maximumSize) {
|
||||
this.maximumSize = maximumSize;
|
||||
while (size() > maximumSize) {
|
||||
removeLRU();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add a serial version uid, so that if we change things in the future
|
||||
// without changing the format, we can still deserialize properly.
|
||||
private static final long serialVersionUID = 2197433140769957051L;
|
||||
}
|
|
@ -1,493 +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.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.collections.iterators.EmptyIterator;
|
||||
|
||||
/**
|
||||
* <code>MultiHashMap</code> is the default implementation of the
|
||||
* {@link org.apache.commons.collections.MultiMap MultiMap} interface.
|
||||
* <p>
|
||||
* A <code>MultiMap</code> is a Map with slightly different semantics.
|
||||
* Putting a value into the map will add the value to a Collection at that key.
|
||||
* Getting a value will return a Collection, holding all the values put to that key.
|
||||
* <p>
|
||||
* This implementation uses an <code>ArrayList</code> as the collection.
|
||||
* The internal storage list is made available without cloning via the
|
||||
* <code>get(Object)</code> and <code>entrySet()</code> methods.
|
||||
* The implementation returns <code>null</code> when there are no values mapped to a key.
|
||||
* <p>
|
||||
* For example:
|
||||
* <pre>
|
||||
* MultiMap mhm = new MultiHashMap();
|
||||
* mhm.put(key, "A");
|
||||
* mhm.put(key, "B");
|
||||
* mhm.put(key, "C");
|
||||
* List list = (List) mhm.get(key);</pre>
|
||||
* <p>
|
||||
* <code>list</code> will be a list containing "A", "B", "C".
|
||||
*
|
||||
* @deprecated Class now available as MultiValueMap in map subpackage.
|
||||
* This version is due to be removed in collections v4.0.
|
||||
*
|
||||
* @since Commons Collections 2.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Christopher Berry
|
||||
* @author James Strachan
|
||||
* @author Steve Downey
|
||||
* @author Stephen Colebourne
|
||||
* @author Julien Buret
|
||||
* @author Serhiy Yevtushenko
|
||||
* @author Robert Ribnitz
|
||||
*/
|
||||
public class MultiHashMap extends HashMap implements MultiMap {
|
||||
|
||||
// backed values collection
|
||||
private transient Collection values = null;
|
||||
|
||||
// compatibility with commons-collection releases 2.0/2.1
|
||||
private static final long serialVersionUID = 1943563828307035349L;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public MultiHashMap() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param initialCapacity the initial map capacity
|
||||
*/
|
||||
public MultiHashMap(int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param initialCapacity the initial map capacity
|
||||
* @param loadFactor the amount 0.0-1.0 at which to resize the map
|
||||
*/
|
||||
public MultiHashMap(int initialCapacity, float loadFactor) {
|
||||
super(initialCapacity, loadFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that copies the input map creating an independent copy.
|
||||
* <p>
|
||||
* This method performs different behaviour depending on whether the map
|
||||
* specified is a MultiMap or not. If a MultiMap is specified, each internal
|
||||
* collection is also cloned. If the specified map only implements Map, then
|
||||
* the values are not cloned.
|
||||
* <p>
|
||||
* NOTE: From Commons Collections 3.1 this method correctly copies a MultiMap
|
||||
* to form a truly independent new map.
|
||||
* NOTE: From Commons Collections 3.2 this method delegates to the newly
|
||||
* added putAll(Map) override method.
|
||||
*
|
||||
* @param mapToCopy a Map to copy
|
||||
*/
|
||||
public MultiHashMap(Map mapToCopy) {
|
||||
// be careful of JDK 1.3 vs 1.4 differences
|
||||
super((int) (mapToCopy.size() * 1.4f));
|
||||
putAll(mapToCopy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the object during deserialization.
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
|
||||
// This method is needed because the 1.2/1.3 Java deserialisation called
|
||||
// put and thus messed up that method
|
||||
|
||||
// default read object
|
||||
s.defaultReadObject();
|
||||
|
||||
// problem only with jvm <1.4
|
||||
String version = "1.2";
|
||||
try {
|
||||
version = System.getProperty("java.version");
|
||||
} catch (SecurityException ex) {
|
||||
// ignore and treat as 1.2/1.3
|
||||
}
|
||||
|
||||
if (version.startsWith("1.2") || version.startsWith("1.3")) {
|
||||
for (Iterator iterator = entrySet().iterator(); iterator.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
// put has created a extra collection level, remove it
|
||||
super.put(entry.getKey(), ((Collection) entry.getValue()).iterator().next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the total size of the map by counting all the values.
|
||||
*
|
||||
* @return the total size of the map counting all values
|
||||
* @since Commons Collections 3.1
|
||||
*/
|
||||
public int totalSize() {
|
||||
int total = 0;
|
||||
Collection values = super.values();
|
||||
for (Iterator it = values.iterator(); it.hasNext();) {
|
||||
Collection coll = (Collection) it.next();
|
||||
total += coll.size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the collection mapped to the specified key.
|
||||
* This method is a convenience method to typecast the result of <code>get(key)</code>.
|
||||
*
|
||||
* @param key the key to retrieve
|
||||
* @return the collection mapped to the key, null if no mapping
|
||||
* @since Commons Collections 3.1
|
||||
*/
|
||||
public Collection getCollection(Object key) {
|
||||
return (Collection) get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the collection mapped to the specified key.
|
||||
*
|
||||
* @param key the key to get size for
|
||||
* @return the size of the collection at the key, zero if key not in map
|
||||
* @since Commons Collections 3.1
|
||||
*/
|
||||
public int size(Object key) {
|
||||
Collection coll = getCollection(key);
|
||||
if (coll == null) {
|
||||
return 0;
|
||||
}
|
||||
return coll.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an iterator for the collection mapped to the specified key.
|
||||
*
|
||||
* @param key the key to get an iterator for
|
||||
* @return the iterator of the collection at the key, empty iterator if key not in map
|
||||
* @since Commons Collections 3.1
|
||||
*/
|
||||
public Iterator iterator(Object key) {
|
||||
Collection coll = getCollection(key);
|
||||
if (coll == null) {
|
||||
return EmptyIterator.INSTANCE;
|
||||
}
|
||||
return coll.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the value to the collection associated with the specified key.
|
||||
* <p>
|
||||
* Unlike a normal <code>Map</code> the previous value is not replaced.
|
||||
* Instead the new value is added to the collection stored against the key.
|
||||
*
|
||||
* @param key the key to store against
|
||||
* @param value the value to add to the collection at the key
|
||||
* @return the value added if the map changed and null if the map did not change
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
// NOTE:: put is called during deserialization in JDK < 1.4 !!!!!!
|
||||
// so we must have a readObject()
|
||||
Collection coll = getCollection(key);
|
||||
if (coll == null) {
|
||||
coll = createCollection(null);
|
||||
super.put(key, coll);
|
||||
}
|
||||
boolean results = coll.add(value);
|
||||
return (results ? value : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override superclass to ensure that MultiMap instances are
|
||||
* correctly handled.
|
||||
* <p>
|
||||
* NOTE: Prior to version 3.2, putAll(map) did not work properly
|
||||
* when passed a MultiMap.
|
||||
*
|
||||
* @param map the map to copy (either a normal or multi map)
|
||||
*/
|
||||
public void putAll(Map map) {
|
||||
if (map instanceof MultiMap) {
|
||||
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
Collection coll = (Collection) entry.getValue();
|
||||
putAll(entry.getKey(), coll);
|
||||
}
|
||||
} else {
|
||||
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a collection of values to the collection associated with the specified key.
|
||||
*
|
||||
* @param key the key to store against
|
||||
* @param values the values to add to the collection at the key, null ignored
|
||||
* @return true if this map changed
|
||||
* @since Commons Collections 3.1
|
||||
*/
|
||||
public boolean putAll(Object key, Collection values) {
|
||||
if (values == null || values.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
Collection coll = getCollection(key);
|
||||
if (coll == null) {
|
||||
coll = createCollection(values);
|
||||
if (coll.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
super.put(key, coll);
|
||||
return true;
|
||||
} else {
|
||||
return coll.addAll(values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the map contains the value specified.
|
||||
* <p>
|
||||
* This checks all collections against all keys for the value, and thus could be slow.
|
||||
*
|
||||
* @param value the value to search for
|
||||
* @return true if the map contains the value
|
||||
*/
|
||||
public boolean containsValue(Object value) {
|
||||
Set pairs = super.entrySet();
|
||||
|
||||
if (pairs == null) {
|
||||
return false;
|
||||
}
|
||||
Iterator pairsIterator = pairs.iterator();
|
||||
while (pairsIterator.hasNext()) {
|
||||
Map.Entry keyValuePair = (Map.Entry) pairsIterator.next();
|
||||
Collection coll = (Collection) keyValuePair.getValue();
|
||||
if (coll.contains(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the collection at the specified key contains the value.
|
||||
*
|
||||
* @param value the value to search for
|
||||
* @return true if the map contains the value
|
||||
* @since Commons Collections 3.1
|
||||
*/
|
||||
public boolean containsValue(Object key, Object value) {
|
||||
Collection coll = getCollection(key);
|
||||
if (coll == null) {
|
||||
return false;
|
||||
}
|
||||
return coll.contains(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specific value from map.
|
||||
* <p>
|
||||
* The item is removed from the collection mapped to the specified key.
|
||||
* Other values attached to that key are unaffected.
|
||||
* <p>
|
||||
* If the last value for a key is removed, <code>null</code> will be returned
|
||||
* from a subsequant <code>get(key)</code>.
|
||||
*
|
||||
* @param key the key to remove from
|
||||
* @param item the value to remove
|
||||
* @return the value removed (which was passed in), null if nothing removed
|
||||
*/
|
||||
public Object remove(Object key, Object item) {
|
||||
Collection valuesForKey = getCollection(key);
|
||||
if (valuesForKey == null) {
|
||||
return null;
|
||||
}
|
||||
boolean removed = valuesForKey.remove(item);
|
||||
if (removed == false) {
|
||||
return null;
|
||||
}
|
||||
// remove the list if it is now empty
|
||||
// (saves space, and allows equals to work)
|
||||
if (valuesForKey.isEmpty()){
|
||||
remove(key);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the map.
|
||||
* <p>
|
||||
* This clears each collection in the map, and so may be slow.
|
||||
*/
|
||||
public void clear() {
|
||||
// For gc, clear each list in the map
|
||||
Set pairs = super.entrySet();
|
||||
Iterator pairsIterator = pairs.iterator();
|
||||
while (pairsIterator.hasNext()) {
|
||||
Map.Entry keyValuePair = (Map.Entry) pairsIterator.next();
|
||||
Collection coll = (Collection) keyValuePair.getValue();
|
||||
coll.clear();
|
||||
}
|
||||
super.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a collection containing all the values in the map.
|
||||
* <p>
|
||||
* This returns a collection containing the combination of values from all keys.
|
||||
*
|
||||
* @return a collection view of the values contained in this map
|
||||
*/
|
||||
public Collection values() {
|
||||
Collection vs = values;
|
||||
return (vs != null ? vs : (values = new Values()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the values iterator from the superclass, as used by inner class.
|
||||
*
|
||||
* @return iterator
|
||||
*/
|
||||
Iterator superValuesIterator() {
|
||||
return super.values().iterator();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Inner class to view the elements.
|
||||
*/
|
||||
private class Values extends AbstractCollection {
|
||||
|
||||
public Iterator iterator() {
|
||||
return new ValueIterator();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
int compt = 0;
|
||||
Iterator it = iterator();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
compt++;
|
||||
}
|
||||
return compt;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
MultiHashMap.this.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner iterator to view the elements.
|
||||
*/
|
||||
private class ValueIterator implements Iterator {
|
||||
private Iterator backedIterator;
|
||||
private Iterator tempIterator;
|
||||
|
||||
private ValueIterator() {
|
||||
backedIterator = MultiHashMap.this.superValuesIterator();
|
||||
}
|
||||
|
||||
private boolean searchNextIterator() {
|
||||
while (tempIterator == null || tempIterator.hasNext() == false) {
|
||||
if (backedIterator.hasNext() == false) {
|
||||
return false;
|
||||
}
|
||||
tempIterator = ((Collection) backedIterator.next()).iterator();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return searchNextIterator();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (searchNextIterator() == false) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return tempIterator.next();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (tempIterator == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
tempIterator.remove();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Clones the map creating an independent copy.
|
||||
* <p>
|
||||
* The clone will shallow clone the collections as well as the map.
|
||||
*
|
||||
* @return the cloned map
|
||||
*/
|
||||
public Object clone() {
|
||||
MultiHashMap cloned = (MultiHashMap) super.clone();
|
||||
|
||||
// clone each Collection container
|
||||
for (Iterator it = cloned.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
Collection coll = (Collection) entry.getValue();
|
||||
Collection newColl = createCollection(coll);
|
||||
entry.setValue(newColl);
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the map value Collection container.
|
||||
* <p>
|
||||
* This method can be overridden to use your own collection type.
|
||||
*
|
||||
* @param coll the collection to copy, may be null
|
||||
* @return the new collection
|
||||
*/
|
||||
protected Collection createCollection(Collection coll) {
|
||||
if (coll == null) {
|
||||
return new ArrayList();
|
||||
} else {
|
||||
return new ArrayList(coll);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,72 +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;
|
||||
|
||||
/**
|
||||
* Defines a collection for priority queues, which can insert, peek and pop.
|
||||
* <p>
|
||||
* This interface is now replaced by the <code>Buffer</code> interface.
|
||||
*
|
||||
* @deprecated Replaced by the Buffer interface and implementations in buffer subpackage.
|
||||
* Due to be removed in v4.0.
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Peter Donald
|
||||
*/
|
||||
public interface PriorityQueue {
|
||||
|
||||
/**
|
||||
* Clear all elements from queue.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Test if queue is empty.
|
||||
*
|
||||
* @return true if queue is empty else false.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Insert an element into queue.
|
||||
*
|
||||
* @param element the element to be inserted
|
||||
*
|
||||
* @throws ClassCastException if the specified <code>element</code>'s
|
||||
* type prevents it from being compared to other items in the queue to
|
||||
* determine its relative priority.
|
||||
*/
|
||||
void insert(Object element);
|
||||
|
||||
/**
|
||||
* Return element on top of heap but don't remove it.
|
||||
*
|
||||
* @return the element at top of heap
|
||||
* @throws java.util.NoSuchElementException if <code>isEmpty() == true</code>
|
||||
*/
|
||||
Object peek();
|
||||
|
||||
/**
|
||||
* Return element on top of heap and remove it.
|
||||
*
|
||||
* @return the element at top of heap
|
||||
* @throws java.util.NoSuchElementException if <code>isEmpty() == true</code>
|
||||
*/
|
||||
Object pop();
|
||||
|
||||
}
|
|
@ -1,163 +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.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>This <code>Map</code> wraps another <code>Map</code>
|
||||
* implementation, using the wrapped instance for its default
|
||||
* implementation. This class is used as a framework on which to
|
||||
* build to extensions for its wrapped <code>Map</code> object which
|
||||
* would be unavailable or inconvenient via sub-classing (but usable
|
||||
* via composition).</p>
|
||||
*
|
||||
* <p>This implementation does not perform any special processing with
|
||||
* {@link #entrySet()}, {@link #keySet()} or {@link #values()}. Instead
|
||||
* it simply returns the set/collection from the wrapped map. This may be
|
||||
* undesirable, for example if you are trying to write a validating
|
||||
* implementation it would provide a loophole around the validation. But,
|
||||
* you might want that loophole, so this class is kept simple.</p>
|
||||
*
|
||||
* @deprecated Moved to map subpackage as AbstractMapDecorator. It will be removed in v4.0.
|
||||
* @since Commons Collections 2.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Daniel Rall
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public abstract class ProxyMap implements Map {
|
||||
|
||||
/**
|
||||
* The <code>Map</code> to delegate to.
|
||||
*/
|
||||
protected Map map;
|
||||
|
||||
/**
|
||||
* Constructor that uses the specified map to delegate to.
|
||||
* <p>
|
||||
* Note that the map is used for delegation, and is not copied. This is
|
||||
* different to the normal use of a <code>Map</code> parameter in
|
||||
* collections constructors.
|
||||
*
|
||||
* @param map the <code>Map</code> to delegate to
|
||||
*/
|
||||
public ProxyMap(Map map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#clear()} method.
|
||||
*/
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#containsKey(Object)} method.
|
||||
*/
|
||||
public boolean containsKey(Object key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#containsValue(Object)} method.
|
||||
*/
|
||||
public boolean containsValue(Object value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#entrySet()} method.
|
||||
*/
|
||||
public Set entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#equals(Object)} method.
|
||||
*/
|
||||
public boolean equals(Object m) {
|
||||
return map.equals(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#get(Object)} method.
|
||||
*/
|
||||
public Object get(Object key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#hashCode()} method.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#isEmpty()} method.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#keySet()} method.
|
||||
*/
|
||||
public Set keySet() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#put(Object,Object)} method.
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#putAll(Map)} method.
|
||||
*/
|
||||
public void putAll(Map t) {
|
||||
map.putAll(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#remove(Object)} method.
|
||||
*/
|
||||
public Object remove(Object key) {
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#size()} method.
|
||||
*/
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link Map#values()} method.
|
||||
*/
|
||||
public Collection values() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,958 +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.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.collections.keyvalue.DefaultMapEntry;
|
||||
|
||||
/**
|
||||
* Hash-based {@link Map} implementation that allows
|
||||
* mappings to be removed by the garbage collector.<p>
|
||||
*
|
||||
* When you construct a <code>ReferenceMap</code>, you can
|
||||
* specify what kind of references are used to store the
|
||||
* map's keys and values. If non-hard references are
|
||||
* used, then the garbage collector can remove mappings
|
||||
* if a key or value becomes unreachable, or if the
|
||||
* JVM's memory is running low. For information on how
|
||||
* the different reference types behave, see
|
||||
* {@link Reference}.<p>
|
||||
*
|
||||
* Different types of references can be specified for keys
|
||||
* and values. The keys can be configured to be weak but
|
||||
* the values hard, in which case this class will behave
|
||||
* like a <a href="http://java.sun.com/j2se/1.4/docs/api/java/util/WeakHashMap.html">
|
||||
* <code>WeakHashMap</code></a>. However, you
|
||||
* can also specify hard keys and weak values, or any other
|
||||
* combination. The default constructor uses hard keys
|
||||
* and soft values, providing a memory-sensitive cache.<p>
|
||||
*
|
||||
* The algorithms used are basically the same as those
|
||||
* in {@link java.util.HashMap}. In particular, you
|
||||
* can specify a load factor and capacity to suit your
|
||||
* needs. All optional {@link Map} operations are
|
||||
* supported.<p>
|
||||
*
|
||||
* However, this {@link Map} implementation does <I>not</I>
|
||||
* allow null elements. Attempting to add a null key or
|
||||
* or a null value to the map will raise a
|
||||
* <code>NullPointerException</code>.<p>
|
||||
*
|
||||
* As usual, this implementation is not synchronized. You
|
||||
* can use {@link java.util.Collections#synchronizedMap} to
|
||||
* provide synchronized access to a <code>ReferenceMap</code>.
|
||||
*
|
||||
* @see java.lang.ref.Reference
|
||||
*
|
||||
* @deprecated Moved to map subpackage. Due to be removed in v4.0.
|
||||
* @since Commons Collections 2.1
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Paul Jack
|
||||
*/
|
||||
public class ReferenceMap extends AbstractMap {
|
||||
|
||||
/**
|
||||
* For serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = -3370601314380922368L;
|
||||
|
||||
|
||||
/**
|
||||
* Constant indicating that hard references should be used.
|
||||
*/
|
||||
final public static int HARD = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Constant indicating that soft references should be used.
|
||||
*/
|
||||
final public static int SOFT = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Constant indicating that weak references should be used.
|
||||
*/
|
||||
final public static int WEAK = 2;
|
||||
|
||||
|
||||
// --- serialized instance variables:
|
||||
|
||||
|
||||
/**
|
||||
* The reference type for keys. Must be HARD, SOFT, WEAK.
|
||||
* Note: I originally marked this field as final, but then this class
|
||||
* didn't compile under JDK1.2.2.
|
||||
* @serial
|
||||
*/
|
||||
private int keyType;
|
||||
|
||||
|
||||
/**
|
||||
* The reference type for values. Must be HARD, SOFT, WEAK.
|
||||
* Note: I originally marked this field as final, but then this class
|
||||
* didn't compile under JDK1.2.2.
|
||||
* @serial
|
||||
*/
|
||||
private int valueType;
|
||||
|
||||
|
||||
/**
|
||||
* The threshold variable is calculated by multiplying
|
||||
* table.length and loadFactor.
|
||||
* Note: I originally marked this field as final, but then this class
|
||||
* didn't compile under JDK1.2.2.
|
||||
* @serial
|
||||
*/
|
||||
private float loadFactor;
|
||||
|
||||
/**
|
||||
* Should the value be automatically purged when the associated key has been collected?
|
||||
*/
|
||||
private boolean purgeValues = false;
|
||||
|
||||
|
||||
// -- Non-serialized instance variables
|
||||
|
||||
/**
|
||||
* ReferenceQueue used to eliminate stale mappings.
|
||||
* See purge.
|
||||
*/
|
||||
private transient ReferenceQueue queue = new ReferenceQueue();
|
||||
|
||||
|
||||
/**
|
||||
* The hash table. Its length is always a power of two.
|
||||
*/
|
||||
private transient Entry[] table;
|
||||
|
||||
|
||||
/**
|
||||
* Number of mappings in this map.
|
||||
*/
|
||||
private transient int size;
|
||||
|
||||
|
||||
/**
|
||||
* When size reaches threshold, the map is resized.
|
||||
* See resize().
|
||||
*/
|
||||
private transient int threshold;
|
||||
|
||||
|
||||
/**
|
||||
* Number of times this map has been modified.
|
||||
*/
|
||||
private transient volatile int modCount;
|
||||
|
||||
|
||||
/**
|
||||
* Cached key set. May be null if key set is never accessed.
|
||||
*/
|
||||
private transient Set keySet;
|
||||
|
||||
|
||||
/**
|
||||
* Cached entry set. May be null if entry set is never accessed.
|
||||
*/
|
||||
private transient Set entrySet;
|
||||
|
||||
|
||||
/**
|
||||
* Cached values. May be null if values() is never accessed.
|
||||
*/
|
||||
private transient Collection values;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ReferenceMap</code> that will
|
||||
* use hard references to keys and soft references to values.
|
||||
*/
|
||||
public ReferenceMap() {
|
||||
this(HARD, SOFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ReferenceMap</code> that will
|
||||
* use the specified types of references.
|
||||
*
|
||||
* @param keyType the type of reference to use for keys;
|
||||
* must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
|
||||
* @param valueType the type of reference to use for values;
|
||||
* must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
|
||||
* @param purgeValues should the value be automatically purged when the
|
||||
* key is garbage collected
|
||||
*/
|
||||
public ReferenceMap(int keyType, int valueType, boolean purgeValues) {
|
||||
this(keyType, valueType);
|
||||
this.purgeValues = purgeValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ReferenceMap</code> that will
|
||||
* use the specified types of references.
|
||||
*
|
||||
* @param keyType the type of reference to use for keys;
|
||||
* must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
|
||||
* @param valueType the type of reference to use for values;
|
||||
* must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
|
||||
*/
|
||||
public ReferenceMap(int keyType, int valueType) {
|
||||
this(keyType, valueType, 16, 0.75f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ReferenceMap</code> with the
|
||||
* specified reference types, load factor and initial
|
||||
* capacity.
|
||||
*
|
||||
* @param keyType the type of reference to use for keys;
|
||||
* must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
|
||||
* @param valueType the type of reference to use for values;
|
||||
* must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
|
||||
* @param capacity the initial capacity for the map
|
||||
* @param loadFactor the load factor for the map
|
||||
* @param purgeValues should the value be automatically purged when the
|
||||
* key is garbage collected
|
||||
*/
|
||||
public ReferenceMap(
|
||||
int keyType,
|
||||
int valueType,
|
||||
int capacity,
|
||||
float loadFactor,
|
||||
boolean purgeValues) {
|
||||
this(keyType, valueType, capacity, loadFactor);
|
||||
this.purgeValues = purgeValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ReferenceMap</code> with the
|
||||
* specified reference types, load factor and initial
|
||||
* capacity.
|
||||
*
|
||||
* @param keyType the type of reference to use for keys;
|
||||
* must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
|
||||
* @param valueType the type of reference to use for values;
|
||||
* must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
|
||||
* @param capacity the initial capacity for the map
|
||||
* @param loadFactor the load factor for the map
|
||||
*/
|
||||
public ReferenceMap(int keyType, int valueType, int capacity, float loadFactor) {
|
||||
super();
|
||||
|
||||
verify("keyType", keyType);
|
||||
verify("valueType", valueType);
|
||||
|
||||
if (capacity <= 0) {
|
||||
throw new IllegalArgumentException("capacity must be positive");
|
||||
}
|
||||
if ((loadFactor <= 0.0f) || (loadFactor >= 1.0f)) {
|
||||
throw new IllegalArgumentException("Load factor must be greater than 0 and less than 1.");
|
||||
}
|
||||
|
||||
this.keyType = keyType;
|
||||
this.valueType = valueType;
|
||||
|
||||
int v = 1;
|
||||
while (v < capacity) v *= 2;
|
||||
|
||||
this.table = new Entry[v];
|
||||
this.loadFactor = loadFactor;
|
||||
this.threshold = (int)(v * loadFactor);
|
||||
}
|
||||
|
||||
|
||||
// used by constructor
|
||||
private static void verify(String name, int type) {
|
||||
if ((type < HARD) || (type > WEAK)) {
|
||||
throw new IllegalArgumentException(name +
|
||||
" must be HARD, SOFT, WEAK.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes this object to the given output stream.
|
||||
*
|
||||
* @param out the output stream to write to
|
||||
* @throws IOException if the stream raises it
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.defaultWriteObject();
|
||||
out.writeInt(table.length);
|
||||
|
||||
// Have to use null-terminated list because size might shrink
|
||||
// during iteration
|
||||
|
||||
for (Iterator iter = entrySet().iterator(); iter.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry)iter.next();
|
||||
out.writeObject(entry.getKey());
|
||||
out.writeObject(entry.getValue());
|
||||
}
|
||||
out.writeObject(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the contents of this object from the given input stream.
|
||||
*
|
||||
* @param inp the input stream to read from
|
||||
* @throws IOException if the stream raises it
|
||||
* @throws ClassNotFoundException if the stream raises it
|
||||
*/
|
||||
private void readObject(ObjectInputStream inp) throws IOException, ClassNotFoundException {
|
||||
inp.defaultReadObject();
|
||||
table = new Entry[inp.readInt()];
|
||||
threshold = (int)(table.length * loadFactor);
|
||||
queue = new ReferenceQueue();
|
||||
Object key = inp.readObject();
|
||||
while (key != null) {
|
||||
Object value = inp.readObject();
|
||||
put(key, value);
|
||||
key = inp.readObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a reference of the given type to the given
|
||||
* referent. The reference is registered with the queue
|
||||
* for later purging.
|
||||
*
|
||||
* @param type HARD, SOFT or WEAK
|
||||
* @param referent the object to refer to
|
||||
* @param hash the hash code of the <I>key</I> of the mapping;
|
||||
* this number might be different from referent.hashCode() if
|
||||
* the referent represents a value and not a key
|
||||
*/
|
||||
private Object toReference(int type, Object referent, int hash) {
|
||||
switch (type) {
|
||||
case HARD: return referent;
|
||||
case SOFT: return new SoftRef(hash, referent, queue);
|
||||
case WEAK: return new WeakRef(hash, referent, queue);
|
||||
default: throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the entry associated with the given key.
|
||||
*
|
||||
* @param key the key of the entry to look up
|
||||
* @return the entry associated with that key, or null
|
||||
* if the key is not in this map
|
||||
*/
|
||||
private Entry getEntry(Object key) {
|
||||
if (key == null) return null;
|
||||
int hash = key.hashCode();
|
||||
int index = indexFor(hash);
|
||||
for (Entry entry = table[index]; entry != null; entry = entry.next) {
|
||||
if ((entry.hash == hash) && key.equals(entry.getKey())) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts the given hash code into an index into the
|
||||
* hash table.
|
||||
*/
|
||||
private int indexFor(int hash) {
|
||||
// mix the bits to avoid bucket collisions...
|
||||
hash += ~(hash << 15);
|
||||
hash ^= (hash >>> 10);
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >>> 6);
|
||||
hash += ~(hash << 11);
|
||||
hash ^= (hash >>> 16);
|
||||
return hash & (table.length - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resizes this hash table by doubling its capacity.
|
||||
* This is an expensive operation, as entries must
|
||||
* be copied from the old smaller table to the new
|
||||
* bigger table.
|
||||
*/
|
||||
private void resize() {
|
||||
Entry[] old = table;
|
||||
table = new Entry[old.length * 2];
|
||||
|
||||
for (int i = 0; i < old.length; i++) {
|
||||
Entry next = old[i];
|
||||
while (next != null) {
|
||||
Entry entry = next;
|
||||
next = next.next;
|
||||
int index = indexFor(entry.hash);
|
||||
entry.next = table[index];
|
||||
table[index] = entry;
|
||||
}
|
||||
old[i] = null;
|
||||
}
|
||||
threshold = (int)(table.length * loadFactor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Purges stale mappings from this map.
|
||||
* <p>
|
||||
* Ordinarily, stale mappings are only removed during
|
||||
* a write operation, although this method is called for both
|
||||
* read and write operations to maintain a consistent state.
|
||||
* <p>
|
||||
* Note that this method is not synchronized! Special
|
||||
* care must be taken if, for instance, you want stale
|
||||
* mappings to be removed on a periodic basis by some
|
||||
* background thread.
|
||||
*/
|
||||
private void purge() {
|
||||
Reference ref = queue.poll();
|
||||
while (ref != null) {
|
||||
purge(ref);
|
||||
ref = queue.poll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void purge(Reference ref) {
|
||||
// The hashCode of the reference is the hashCode of the
|
||||
// mapping key, even if the reference refers to the
|
||||
// mapping value...
|
||||
int hash = ref.hashCode();
|
||||
int index = indexFor(hash);
|
||||
Entry previous = null;
|
||||
Entry entry = table[index];
|
||||
while (entry != null) {
|
||||
if (entry.purge(ref)) {
|
||||
if (previous == null) table[index] = entry.next;
|
||||
else previous.next = entry.next;
|
||||
this.size--;
|
||||
return;
|
||||
}
|
||||
previous = entry;
|
||||
entry = entry.next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the size of this map.
|
||||
*
|
||||
* @return the size of this map
|
||||
*/
|
||||
public int size() {
|
||||
purge();
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this map is empty.
|
||||
*
|
||||
* @return <code>true</code> if this map is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
purge();
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this map contains the given key.
|
||||
*
|
||||
* @return true if the given key is in this map
|
||||
*/
|
||||
public boolean containsKey(Object key) {
|
||||
purge();
|
||||
Entry entry = getEntry(key);
|
||||
if (entry == null) return false;
|
||||
return entry.getValue() != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value associated with the given key, if any.
|
||||
*
|
||||
* @return the value associated with the given key, or <code>null</code>
|
||||
* if the key maps to no value
|
||||
*/
|
||||
public Object get(Object key) {
|
||||
purge();
|
||||
Entry entry = getEntry(key);
|
||||
if (entry == null) return null;
|
||||
return entry.getValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Associates the given key with the given value.<p>
|
||||
* Neither the key nor the value may be null.
|
||||
*
|
||||
* @param key the key of the mapping
|
||||
* @param value the value of the mapping
|
||||
* @return the last value associated with that key, or
|
||||
* null if no value was associated with the key
|
||||
* @throws NullPointerException if either the key or value
|
||||
* is null
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
if (key == null) throw new NullPointerException("null keys not allowed");
|
||||
if (value == null) throw new NullPointerException("null values not allowed");
|
||||
|
||||
purge();
|
||||
if (size + 1 > threshold) resize();
|
||||
|
||||
int hash = key.hashCode();
|
||||
int index = indexFor(hash);
|
||||
Entry entry = table[index];
|
||||
while (entry != null) {
|
||||
if ((hash == entry.hash) && key.equals(entry.getKey())) {
|
||||
Object result = entry.getValue();
|
||||
entry.setValue(value);
|
||||
return result;
|
||||
}
|
||||
entry = entry.next;
|
||||
}
|
||||
this.size++;
|
||||
modCount++;
|
||||
key = toReference(keyType, key, hash);
|
||||
value = toReference(valueType, value, hash);
|
||||
table[index] = new Entry(key, hash, value, table[index]);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the key and its associated value from this map.
|
||||
*
|
||||
* @param key the key to remove
|
||||
* @return the value associated with that key, or null if
|
||||
* the key was not in the map
|
||||
*/
|
||||
public Object remove(Object key) {
|
||||
if (key == null) return null;
|
||||
purge();
|
||||
int hash = key.hashCode();
|
||||
int index = indexFor(hash);
|
||||
Entry previous = null;
|
||||
Entry entry = table[index];
|
||||
while (entry != null) {
|
||||
if ((hash == entry.hash) && key.equals(entry.getKey())) {
|
||||
if (previous == null) table[index] = entry.next;
|
||||
else previous.next = entry.next;
|
||||
this.size--;
|
||||
modCount++;
|
||||
return entry.getValue();
|
||||
}
|
||||
previous = entry;
|
||||
entry = entry.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears this map.
|
||||
*/
|
||||
public void clear() {
|
||||
Arrays.fill(table, null);
|
||||
size = 0;
|
||||
while (queue.poll() != null); // drain the queue
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a set view of this map's entries.
|
||||
*
|
||||
* @return a set view of this map's entries
|
||||
*/
|
||||
public Set entrySet() {
|
||||
if (entrySet != null) {
|
||||
return entrySet;
|
||||
}
|
||||
entrySet = new AbstractSet() {
|
||||
public int size() {
|
||||
return ReferenceMap.this.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
ReferenceMap.this.clear();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
if (o == null) return false;
|
||||
if (!(o instanceof Map.Entry)) return false;
|
||||
Map.Entry e = (Map.Entry)o;
|
||||
Entry e2 = getEntry(e.getKey());
|
||||
return (e2 != null) && e.equals(e2);
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
boolean r = contains(o);
|
||||
if (r) {
|
||||
Map.Entry e = (Map.Entry)o;
|
||||
ReferenceMap.this.remove(e.getKey());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new EntryIterator();
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return toArray(new Object[0]);
|
||||
}
|
||||
|
||||
public Object[] toArray(Object[] arr) {
|
||||
ArrayList list = new ArrayList();
|
||||
Iterator iterator = iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Entry e = (Entry)iterator.next();
|
||||
list.add(new DefaultMapEntry(e.getKey(), e.getValue()));
|
||||
}
|
||||
return list.toArray(arr);
|
||||
}
|
||||
};
|
||||
return entrySet;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a set view of this map's keys.
|
||||
*
|
||||
* @return a set view of this map's keys
|
||||
*/
|
||||
public Set keySet() {
|
||||
if (keySet != null) return keySet;
|
||||
keySet = new AbstractSet() {
|
||||
public int size() {
|
||||
return ReferenceMap.this.size();
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new KeyIterator();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return containsKey(o);
|
||||
}
|
||||
|
||||
|
||||
public boolean remove(Object o) {
|
||||
Object r = ReferenceMap.this.remove(o);
|
||||
return r != null;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
ReferenceMap.this.clear();
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return toArray(new Object[0]);
|
||||
}
|
||||
|
||||
public Object[] toArray(Object[] array) {
|
||||
Collection c = new ArrayList(size());
|
||||
for (Iterator it = iterator(); it.hasNext(); ) {
|
||||
c.add(it.next());
|
||||
}
|
||||
return c.toArray(array);
|
||||
}
|
||||
};
|
||||
return keySet;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a collection view of this map's values.
|
||||
*
|
||||
* @return a collection view of this map's values.
|
||||
*/
|
||||
public Collection values() {
|
||||
if (values != null) return values;
|
||||
values = new AbstractCollection() {
|
||||
public int size() {
|
||||
return ReferenceMap.this.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
ReferenceMap.this.clear();
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new ValueIterator();
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return toArray(new Object[0]);
|
||||
}
|
||||
|
||||
public Object[] toArray(Object[] array) {
|
||||
Collection c = new ArrayList(size());
|
||||
for (Iterator it = iterator(); it.hasNext(); ) {
|
||||
c.add(it.next());
|
||||
}
|
||||
return c.toArray(array);
|
||||
}
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
// If getKey() or getValue() returns null, it means
|
||||
// the mapping is stale and should be removed.
|
||||
private class Entry implements Map.Entry, KeyValue {
|
||||
|
||||
Object key;
|
||||
Object value;
|
||||
int hash;
|
||||
Entry next;
|
||||
|
||||
|
||||
public Entry(Object key, int hash, Object value, Entry next) {
|
||||
this.key = key;
|
||||
this.hash = hash;
|
||||
this.value = value;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
|
||||
public Object getKey() {
|
||||
return (keyType > HARD) ? ((Reference)key).get() : key;
|
||||
}
|
||||
|
||||
|
||||
public Object getValue() {
|
||||
return (valueType > HARD) ? ((Reference)value).get() : value;
|
||||
}
|
||||
|
||||
|
||||
public Object setValue(Object object) {
|
||||
Object old = getValue();
|
||||
if (valueType > HARD) ((Reference)value).clear();
|
||||
value = toReference(valueType, object, hash);
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null) return false;
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof Map.Entry)) return false;
|
||||
|
||||
Map.Entry entry = (Map.Entry)o;
|
||||
Object key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if ((key == null) || (value == null)) return false;
|
||||
return key.equals(getKey()) && value.equals(getValue());
|
||||
}
|
||||
|
||||
|
||||
public int hashCode() {
|
||||
Object v = getValue();
|
||||
return hash ^ ((v == null) ? 0 : v.hashCode());
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return getKey() + "=" + getValue();
|
||||
}
|
||||
|
||||
|
||||
boolean purge(Reference ref) {
|
||||
boolean r = (keyType > HARD) && (key == ref);
|
||||
r = r || ((valueType > HARD) && (value == ref));
|
||||
if (r) {
|
||||
if (keyType > HARD) ((Reference)key).clear();
|
||||
if (valueType > HARD) {
|
||||
((Reference)value).clear();
|
||||
} else if (purgeValues) {
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class EntryIterator implements Iterator {
|
||||
// These fields keep track of where we are in the table.
|
||||
int index;
|
||||
Entry entry;
|
||||
Entry previous;
|
||||
|
||||
// These Object fields provide hard references to the
|
||||
// current and next entry; this assures that if hasNext()
|
||||
// returns true, next() will actually return a valid element.
|
||||
Object nextKey, nextValue;
|
||||
Object currentKey, currentValue;
|
||||
|
||||
int expectedModCount;
|
||||
|
||||
|
||||
public EntryIterator() {
|
||||
index = (size() != 0 ? table.length : 0);
|
||||
// have to do this here! size() invocation above
|
||||
// may have altered the modCount.
|
||||
expectedModCount = modCount;
|
||||
}
|
||||
|
||||
|
||||
public boolean hasNext() {
|
||||
checkMod();
|
||||
while (nextNull()) {
|
||||
Entry e = entry;
|
||||
int i = index;
|
||||
while ((e == null) && (i > 0)) {
|
||||
i--;
|
||||
e = table[i];
|
||||
}
|
||||
entry = e;
|
||||
index = i;
|
||||
if (e == null) {
|
||||
currentKey = null;
|
||||
currentValue = null;
|
||||
return false;
|
||||
}
|
||||
nextKey = e.getKey();
|
||||
nextValue = e.getValue();
|
||||
if (nextNull()) entry = entry.next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void checkMod() {
|
||||
if (modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean nextNull() {
|
||||
return (nextKey == null) || (nextValue == null);
|
||||
}
|
||||
|
||||
protected Entry nextEntry() {
|
||||
checkMod();
|
||||
if (nextNull() && !hasNext()) throw new NoSuchElementException();
|
||||
previous = entry;
|
||||
entry = entry.next;
|
||||
currentKey = nextKey;
|
||||
currentValue = nextValue;
|
||||
nextKey = null;
|
||||
nextValue = null;
|
||||
return previous;
|
||||
}
|
||||
|
||||
|
||||
public Object next() {
|
||||
return nextEntry();
|
||||
}
|
||||
|
||||
|
||||
public void remove() {
|
||||
checkMod();
|
||||
if (previous == null) throw new IllegalStateException();
|
||||
ReferenceMap.this.remove(currentKey);
|
||||
previous = null;
|
||||
currentKey = null;
|
||||
currentValue = null;
|
||||
expectedModCount = modCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class ValueIterator extends EntryIterator {
|
||||
public Object next() {
|
||||
return nextEntry().getValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class KeyIterator extends EntryIterator {
|
||||
public Object next() {
|
||||
return nextEntry().getKey();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// These two classes store the hashCode of the key of
|
||||
// of the mapping, so that after they're dequeued a quick
|
||||
// lookup of the bucket in the table can occur.
|
||||
|
||||
|
||||
private static class SoftRef extends SoftReference {
|
||||
private int hash;
|
||||
|
||||
|
||||
public SoftRef(int hash, Object r, ReferenceQueue q) {
|
||||
super(r, q);
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class WeakRef extends WeakReference {
|
||||
private int hash;
|
||||
|
||||
|
||||
public WeakRef(int hash, Object r, ReferenceQueue q) {
|
||||
super(r, q);
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,711 +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.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A StaticBucketMap is an efficient, thread-safe implementation of
|
||||
* <code>java.util.Map</code> that performs well in in a highly
|
||||
* thread-contentious environment. The map supports very efficient
|
||||
* {@link #get(Object) get}, {@link #put(Object,Object) put},
|
||||
* {@link #remove(Object) remove} and {@link #containsKey(Object) containsKey}
|
||||
* operations, assuming (approximate) uniform hashing and
|
||||
* that the number of entries does not exceed the number of buckets. If the
|
||||
* number of entries exceeds the number of buckets or if the hash codes of the
|
||||
* objects are not uniformly distributed, these operations have a worst case
|
||||
* scenario that is proportional to the number of elements in the map
|
||||
* (<i>O(n)</i>).<p>
|
||||
*
|
||||
* Each bucket in the hash table has its own monitor, so two threads can
|
||||
* safely operate on the map at the same time, often without incurring any
|
||||
* monitor contention. This means that you don't have to wrap instances
|
||||
* of this class with {@link java.util.Collections#synchronizedMap(Map)};
|
||||
* instances are already thread-safe. Unfortunately, however, this means
|
||||
* that this map implementation behaves in ways you may find disconcerting.
|
||||
* Bulk operations, such as {@link #putAll(Map) putAll} or the
|
||||
* {@link Collection#retainAll(Collection) retainAll} operation in collection
|
||||
* views, are <i>not</i> atomic. If two threads are simultaneously
|
||||
* executing
|
||||
*
|
||||
* <pre>
|
||||
* staticBucketMapInstance.putAll(map);
|
||||
* </pre>
|
||||
*
|
||||
* and
|
||||
*
|
||||
* <pre>
|
||||
* staticBucketMapInstance.entrySet().removeAll(map.entrySet());
|
||||
* </pre>
|
||||
*
|
||||
* then the results are generally random. Those two statement could cancel
|
||||
* each other out, leaving <code>staticBucketMapInstance</code> essentially
|
||||
* unchanged, or they could leave some random subset of <code>map</code> in
|
||||
* <code>staticBucketMapInstance</code>.<p>
|
||||
*
|
||||
* Also, much like an encyclopedia, the results of {@link #size()} and
|
||||
* {@link #isEmpty()} are out-of-date as soon as they are produced.<p>
|
||||
*
|
||||
* The iterators returned by the collection views of this class are <i>not</i>
|
||||
* fail-fast. They will <i>never</i> raise a
|
||||
* {@link java.util.ConcurrentModificationException}. Keys and values
|
||||
* added to the map after the iterator is created do not necessarily appear
|
||||
* during iteration. Similarly, the iterator does not necessarily fail to
|
||||
* return keys and values that were removed after the iterator was created.<p>
|
||||
*
|
||||
* Finally, unlike {@link java.util.HashMap}-style implementations, this
|
||||
* class <i>never</i> rehashes the map. The number of buckets is fixed
|
||||
* at construction time and never altered. Performance may degrade if
|
||||
* you do not allocate enough buckets upfront.<p>
|
||||
*
|
||||
* The {@link #atomic(Runnable)} method is provided to allow atomic iterations
|
||||
* and bulk operations; however, overuse of {@link #atomic(Runnable) atomic}
|
||||
* will basically result in a map that's slower than an ordinary synchronized
|
||||
* {@link java.util.HashMap}.
|
||||
*
|
||||
* Use this class if you do not require reliable bulk operations and
|
||||
* iterations, or if you can make your own guarantees about how bulk
|
||||
* operations will affect the map.<p>
|
||||
*
|
||||
* @deprecated Moved to map subpackage. Due to be removed in v4.0.
|
||||
* @since Commons Collections 2.1
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
|
||||
* @author <a href="mailto:g-froehlich@gmx.de">Gerhard Froehlich</a>
|
||||
* @author <a href="mailto:mas@apache.org">Michael A. Smith</a>
|
||||
* @author Paul Jack
|
||||
* @author Leo Sutic
|
||||
* @author Janek Bogucki
|
||||
* @author Kazuya Ujihara
|
||||
*/
|
||||
public final class StaticBucketMap implements Map {
|
||||
|
||||
private static final int DEFAULT_BUCKETS = 255;
|
||||
private Node[] m_buckets;
|
||||
private Lock[] m_locks;
|
||||
|
||||
/**
|
||||
* Initializes the map with the default number of buckets (255).
|
||||
*/
|
||||
public StaticBucketMap()
|
||||
{
|
||||
this( DEFAULT_BUCKETS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the map with a specified number of buckets. The number
|
||||
* of buckets is never below 17, and is always an odd number (StaticBucketMap
|
||||
* ensures this). The number of buckets is inversely proportional to the
|
||||
* chances for thread contention. The fewer buckets, the more chances for
|
||||
* thread contention. The more buckets the fewer chances for thread
|
||||
* contention.
|
||||
*
|
||||
* @param numBuckets the number of buckets for this map
|
||||
*/
|
||||
public StaticBucketMap( int numBuckets )
|
||||
{
|
||||
int size = Math.max( 17, numBuckets );
|
||||
|
||||
// Ensure that bucketSize is never a power of 2 (to ensure maximal distribution)
|
||||
if( size % 2 == 0 )
|
||||
{
|
||||
size--;
|
||||
}
|
||||
|
||||
m_buckets = new Node[ size ];
|
||||
m_locks = new Lock[ size ];
|
||||
|
||||
for( int i = 0; i < size; i++ )
|
||||
{
|
||||
m_locks[ i ] = new Lock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the exact hash entry for the key. The hash algorithm
|
||||
* is rather simplistic, but it does the job:
|
||||
*
|
||||
* <pre>
|
||||
* He = |Hk mod n|
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* He is the entry's hashCode, Hk is the key's hashCode, and n is
|
||||
* the number of buckets.
|
||||
* </p>
|
||||
*/
|
||||
private final int getHash( Object key )
|
||||
{
|
||||
if( key == null ) return 0;
|
||||
int hash = key.hashCode();
|
||||
hash += ~(hash << 15);
|
||||
hash ^= (hash >>> 10);
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >>> 6);
|
||||
hash += ~(hash << 11);
|
||||
hash ^= (hash >>> 16);
|
||||
hash %= m_buckets.length;
|
||||
return ( hash < 0 ) ? hash * -1 : hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#keySet()}.
|
||||
*/
|
||||
public Set keySet()
|
||||
{
|
||||
return new KeySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#size()}.
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
for( int i = 0; i < m_buckets.length; i++ )
|
||||
{
|
||||
cnt += m_locks[i].size;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#put(Object, Object)}.
|
||||
*/
|
||||
public Object put( final Object key, final Object value )
|
||||
{
|
||||
int hash = getHash( key );
|
||||
|
||||
synchronized( m_locks[ hash ] )
|
||||
{
|
||||
Node n = m_buckets[ hash ];
|
||||
|
||||
if( n == null )
|
||||
{
|
||||
n = new Node();
|
||||
n.key = key;
|
||||
n.value = value;
|
||||
m_buckets[ hash ] = n;
|
||||
m_locks[hash].size++;
|
||||
return null;
|
||||
}
|
||||
|
||||
// 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
|
||||
// the old value.
|
||||
for( Node next = n; next != null; next = next.next )
|
||||
{
|
||||
n = next;
|
||||
|
||||
if( n.key == key || ( n.key != null && n.key.equals( key ) ) )
|
||||
{
|
||||
Object returnVal = n.value;
|
||||
n.value = value;
|
||||
return returnVal;
|
||||
}
|
||||
}
|
||||
|
||||
// The key was not found in the current list of nodes, add it to the end
|
||||
// in a new node.
|
||||
Node newNode = new Node();
|
||||
newNode.key = key;
|
||||
newNode.value = value;
|
||||
n.next = newNode;
|
||||
m_locks[hash].size++;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#get(Object)}.
|
||||
*/
|
||||
public Object get( final Object key )
|
||||
{
|
||||
int hash = getHash( key );
|
||||
|
||||
synchronized( m_locks[ hash ] )
|
||||
{
|
||||
Node n = m_buckets[ hash ];
|
||||
|
||||
while( n != null )
|
||||
{
|
||||
if( n.key == key || ( n.key != null && n.key.equals( key ) ) )
|
||||
{
|
||||
return n.value;
|
||||
}
|
||||
|
||||
n = n.next;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#containsKey(Object)}.
|
||||
*/
|
||||
public boolean containsKey( final Object key )
|
||||
{
|
||||
int hash = getHash( key );
|
||||
|
||||
synchronized( m_locks[ hash ] )
|
||||
{
|
||||
Node n = m_buckets[ hash ];
|
||||
|
||||
while( n != null )
|
||||
{
|
||||
if( n.key == key || ( n.key != null && n.key.equals( key ) ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
n = n.next;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#containsValue(Object)}.
|
||||
*/
|
||||
public boolean containsValue( final Object value )
|
||||
{
|
||||
for( int i = 0; i < m_buckets.length; i++ )
|
||||
{
|
||||
synchronized( m_locks[ i ] )
|
||||
{
|
||||
Node n = m_buckets[ i ];
|
||||
|
||||
while( n != null )
|
||||
{
|
||||
if( n.value == value ||
|
||||
(n.value != null && n.value.equals( value ) ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
n = n.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#values()}.
|
||||
*/
|
||||
public Collection values()
|
||||
{
|
||||
return new Values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#entrySet()}.
|
||||
*/
|
||||
public Set entrySet()
|
||||
{
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#putAll(Map)}.
|
||||
*/
|
||||
public void putAll( Map other )
|
||||
{
|
||||
Iterator i = other.keySet().iterator();
|
||||
|
||||
while( i.hasNext() )
|
||||
{
|
||||
Object key = i.next();
|
||||
put( key, other.get( key ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#remove(Object)}.
|
||||
*/
|
||||
public Object remove( Object key )
|
||||
{
|
||||
int hash = getHash( key );
|
||||
|
||||
synchronized( m_locks[ hash ] )
|
||||
{
|
||||
Node n = m_buckets[ hash ];
|
||||
Node prev = null;
|
||||
|
||||
while( n != null )
|
||||
{
|
||||
if( n.key == key || ( n.key != null && n.key.equals( key ) ) )
|
||||
{
|
||||
// Remove this node from the linked list of nodes.
|
||||
if( null == prev )
|
||||
{
|
||||
// This node was the head, set the next node to be the new head.
|
||||
m_buckets[ hash ] = n.next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the next node of the previous node to be the node after this one.
|
||||
prev.next = n.next;
|
||||
}
|
||||
m_locks[hash].size--;
|
||||
return n.value;
|
||||
}
|
||||
|
||||
prev = n;
|
||||
n = n.next;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#isEmpty()}.
|
||||
*/
|
||||
public final boolean isEmpty()
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#clear()}.
|
||||
*/
|
||||
public final void clear()
|
||||
{
|
||||
for( int i = 0; i < m_buckets.length; i++ )
|
||||
{
|
||||
Lock lock = m_locks[i];
|
||||
synchronized (lock) {
|
||||
m_buckets[ i ] = null;
|
||||
lock.size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#equals(Object)}.
|
||||
*/
|
||||
public final boolean equals( Object obj )
|
||||
{
|
||||
if( obj == null ) return false;
|
||||
if( obj == this ) return true;
|
||||
|
||||
if( !( obj instanceof Map ) ) return false;
|
||||
|
||||
Map other = (Map)obj;
|
||||
|
||||
return entrySet().equals(other.entrySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link Map#hashCode()}.
|
||||
*/
|
||||
public final int hashCode()
|
||||
{
|
||||
int hashCode = 0;
|
||||
|
||||
for( int i = 0; i < m_buckets.length; i++ )
|
||||
{
|
||||
synchronized( m_locks[ i ] )
|
||||
{
|
||||
Node n = m_buckets[ i ];
|
||||
|
||||
while( n != null )
|
||||
{
|
||||
hashCode += n.hashCode();
|
||||
n = n.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Map.Entry for the StaticBucketMap.
|
||||
*/
|
||||
private static final class Node implements Map.Entry, KeyValue
|
||||
{
|
||||
protected Object key;
|
||||
protected Object value;
|
||||
protected Node next;
|
||||
|
||||
public Object getKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
public Object getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return ( ( key == null ? 0 : key.hashCode() ) ^
|
||||
( value == null ? 0 : value.hashCode() ) );
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if( o == null ) return false;
|
||||
if( o == this ) return true;
|
||||
|
||||
if ( ! (o instanceof Map.Entry ) )
|
||||
return false;
|
||||
|
||||
Map.Entry e2 = (Map.Entry)o;
|
||||
|
||||
return ((key == null ?
|
||||
e2.getKey() == null : key.equals(e2.getKey())) &&
|
||||
(value == null ?
|
||||
e2.getValue() == null : value.equals(e2.getValue())));
|
||||
}
|
||||
|
||||
public Object setValue( Object val )
|
||||
{
|
||||
Object retVal = value;
|
||||
value = val;
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
private final static class Lock {
|
||||
|
||||
public int size;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class EntryIterator implements Iterator {
|
||||
|
||||
private ArrayList current = new ArrayList();
|
||||
private int bucket;
|
||||
private Map.Entry last;
|
||||
|
||||
|
||||
public boolean hasNext() {
|
||||
if (current.size() > 0) return true;
|
||||
while (bucket < m_buckets.length) {
|
||||
synchronized (m_locks[bucket]) {
|
||||
Node n = m_buckets[bucket];
|
||||
while (n != null) {
|
||||
current.add(n);
|
||||
n = n.next;
|
||||
}
|
||||
bucket++;
|
||||
if (current.size() > 0) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Map.Entry nextEntry() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
last = (Map.Entry)current.remove(current.size() - 1);
|
||||
return last;
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
return nextEntry();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (last == null) throw new IllegalStateException();
|
||||
StaticBucketMap.this.remove(last.getKey());
|
||||
last = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ValueIterator extends EntryIterator {
|
||||
|
||||
public Object next() {
|
||||
return nextEntry().getValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class KeyIterator extends EntryIterator {
|
||||
|
||||
public Object next() {
|
||||
return nextEntry().getKey();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class EntrySet extends AbstractSet {
|
||||
|
||||
public int size() {
|
||||
return StaticBucketMap.this.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
StaticBucketMap.this.clear();
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new EntryIterator();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
Map.Entry entry = (Map.Entry)o;
|
||||
int hash = getHash(entry.getKey());
|
||||
synchronized (m_locks[hash]) {
|
||||
for (Node n = m_buckets[hash]; n != null; n = n.next) {
|
||||
if (n.equals(entry)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean remove(Object obj) {
|
||||
if (obj instanceof Map.Entry == false) {
|
||||
return false;
|
||||
}
|
||||
Map.Entry entry = (Map.Entry) obj;
|
||||
int hash = getHash(entry.getKey());
|
||||
synchronized (m_locks[hash]) {
|
||||
for (Node n = m_buckets[hash]; n != null; n = n.next) {
|
||||
if (n.equals(entry)) {
|
||||
StaticBucketMap.this.remove(n.getKey());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class KeySet extends AbstractSet {
|
||||
|
||||
public int size() {
|
||||
return StaticBucketMap.this.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
StaticBucketMap.this.clear();
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new KeyIterator();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return StaticBucketMap.this.containsKey(o);
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
int hash = getHash(o);
|
||||
synchronized (m_locks[hash]) {
|
||||
for (Node n = m_buckets[hash]; n != null; n = n.next) {
|
||||
Object k = n.getKey();
|
||||
if ((k == o) || ((k != null) && k.equals(o))) {
|
||||
StaticBucketMap.this.remove(k);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class Values extends AbstractCollection {
|
||||
|
||||
public int size() {
|
||||
return StaticBucketMap.this.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
StaticBucketMap.this.clear();
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new ValueIterator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prevents any operations from occurring on this map while the
|
||||
* given {@link Runnable} executes. This method can be used, for
|
||||
* instance, to execute a bulk operation atomically:
|
||||
*
|
||||
* <pre>
|
||||
* staticBucketMapInstance.atomic(new Runnable() {
|
||||
* public void run() {
|
||||
* staticBucketMapInstance.putAll(map);
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* It can also be used if you need a reliable iterator:
|
||||
*
|
||||
* <pre>
|
||||
* staticBucketMapInstance.atomic(new Runnable() {
|
||||
* public void run() {
|
||||
* Iterator iterator = staticBucketMapInstance.iterator();
|
||||
* while (iterator.hasNext()) {
|
||||
* foo(iterator.next();
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* <B>Implementation note:</B> This method requires a lot of time
|
||||
* and a ton of stack space. Essentially a recursive algorithm is used
|
||||
* to enter each bucket's monitor. If you have twenty thousand buckets
|
||||
* in your map, then the recursive method will be invoked twenty thousand
|
||||
* times. You have been warned.
|
||||
*
|
||||
* @param r the code to execute atomically
|
||||
*/
|
||||
public void atomic(Runnable r) {
|
||||
if (r == null) throw new NullPointerException();
|
||||
atomic(r, 0);
|
||||
}
|
||||
|
||||
private void atomic(Runnable r, int bucket) {
|
||||
if (bucket >= m_buckets.length) {
|
||||
r.run();
|
||||
return;
|
||||
}
|
||||
synchronized (m_locks[bucket]) {
|
||||
atomic(r, bucket + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,103 +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.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* A thread safe version of the PriorityQueue.
|
||||
* Provides synchronized wrapper methods for all the methods
|
||||
* defined in the PriorityQueue interface.
|
||||
*
|
||||
* @deprecated PriorityQueue is replaced by the Buffer interface, see buffer subpackage.
|
||||
* Due to be removed in v4.0.
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Ram Chidambaram
|
||||
*/
|
||||
public final class SynchronizedPriorityQueue implements PriorityQueue {
|
||||
|
||||
/**
|
||||
* The underlying priority queue.
|
||||
*/
|
||||
protected final PriorityQueue m_priorityQueue;
|
||||
|
||||
/**
|
||||
* Constructs a new synchronized priority queue.
|
||||
*
|
||||
* @param priorityQueue the priority queue to synchronize
|
||||
*/
|
||||
public SynchronizedPriorityQueue(final PriorityQueue priorityQueue) {
|
||||
m_priorityQueue = priorityQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all elements from queue.
|
||||
*/
|
||||
public synchronized void clear() {
|
||||
m_priorityQueue.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if queue is empty.
|
||||
*
|
||||
* @return true if queue is empty else false.
|
||||
*/
|
||||
public synchronized boolean isEmpty() {
|
||||
return m_priorityQueue.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an element into queue.
|
||||
*
|
||||
* @param element the element to be inserted
|
||||
*/
|
||||
public synchronized void insert(final Object element) {
|
||||
m_priorityQueue.insert(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return element on top of heap but don't remove it.
|
||||
*
|
||||
* @return the element at top of heap
|
||||
* @throws NoSuchElementException if isEmpty() == true
|
||||
*/
|
||||
public synchronized Object peek() throws NoSuchElementException {
|
||||
return m_priorityQueue.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return element on top of heap and remove it.
|
||||
*
|
||||
* @return the element at top of heap
|
||||
* @throws NoSuchElementException if isEmpty() == true
|
||||
*/
|
||||
public synchronized Object pop() throws NoSuchElementException {
|
||||
return m_priorityQueue.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the underlying queue.
|
||||
*
|
||||
* @return a string representation of the underlying queue
|
||||
*/
|
||||
public synchronized String toString() {
|
||||
return m_priorityQueue.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,77 +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.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* A {@link Bag} that is backed by a {@link TreeMap}.
|
||||
* Order will be maintained among the unique representative
|
||||
* members.
|
||||
*
|
||||
* @deprecated Moved to bag subpackage and rewritten internally. Due to be removed in v4.0.
|
||||
* @since Commons Collections 2.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Chuck Burdick
|
||||
*/
|
||||
public class TreeBag extends DefaultMapBag implements SortedBag {
|
||||
|
||||
/**
|
||||
* Constructs an empty <code>TreeBag</code>.
|
||||
*/
|
||||
public TreeBag() {
|
||||
super(new TreeMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@link Bag} that maintains order on its unique
|
||||
* representative members according to the given {@link Comparator}.
|
||||
*
|
||||
* @param comparator the comparator to use
|
||||
*/
|
||||
public TreeBag(Comparator comparator) {
|
||||
super(new TreeMap(comparator));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link Bag} containing all the members of the given
|
||||
* collection.
|
||||
*
|
||||
* @param coll the collection to copy into the bag
|
||||
*/
|
||||
public TreeBag(Collection coll) {
|
||||
this();
|
||||
addAll(coll);
|
||||
}
|
||||
|
||||
public Object first() {
|
||||
return ((SortedMap) getMap()).firstKey();
|
||||
}
|
||||
|
||||
public Object last() {
|
||||
return ((SortedMap) getMap()).lastKey();
|
||||
}
|
||||
|
||||
public Comparator comparator() {
|
||||
return ((SortedMap) getMap()).comparator();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,274 +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.AbstractCollection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* UnboundedFifoBuffer is a very efficient buffer implementation.
|
||||
* According to performance testing, it exhibits a constant access time, but it
|
||||
* also outperforms ArrayList when used for the same purpose.
|
||||
* <p>
|
||||
* The removal order of an <code>UnboundedFifoBuffer</code> is based on the insertion
|
||||
* order; elements are removed in the same order in which they were added.
|
||||
* The iteration order is the same as the removal order.
|
||||
* <p>
|
||||
* The {@link #remove()} and {@link #get()} operations perform in constant time.
|
||||
* The {@link #add(Object)} operation performs in amortized constant time. All
|
||||
* other operations perform in linear time or worse.
|
||||
* <p>
|
||||
* Note that this implementation is not synchronized. The following can be
|
||||
* used to provide synchronized access to your <code>UnboundedFifoBuffer</code>:
|
||||
* <pre>
|
||||
* Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoBuffer());
|
||||
* </pre>
|
||||
* <p>
|
||||
* This buffer prevents null objects from being added.
|
||||
*
|
||||
* @deprecated Moved to buffer subpackage. Due to be removed in v4.0.
|
||||
* @since Commons Collections 2.1
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Avalon
|
||||
* @author Federico Barbieri
|
||||
* @author Berin Loritsch
|
||||
* @author Paul Jack
|
||||
* @author Stephen Colebourne
|
||||
* @author Andreas Schlosser
|
||||
*/
|
||||
public class UnboundedFifoBuffer extends AbstractCollection implements Buffer {
|
||||
|
||||
protected Object[] m_buffer;
|
||||
protected int m_head;
|
||||
protected int m_tail;
|
||||
|
||||
/**
|
||||
* Constructs an UnboundedFifoBuffer with the default number of elements.
|
||||
* It is exactly the same as performing the following:
|
||||
*
|
||||
* <pre>
|
||||
* new UnboundedFifoBuffer(32);
|
||||
* </pre>
|
||||
*/
|
||||
public UnboundedFifoBuffer() {
|
||||
this(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an UnboundedFifoBuffer with the specified number of elements.
|
||||
* The integer must be a positive integer.
|
||||
*
|
||||
* @param initialSize the initial size of the buffer
|
||||
* @throws IllegalArgumentException if the size is less than 1
|
||||
*/
|
||||
public UnboundedFifoBuffer(int initialSize) {
|
||||
if (initialSize <= 0) {
|
||||
throw new IllegalArgumentException("The size must be greater than 0");
|
||||
}
|
||||
m_buffer = new Object[initialSize + 1];
|
||||
m_head = 0;
|
||||
m_tail = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements stored in the buffer.
|
||||
*
|
||||
* @return this buffer's size
|
||||
*/
|
||||
public int size() {
|
||||
int size = 0;
|
||||
|
||||
if (m_tail < m_head) {
|
||||
size = m_buffer.length - m_head + m_tail;
|
||||
} else {
|
||||
size = m_tail - m_head;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this buffer is empty; false otherwise.
|
||||
*
|
||||
* @return true if this buffer is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return (size() == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given element to this buffer.
|
||||
*
|
||||
* @param obj the element to add
|
||||
* @return true, always
|
||||
* @throws NullPointerException if the given element is null
|
||||
* @throws BufferOverflowException if this buffer is full
|
||||
*/
|
||||
public boolean add(final Object obj) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException("Attempted to add null object to buffer");
|
||||
}
|
||||
|
||||
if (size() + 1 >= m_buffer.length) {
|
||||
Object[] tmp = new Object[((m_buffer.length - 1) * 2) + 1];
|
||||
|
||||
int j = 0;
|
||||
for (int i = m_head; i != m_tail;) {
|
||||
tmp[j] = m_buffer[i];
|
||||
m_buffer[i] = null;
|
||||
|
||||
j++;
|
||||
i++;
|
||||
if (i == m_buffer.length) {
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer = tmp;
|
||||
m_head = 0;
|
||||
m_tail = j;
|
||||
}
|
||||
|
||||
m_buffer[m_tail] = obj;
|
||||
m_tail++;
|
||||
if (m_tail >= m_buffer.length) {
|
||||
m_tail = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next object in the buffer.
|
||||
*
|
||||
* @return the next object in the buffer
|
||||
* @throws BufferUnderflowException if this buffer is empty
|
||||
*/
|
||||
public Object get() {
|
||||
if (isEmpty()) {
|
||||
throw new BufferUnderflowException("The buffer is already empty");
|
||||
}
|
||||
|
||||
return m_buffer[m_head];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the next object from the buffer
|
||||
*
|
||||
* @return the removed object
|
||||
* @throws BufferUnderflowException if this buffer is empty
|
||||
*/
|
||||
public Object remove() {
|
||||
if (isEmpty()) {
|
||||
throw new BufferUnderflowException("The buffer is already empty");
|
||||
}
|
||||
|
||||
Object element = m_buffer[m_head];
|
||||
|
||||
if (null != element) {
|
||||
m_buffer[m_head] = null;
|
||||
|
||||
m_head++;
|
||||
if (m_head >= m_buffer.length) {
|
||||
m_head = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the internal index.
|
||||
*
|
||||
* @param index the index to increment
|
||||
* @return the updated index
|
||||
*/
|
||||
private int increment(int index) {
|
||||
index++;
|
||||
if (index >= m_buffer.length) {
|
||||
index = 0;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the internal index.
|
||||
*
|
||||
* @param index the index to decrement
|
||||
* @return the updated index
|
||||
*/
|
||||
private int decrement(int index) {
|
||||
index--;
|
||||
if (index < 0) {
|
||||
index = m_buffer.length - 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over this buffer's elements.
|
||||
*
|
||||
* @return an iterator over this buffer's elements
|
||||
*/
|
||||
public Iterator iterator() {
|
||||
return new Iterator() {
|
||||
|
||||
private int index = m_head;
|
||||
private int lastReturnedIndex = -1;
|
||||
|
||||
public boolean hasNext() {
|
||||
return index != m_tail;
|
||||
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (!hasNext())
|
||||
throw new NoSuchElementException();
|
||||
lastReturnedIndex = index;
|
||||
index = increment(index);
|
||||
return m_buffer[lastReturnedIndex];
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (lastReturnedIndex == -1)
|
||||
throw new IllegalStateException();
|
||||
|
||||
// First element can be removed quickly
|
||||
if (lastReturnedIndex == m_head) {
|
||||
UnboundedFifoBuffer.this.remove();
|
||||
lastReturnedIndex = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Other elements require us to shift the subsequent elements
|
||||
int i = increment(lastReturnedIndex);
|
||||
while (i != m_tail) {
|
||||
m_buffer[decrement(i)] = m_buffer[i];
|
||||
i = increment(i);
|
||||
}
|
||||
|
||||
lastReturnedIndex = -1;
|
||||
m_tail = decrement(m_tail);
|
||||
m_buffer[m_tail] = null;
|
||||
index = decrement(index);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -1,102 +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.iterators;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* A Proxy {@link Iterator Iterator} which delegates its methods to a proxy instance.
|
||||
*
|
||||
* @deprecated Use AbstractIteratorDecorator. Will be removed in v4.0
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author James Strachan
|
||||
*/
|
||||
public class ProxyIterator implements Iterator {
|
||||
|
||||
/** Holds value of property iterator. */
|
||||
private Iterator iterator;
|
||||
|
||||
// Constructors
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ProxyIterator</code> that will not function
|
||||
* until {@link #setIterator(Iterator)} is called.
|
||||
*/
|
||||
public ProxyIterator() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ProxyIterator</code> that will use the
|
||||
* given iterator.
|
||||
*
|
||||
* @param iterator the underlying iterator
|
||||
*/
|
||||
public ProxyIterator(Iterator iterator) {
|
||||
super();
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
// Iterator interface
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if the underlying iterator has more elements.
|
||||
*
|
||||
* @return true if the underlying iterator has more elements
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return getIterator().hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next element from the underlying iterator.
|
||||
*
|
||||
* @return the next element from the underlying iterator
|
||||
* @throws java.util.NoSuchElementException if the underlying iterator
|
||||
* raises it because it has no more elements
|
||||
*/
|
||||
public Object next() {
|
||||
return getIterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last returned element from the collection that spawned
|
||||
* the underlying iterator.
|
||||
*/
|
||||
public void remove() {
|
||||
getIterator().remove();
|
||||
}
|
||||
|
||||
// Properties
|
||||
//-------------------------------------------------------------------------
|
||||
/** Getter for property iterator.
|
||||
* @return Value of property iterator.
|
||||
*/
|
||||
public Iterator getIterator() {
|
||||
return iterator;
|
||||
}
|
||||
/** Setter for property iterator.
|
||||
* @param iterator New value of property iterator.
|
||||
*/
|
||||
public void setIterator(Iterator iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
}
|
|
@ -1,163 +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.iterators;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
* A proxy {@link ListIterator ListIterator} which delegates its
|
||||
* methods to a proxy instance.
|
||||
*
|
||||
* @deprecated Use AbstractListIteratorDecorator. Will be removed in v4.0
|
||||
* @since Commons Collections 2.0
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Rodney Waldhoff
|
||||
*/
|
||||
public class ProxyListIterator implements ListIterator {
|
||||
|
||||
/** Holds value of property "iterator". */
|
||||
private ListIterator iterator;
|
||||
|
||||
// Constructors
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ProxyListIterator</code> that will not
|
||||
* function until {@link #setListIterator(ListIterator) setListIterator}
|
||||
* is invoked.
|
||||
*/
|
||||
public ProxyListIterator() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ProxyListIterator</code> that will use the
|
||||
* given list iterator.
|
||||
*
|
||||
* @param iterator the list iterator to use
|
||||
*/
|
||||
public ProxyListIterator(ListIterator iterator) {
|
||||
super();
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
// ListIterator interface
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link ListIterator#add(Object)} method.
|
||||
*
|
||||
* @throws NullPointerException if the underlying iterator is null
|
||||
*/
|
||||
public void add(Object o) {
|
||||
getListIterator().add(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link ListIterator#hasNext()} method.
|
||||
*
|
||||
* @throws NullPointerException if the underlying iterator is null
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return getListIterator().hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link ListIterator#hasPrevious()} method.
|
||||
*
|
||||
* @throws NullPointerException if the underlying iterator is null
|
||||
*/
|
||||
public boolean hasPrevious() {
|
||||
return getListIterator().hasPrevious();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link ListIterator#next()} method.
|
||||
*
|
||||
* @throws NullPointerException if the underlying iterator is null
|
||||
*/
|
||||
public Object next() {
|
||||
return getListIterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link ListIterator#nextIndex()} method.
|
||||
*
|
||||
* @throws NullPointerException if the underlying iterator is null
|
||||
*/
|
||||
public int nextIndex() {
|
||||
return getListIterator().nextIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link ListIterator#previous()} method.
|
||||
*
|
||||
* @throws NullPointerException if the underlying iterator is null
|
||||
*/
|
||||
public Object previous() {
|
||||
return getListIterator().previous();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link ListIterator#previousIndex()} method.
|
||||
*
|
||||
* @throws NullPointerException if the underlying iterator is null
|
||||
*/
|
||||
public int previousIndex() {
|
||||
return getListIterator().previousIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link ListIterator#remove()} method.
|
||||
*
|
||||
* @throws NullPointerException if the underlying iterator is null
|
||||
*/
|
||||
public void remove() {
|
||||
getListIterator().remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the underlying {@link ListIterator#set(Object)} method.
|
||||
*
|
||||
* @throws NullPointerException if the underlying iterator is null
|
||||
*/
|
||||
public void set(Object o) {
|
||||
getListIterator().set(o);
|
||||
}
|
||||
|
||||
// Properties
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Getter for property iterator.
|
||||
* @return Value of property iterator.
|
||||
*/
|
||||
public ListIterator getListIterator() {
|
||||
return iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property iterator.
|
||||
* @param iterator New value of property iterator.
|
||||
*/
|
||||
public void setListIterator(ListIterator iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -54,7 +54,6 @@ public class MapPerformance {
|
|||
Map unmodHashMap = Collections.unmodifiableMap(new HashMap(hashMap));
|
||||
Map fastHashMap = new FastHashMap(hashMap);
|
||||
Map treeMap = new TreeMap(hashMap);
|
||||
Map seqMap = new SequencedHashMap(hashMap);
|
||||
// Map linkedMap = new LinkedHashMap(hashMap);
|
||||
// Map syncMap = Collections.unmodifiableMap(new HashMap(hashMap));
|
||||
// Map bucketMap = new StaticBucketMap();
|
||||
|
|
|
@ -41,6 +41,7 @@ public class TestAll extends TestCase {
|
|||
suite.addTest(TestBufferUtils.suite());
|
||||
suite.addTest(TestEnumerationUtils.suite());
|
||||
suite.addTest(TestFactoryUtils.suite());
|
||||
suite.addTest(TestIteratorUtils.suite());
|
||||
suite.addTest(TestListUtils.suite());
|
||||
suite.addTest(TestMapUtils.suite());
|
||||
suite.addTest(TestPredicateUtils.suite());
|
||||
|
@ -48,12 +49,6 @@ public class TestAll extends TestCase {
|
|||
suite.addTest(TestTransformerUtils.suite());
|
||||
|
||||
suite.addTest(TestArrayStack.suite());
|
||||
suite.addTest(TestBeanMap.suite());
|
||||
suite.addTest(TestBinaryHeap.suite());
|
||||
suite.addTest(TestBoundedFifoBuffer.suite());
|
||||
suite.addTest(TestBoundedFifoBuffer2.suite());
|
||||
suite.addTest(TestCursorableLinkedList.suite());
|
||||
suite.addTest(TestDoubleOrderedMap.suite());
|
||||
suite.addTest(TestExtendedProperties.suite());
|
||||
suite.addTest(TestFastArrayList.suite());
|
||||
suite.addTest(TestFastArrayList1.suite());
|
||||
|
@ -61,15 +56,6 @@ public class TestAll extends TestCase {
|
|||
suite.addTest(TestFastHashMap1.suite());
|
||||
suite.addTest(TestFastTreeMap.suite());
|
||||
suite.addTest(TestFastTreeMap1.suite());
|
||||
suite.addTest(TestHashBag.suite());
|
||||
suite.addTest(TestIteratorUtils.suite());
|
||||
suite.addTest(TestLRUMap.suite());
|
||||
suite.addTest(TestMultiHashMap.suite());
|
||||
suite.addTest(TestReferenceMap.suite());
|
||||
suite.addTest(TestSequencedHashMap.suite());
|
||||
suite.addTest(TestStaticBucketMap.suite());
|
||||
suite.addTest(TestTreeBag.suite());
|
||||
suite.addTest(TestUnboundedFifoBuffer.suite());
|
||||
return suite;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,344 +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.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
import org.apache.commons.collections.map.AbstractTestMap;
|
||||
|
||||
/**
|
||||
* Test cases for BeanMap
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Morgan Delagrange
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public class TestBeanMap extends AbstractTestMap {
|
||||
|
||||
public TestBeanMap(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestRunner.run(suite());
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestBeanMap.class);
|
||||
}
|
||||
|
||||
/*
|
||||
note to self. The getter and setter methods were generated by copying the
|
||||
field declarations and using the following regular expression search and
|
||||
replace:
|
||||
|
||||
From:
|
||||
private \(.*\) some\(.*\);
|
||||
To:
|
||||
public \1 getSome\2Value() {
|
||||
return some\2;
|
||||
}
|
||||
public void setSome\2Value(\1 value) {
|
||||
some\2 = value;
|
||||
}
|
||||
|
||||
Also note: The sample keys and mappings were generated manually.
|
||||
*/
|
||||
|
||||
|
||||
public static class BeanWithProperties implements Serializable {
|
||||
private int someInt;
|
||||
private long someLong;
|
||||
private double someDouble;
|
||||
private float someFloat;
|
||||
private short someShort;
|
||||
private byte someByte;
|
||||
private char someChar;
|
||||
private Integer someInteger;
|
||||
private String someString;
|
||||
private Object someObject;
|
||||
|
||||
public int getSomeIntValue() {
|
||||
return someInt;
|
||||
}
|
||||
public void setSomeIntValue(int value) {
|
||||
someInt = value;
|
||||
}
|
||||
|
||||
public long getSomeLongValue() {
|
||||
return someLong;
|
||||
}
|
||||
public void setSomeLongValue(long value) {
|
||||
someLong = value;
|
||||
}
|
||||
|
||||
public double getSomeDoubleValue() {
|
||||
return someDouble;
|
||||
}
|
||||
public void setSomeDoubleValue(double value) {
|
||||
someDouble = value;
|
||||
}
|
||||
|
||||
public float getSomeFloatValue() {
|
||||
return someFloat;
|
||||
}
|
||||
public void setSomeFloatValue(float value) {
|
||||
someFloat = value;
|
||||
}
|
||||
|
||||
public short getSomeShortValue() {
|
||||
return someShort;
|
||||
}
|
||||
public void setSomeShortValue(short value) {
|
||||
someShort = value;
|
||||
}
|
||||
|
||||
public byte getSomeByteValue() {
|
||||
return someByte;
|
||||
}
|
||||
public void setSomeByteValue(byte value) {
|
||||
someByte = value;
|
||||
}
|
||||
|
||||
public char getSomeCharValue() {
|
||||
return someChar;
|
||||
}
|
||||
public void setSomeCharValue(char value) {
|
||||
someChar = value;
|
||||
}
|
||||
|
||||
public String getSomeStringValue() {
|
||||
return someString;
|
||||
}
|
||||
public void setSomeStringValue(String value) {
|
||||
someString = value;
|
||||
}
|
||||
|
||||
public Integer getSomeIntegerValue() {
|
||||
return someInteger;
|
||||
}
|
||||
public void setSomeIntegerValue(Integer value) {
|
||||
someInteger = value;
|
||||
}
|
||||
|
||||
public Object getSomeObjectValue() {
|
||||
return someObject;
|
||||
}
|
||||
public void setSomeObjectValue(Object value) {
|
||||
someObject = value;
|
||||
}
|
||||
}
|
||||
|
||||
// note to self. The Sample keys were generated by copying the field
|
||||
// declarations and using the following regular expression search and replace:
|
||||
//
|
||||
// From:
|
||||
// private \(.*\) some\(.*\);
|
||||
// To:
|
||||
// "some\2Value",
|
||||
//
|
||||
// Then, I manually added the "class" key, which is a property that exists for
|
||||
// all beans (and all objects for that matter.
|
||||
public Object[] getSampleKeys() {
|
||||
Object[] keys = new Object[] {
|
||||
"someIntValue",
|
||||
"someLongValue",
|
||||
"someDoubleValue",
|
||||
"someFloatValue",
|
||||
"someShortValue",
|
||||
"someByteValue",
|
||||
"someCharValue",
|
||||
"someIntegerValue",
|
||||
"someStringValue",
|
||||
"someObjectValue",
|
||||
"class",
|
||||
};
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object value that will be stored in the bean map as a value. Need
|
||||
* to save this externally so that we can make sure the object instances
|
||||
* are equivalent since getSampleValues() would otherwise construct a new
|
||||
* and different Object each time.
|
||||
**/
|
||||
private Object objectInFullMap = new Object();
|
||||
|
||||
// note to self: the sample values were created manually
|
||||
public Object[] getSampleValues() {
|
||||
Object[] values = new Object[] {
|
||||
new Integer(1234),
|
||||
new Long(1298341928234L),
|
||||
new Double(123423.34),
|
||||
new Float(1213332.12f),
|
||||
new Short((short)134),
|
||||
new Byte((byte)10),
|
||||
new Character('a'),
|
||||
new Integer(1432),
|
||||
"SomeStringValue",
|
||||
objectInFullMap,
|
||||
BeanWithProperties.class,
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
public Object[] getNewSampleValues() {
|
||||
Object[] values = new Object[] {
|
||||
new Integer(223),
|
||||
new Long(23341928234L),
|
||||
new Double(23423.34),
|
||||
new Float(213332.12f),
|
||||
new Short((short)234),
|
||||
new Byte((byte)20),
|
||||
new Character('b'),
|
||||
new Integer(232),
|
||||
"SomeNewStringValue",
|
||||
new Object(),
|
||||
null,
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Values is a dead copy in BeanMap, so refresh each time.
|
||||
*/
|
||||
public void verifyValues() {
|
||||
values = map.values();
|
||||
super.verifyValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* The mappings in a BeanMap are fixed on the properties the underlying
|
||||
* bean has. Adding and removing mappings is not possible, thus this
|
||||
* method is overridden to return false.
|
||||
*/
|
||||
public boolean isPutAddSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The mappings in a BeanMap are fixed on the properties the underlying
|
||||
* bean has. Adding and removing mappings is not possible, thus this
|
||||
* method is overridden to return false.
|
||||
*/
|
||||
public boolean isRemoveSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Map makeFullMap() {
|
||||
// note: These values must match (i.e. .equals() must return true)
|
||||
// those returned from getSampleValues().
|
||||
BeanWithProperties bean = new BeanWithProperties();
|
||||
bean.setSomeIntValue(1234);
|
||||
bean.setSomeLongValue(1298341928234L);
|
||||
bean.setSomeDoubleValue(123423.34);
|
||||
bean.setSomeFloatValue(1213332.12f);
|
||||
bean.setSomeShortValue((short)134);
|
||||
bean.setSomeByteValue((byte)10);
|
||||
bean.setSomeCharValue('a');
|
||||
bean.setSomeIntegerValue(new Integer(1432));
|
||||
bean.setSomeStringValue("SomeStringValue");
|
||||
bean.setSomeObjectValue(objectInFullMap);
|
||||
return new BeanMap(bean);
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
return new BeanMap();
|
||||
}
|
||||
|
||||
public String[] ignoredTests() {
|
||||
// Ignore the serialization tests on collection views.
|
||||
return new String[] {
|
||||
"TestBeanMap.bulkTestMapEntrySet.testCanonicalEmptyCollectionExists",
|
||||
"TestBeanMap.bulkTestMapEntrySet.testCanonicalFullCollectionExists",
|
||||
"TestBeanMap.bulkTestMapKeySet.testCanonicalEmptyCollectionExists",
|
||||
"TestBeanMap.bulkTestMapKeySet.testCanonicalFullCollectionExists",
|
||||
"TestBeanMap.bulkTestMapValues.testCanonicalEmptyCollectionExists",
|
||||
"TestBeanMap.bulkTestMapValues.testCanonicalFullCollectionExists",
|
||||
"TestBeanMap.bulkTestMapEntrySet.testSimpleSerialization",
|
||||
"TestBeanMap.bulkTestMapKeySet.testSimpleSerialization",
|
||||
"TestBeanMap.bulkTestMapEntrySet.testSerializeDeserializeThenCompare",
|
||||
"TestBeanMap.bulkTestMapKeySet.testSerializeDeserializeThenCompare"
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Need to override this method because the "clear()" method on the bean
|
||||
* map just returns the bean properties to their default states. It does
|
||||
* not actually remove the mappings as per the map contract. The default
|
||||
* testClear() methods checks that the clear method throws an
|
||||
* UnsupportedOperationException since this class is not add/remove
|
||||
* modifiable. In our case though, we do not always throw that exception.
|
||||
*/
|
||||
public void testMapClear() {
|
||||
//TODO: make sure a call to BeanMap.clear returns the bean to its
|
||||
//default initialization values.
|
||||
}
|
||||
|
||||
/**
|
||||
* Need to override this method because the "put()" method on the bean
|
||||
* doesn't work for this type of Map.
|
||||
*/
|
||||
public void testMapPut() {
|
||||
// see testBeanMapPutAllWriteable
|
||||
}
|
||||
|
||||
public void testBeanMapClone() {
|
||||
BeanMap map = (BeanMap)makeFullMap();
|
||||
try {
|
||||
BeanMap map2 = (BeanMap)((BeanMap)map).clone();
|
||||
|
||||
// make sure containsKey is working to verify the bean was cloned
|
||||
// ok, and the read methods were properly initialized
|
||||
Object[] keys = getSampleKeys();
|
||||
for(int i = 0; i < keys.length; i++) {
|
||||
assertTrue("Cloned BeanMap should contain the same keys",
|
||||
map2.containsKey(keys[i]));
|
||||
}
|
||||
} catch (CloneNotSupportedException exception) {
|
||||
fail("BeanMap.clone() should not throw a " +
|
||||
"CloneNotSupportedException when clone should succeed.");
|
||||
}
|
||||
}
|
||||
|
||||
public void testBeanMapPutAllWriteable() {
|
||||
BeanMap map1 = (BeanMap)makeFullMap();
|
||||
BeanMap map2 = (BeanMap)makeFullMap();
|
||||
map2.put("someIntValue", new Integer(0));
|
||||
map1.putAllWriteable(map2);
|
||||
assertEquals(map1.get("someIntValue"), new Integer(0));
|
||||
}
|
||||
|
||||
public void testMethodAccessor() throws Exception {
|
||||
BeanMap map = (BeanMap) makeFullMap();
|
||||
Method method = BeanWithProperties.class.getDeclaredMethod("getSomeIntegerValue", (Class[]) null);
|
||||
assertEquals(method, map.getReadMethod("someIntegerValue"));
|
||||
}
|
||||
|
||||
public void testMethodMutator() throws Exception {
|
||||
BeanMap map = (BeanMap) makeFullMap();
|
||||
Method method = BeanWithProperties.class.getDeclaredMethod("setSomeIntegerValue", new Class[] {Integer.class});
|
||||
assertEquals(method, map.getWriteMethod("someIntegerValue"));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,344 +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.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Random;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.apache.commons.collections.collection.AbstractTestCollection;
|
||||
import org.apache.commons.collections.comparators.ComparableComparator;
|
||||
import org.apache.commons.collections.comparators.ReverseComparator;
|
||||
|
||||
/**
|
||||
* Tests the BinaryHeap.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Michael A. Smith
|
||||
*/
|
||||
public class TestBinaryHeap extends AbstractTestCollection {
|
||||
|
||||
public static Test suite() {
|
||||
return new TestSuite(TestBinaryHeap.class);
|
||||
}
|
||||
|
||||
public TestBinaryHeap(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void verify() {
|
||||
super.verify();
|
||||
BinaryHeap heap = (BinaryHeap) collection;
|
||||
|
||||
Comparator c = heap.m_comparator;
|
||||
if (c == null)
|
||||
c = ComparatorUtils.naturalComparator();
|
||||
if (!heap.m_isMinHeap)
|
||||
c = ComparatorUtils.reversedComparator(c);
|
||||
|
||||
Object[] tree = heap.m_elements;
|
||||
for (int i = 1; i <= heap.m_size; i++) {
|
||||
Object parent = tree[i];
|
||||
if (i * 2 <= heap.m_size) {
|
||||
assertTrue("Parent is less than or equal to its left child", c.compare(parent, tree[i * 2]) <= 0);
|
||||
}
|
||||
if (i * 2 + 1 < heap.m_size) {
|
||||
assertTrue("Parent is less than or equal to its right child", c.compare(parent, tree[i * 2 + 1]) <= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Overridden because UnboundedFifoBuffer isn't fail fast.
|
||||
* @return false
|
||||
*/
|
||||
public boolean isFailFastSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public Collection makeConfirmedCollection() {
|
||||
return new ArrayList();
|
||||
}
|
||||
|
||||
public Collection makeConfirmedFullCollection() {
|
||||
ArrayList list = new ArrayList();
|
||||
list.addAll(Arrays.asList(getFullElements()));
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new, empty {@link Object} to used for testing.
|
||||
*/
|
||||
public Collection makeCollection() {
|
||||
return new BinaryHeap();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public Object[] getFullElements() {
|
||||
return getFullNonNullStringElements();
|
||||
}
|
||||
|
||||
public Object[] getOtherElements() {
|
||||
return getOtherNonNullStringElements();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testBasicOps() {
|
||||
BinaryHeap heap = new BinaryHeap();
|
||||
|
||||
assertTrue("heap should be empty after create", heap.isEmpty());
|
||||
|
||||
try {
|
||||
heap.peek();
|
||||
fail("NoSuchElementException should be thrown if peek is called before any elements are inserted");
|
||||
} catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
try {
|
||||
heap.pop();
|
||||
fail("NoSuchElementException should be thrown if pop is called before any elements are inserted");
|
||||
} catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
heap.insert("a");
|
||||
heap.insert("c");
|
||||
heap.insert("e");
|
||||
heap.insert("b");
|
||||
heap.insert("d");
|
||||
heap.insert("n");
|
||||
heap.insert("m");
|
||||
heap.insert("l");
|
||||
heap.insert("k");
|
||||
heap.insert("j");
|
||||
heap.insert("i");
|
||||
heap.insert("h");
|
||||
heap.insert("g");
|
||||
heap.insert("f");
|
||||
|
||||
assertTrue("heap should not be empty after inserts", !heap.isEmpty());
|
||||
|
||||
for (int i = 0; i < 14; i++) {
|
||||
assertEquals(
|
||||
"peek using default constructor should return minimum value in the binary heap",
|
||||
String.valueOf((char) ('a' + i)),
|
||||
heap.peek());
|
||||
|
||||
assertEquals(
|
||||
"pop using default constructor should return minimum value in the binary heap",
|
||||
String.valueOf((char) ('a' + i)),
|
||||
heap.pop());
|
||||
|
||||
if (i + 1 < 14) {
|
||||
assertTrue("heap should not be empty before all elements are popped", !heap.isEmpty());
|
||||
} else {
|
||||
assertTrue("heap should be empty after all elements are popped", heap.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
heap.peek();
|
||||
fail("NoSuchElementException should be thrown if peek is called after all elements are popped");
|
||||
} catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
try {
|
||||
heap.pop();
|
||||
fail("NoSuchElementException should be thrown if pop is called after all elements are popped");
|
||||
} catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testBasicComparatorOps() {
|
||||
BinaryHeap heap = new BinaryHeap(new ReverseComparator(new ComparableComparator()));
|
||||
|
||||
assertTrue("heap should be empty after create", heap.isEmpty());
|
||||
|
||||
try {
|
||||
heap.peek();
|
||||
fail("NoSuchElementException should be thrown if peek is called before any elements are inserted");
|
||||
} catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
try {
|
||||
heap.pop();
|
||||
fail("NoSuchElementException should be thrown if pop is called before any elements are inserted");
|
||||
} catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
heap.insert("a");
|
||||
heap.insert("c");
|
||||
heap.insert("e");
|
||||
heap.insert("b");
|
||||
heap.insert("d");
|
||||
heap.insert("n");
|
||||
heap.insert("m");
|
||||
heap.insert("l");
|
||||
heap.insert("k");
|
||||
heap.insert("j");
|
||||
heap.insert("i");
|
||||
heap.insert("h");
|
||||
heap.insert("g");
|
||||
heap.insert("f");
|
||||
|
||||
assertTrue("heap should not be empty after inserts", !heap.isEmpty());
|
||||
|
||||
for (int i = 0; i < 14; i++) {
|
||||
|
||||
// note: since we're using a comparator that reverses items, the
|
||||
// "minimum" item is "n", and the "maximum" item is "a".
|
||||
|
||||
assertEquals(
|
||||
"peek using default constructor should return minimum value in the binary heap",
|
||||
String.valueOf((char) ('n' - i)),
|
||||
heap.peek());
|
||||
|
||||
assertEquals(
|
||||
"pop using default constructor should return minimum value in the binary heap",
|
||||
String.valueOf((char) ('n' - i)),
|
||||
heap.pop());
|
||||
|
||||
if (i + 1 < 14) {
|
||||
assertTrue("heap should not be empty before all elements are popped", !heap.isEmpty());
|
||||
} else {
|
||||
assertTrue("heap should be empty after all elements are popped", heap.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
heap.peek();
|
||||
fail("NoSuchElementException should be thrown if peek is called after all elements are popped");
|
||||
} catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
try {
|
||||
heap.pop();
|
||||
fail("NoSuchElementException should be thrown if pop is called after all elements are popped");
|
||||
} catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Illustrates bad internal heap state reported in Bugzilla PR #235818.
|
||||
*/
|
||||
public void testAddRemove() {
|
||||
resetEmpty();
|
||||
BinaryHeap heap = (BinaryHeap) collection;
|
||||
heap.add(new Integer(0));
|
||||
heap.add(new Integer(2));
|
||||
heap.add(new Integer(4));
|
||||
heap.add(new Integer(3));
|
||||
heap.add(new Integer(8));
|
||||
heap.add(new Integer(10));
|
||||
heap.add(new Integer(12));
|
||||
heap.add(new Integer(3));
|
||||
confirmed.addAll(heap);
|
||||
// System.out.println(heap);
|
||||
Object obj = new Integer(10);
|
||||
heap.remove(obj);
|
||||
confirmed.remove(obj);
|
||||
// System.out.println(heap);
|
||||
verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate heaps staring with Integers from 0 - heapSize - 1.
|
||||
* Then perform random add / remove operations, checking
|
||||
* heap order after modifications. Alternates minHeaps, maxHeaps.
|
||||
*
|
||||
* Based on code provided by Steve Phelps in PR #25818
|
||||
*
|
||||
*/
|
||||
public void testRandom() {
|
||||
int iterations = 500;
|
||||
int heapSize = 100;
|
||||
int operations = 20;
|
||||
Random randGenerator = new Random();
|
||||
BinaryHeap h = null;
|
||||
for(int i=0; i < iterations; i++) {
|
||||
if (i < iterations / 2) {
|
||||
h = new BinaryHeap(true);
|
||||
} else {
|
||||
h = new BinaryHeap(false);
|
||||
}
|
||||
for(int r = 0; r < heapSize; r++) {
|
||||
h.add( new Integer( randGenerator.nextInt(heapSize)) );
|
||||
}
|
||||
for( int r = 0; r < operations; r++ ) {
|
||||
h.remove(new Integer(r));
|
||||
h.add(new Integer(randGenerator.nextInt(heapSize)));
|
||||
}
|
||||
checkOrder(h);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all elements from the heap and verifies that the elements come off
|
||||
* in the correct order. NOTE: this method empties the heap.
|
||||
*/
|
||||
protected void checkOrder(BinaryHeap h) {
|
||||
Integer lastNum = null;
|
||||
Integer num = null;
|
||||
boolean fail = false;
|
||||
while (!h.isEmpty()) {
|
||||
num = (Integer) h.pop();
|
||||
if (h.m_isMinHeap) {
|
||||
assertTrue(lastNum == null || num.intValue() >= lastNum.intValue());
|
||||
} else { // max heap
|
||||
assertTrue(lastNum == null || num.intValue() <= lastNum.intValue());
|
||||
}
|
||||
lastNum = num;
|
||||
num = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string showing the contents of the heap formatted as a tree.
|
||||
* Makes no attempt at padding levels or handling wrapping.
|
||||
*/
|
||||
protected String showTree(BinaryHeap h) {
|
||||
int count = 1;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (int offset = 1; count < h.size() + 1; offset *= 2) {
|
||||
for (int i = offset; i < offset * 2; i++) {
|
||||
if (i < h.m_elements.length && h.m_elements[i] != null)
|
||||
buffer.append(h.m_elements[i] + " ");
|
||||
count++;
|
||||
}
|
||||
buffer.append('\n');
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,166 +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.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.apache.commons.collections.collection.AbstractTestCollection;
|
||||
|
||||
/**
|
||||
* Test cases for BoundedFifoBuffer.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Paul Jack
|
||||
*/
|
||||
public class TestBoundedFifoBuffer extends AbstractTestCollection {
|
||||
|
||||
public TestBoundedFifoBuffer(String n) {
|
||||
super(n);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestBoundedFifoBuffer.class);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Runs through the regular verifications, but also verifies that
|
||||
* the buffer contains the same elements in the same sequence as the
|
||||
* list.
|
||||
*/
|
||||
public void verify() {
|
||||
super.verify();
|
||||
Iterator iterator1 = collection.iterator();
|
||||
Iterator iterator2 = confirmed.iterator();
|
||||
while (iterator2.hasNext()) {
|
||||
assertTrue(iterator1.hasNext());
|
||||
Object o1 = iterator1.next();
|
||||
Object o2 = iterator2.next();
|
||||
assertEquals(o1, o2);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Overridden because UnboundedFifoBuffer doesn't allow null elements.
|
||||
* @return false
|
||||
*/
|
||||
public boolean isNullSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden because UnboundedFifoBuffer isn't fail fast.
|
||||
* @return false
|
||||
*/
|
||||
public boolean isFailFastSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns an empty ArrayList.
|
||||
*
|
||||
* @return an empty ArrayList
|
||||
*/
|
||||
public Collection makeConfirmedCollection() {
|
||||
return new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full ArrayList.
|
||||
*
|
||||
* @return a full ArrayList
|
||||
*/
|
||||
public Collection makeConfirmedFullCollection() {
|
||||
Collection c = makeConfirmedCollection();
|
||||
c.addAll(java.util.Arrays.asList(getFullElements()));
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty BoundedFifoBuffer that won't overflow.
|
||||
*
|
||||
* @return an empty BoundedFifoBuffer
|
||||
*/
|
||||
public Collection makeCollection() {
|
||||
return new BoundedFifoBuffer(100);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Tests that the removal operation actually removes the first element.
|
||||
*/
|
||||
public void testBoundedFifoBufferRemove() {
|
||||
resetFull();
|
||||
int size = confirmed.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object o1 = ((BoundedFifoBuffer)collection).remove();
|
||||
Object o2 = ((ArrayList)confirmed).remove(0);
|
||||
assertEquals("Removed objects should be equal", o1, o2);
|
||||
verify();
|
||||
}
|
||||
|
||||
try {
|
||||
((BoundedFifoBuffer)collection).remove();
|
||||
fail("Empty buffer should raise Underflow.");
|
||||
} catch (BufferUnderflowException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the constructor correctly throws an exception.
|
||||
*/
|
||||
public void testConstructorException1() {
|
||||
try {
|
||||
new BoundedFifoBuffer(0);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the constructor correctly throws an exception.
|
||||
*/
|
||||
public void testConstructorException2() {
|
||||
try {
|
||||
new BoundedFifoBuffer(-20);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the constructor correctly throws an exception.
|
||||
*/
|
||||
public void testConstructorException3() {
|
||||
try {
|
||||
new BoundedFifoBuffer(null);
|
||||
} catch (NullPointerException ex) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
}
|
|
@ -1,120 +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.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Runs tests against a full BoundedFifoBuffer, since many of the algorithms
|
||||
* differ depending on whether the fifo is full or not.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Unknown
|
||||
*/
|
||||
public class TestBoundedFifoBuffer2 extends TestBoundedFifoBuffer {
|
||||
|
||||
public TestBoundedFifoBuffer2(String n) {
|
||||
super(n);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestBoundedFifoBuffer2.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BoundedFifoBuffer that's filled to capacity.
|
||||
* Any attempt to add to the returned buffer will result in a
|
||||
* BufferOverflowException.
|
||||
*
|
||||
* @return a full BoundedFifoBuffer
|
||||
*/
|
||||
public Collection makeFullCollection() {
|
||||
return new BoundedFifoBuffer(Arrays.asList(getFullElements()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden to skip the add tests. All of them would fail with a
|
||||
* BufferOverflowException.
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public boolean isAddSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden because the add operations raise BufferOverflowException
|
||||
* instead of UnsupportedOperationException.
|
||||
*/
|
||||
public void testUnsupportedAdd() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests to make sure the add operations raise BufferOverflowException.
|
||||
*/
|
||||
public void testBufferOverflow() {
|
||||
resetFull();
|
||||
try {
|
||||
collection.add(getOtherElements()[0]);
|
||||
fail("add should raise BufferOverflow.");
|
||||
} catch (BufferOverflowException e) {
|
||||
// expected
|
||||
}
|
||||
verify();
|
||||
|
||||
try {
|
||||
collection.addAll(Arrays.asList(getOtherElements()));
|
||||
fail("addAll should raise BufferOverflow.");
|
||||
} catch (BufferOverflowException e) {
|
||||
// expected
|
||||
}
|
||||
verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests is full
|
||||
*/
|
||||
public void testIsFull() {
|
||||
resetFull();
|
||||
assertEquals(true, ((BoundedCollection) collection).isFull());
|
||||
((BoundedFifoBuffer) collection).remove();
|
||||
assertEquals(false, ((BoundedCollection) collection).isFull());
|
||||
((BoundedFifoBuffer) collection).add("jj");
|
||||
assertEquals(true, ((BoundedCollection) collection).isFull());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests max size
|
||||
*/
|
||||
public void testMaxSize() {
|
||||
resetFull();
|
||||
assertEquals(getFullElements().length, ((BoundedCollection) collection).maxSize());
|
||||
((BoundedFifoBuffer) collection).remove();
|
||||
assertEquals(getFullElements().length, ((BoundedCollection) collection).maxSize());
|
||||
((BoundedFifoBuffer) collection).add("jj");
|
||||
assertEquals(getFullElements().length, ((BoundedCollection) collection).maxSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -325,14 +325,6 @@ public class TestExtendedProperties extends TestCase {
|
|||
assertEquals("import", a.getInclude());
|
||||
assertEquals("include", b.getInclude());
|
||||
|
||||
a.setInclude("");
|
||||
assertEquals(null, a.getInclude());
|
||||
assertEquals("include", b.getInclude());
|
||||
|
||||
a.setInclude("hi");
|
||||
assertEquals("hi", a.getInclude());
|
||||
assertEquals("include", b.getInclude());
|
||||
|
||||
a.setInclude(null);
|
||||
assertEquals(null, a.getInclude());
|
||||
assertEquals("include", b.getInclude());
|
||||
|
|
|
@ -1,51 +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 junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.apache.commons.collections.bag.AbstractTestBag;
|
||||
|
||||
/**
|
||||
* Extension of {@link TestBag} for exercising the {@link HashBag}
|
||||
* implementation.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Chuck Burdick
|
||||
*/
|
||||
public class TestHashBag extends AbstractTestBag {
|
||||
|
||||
public TestHashBag(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return new TestSuite(TestHashBag.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestHashBag.class.getName()};
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public Bag makeBag() {
|
||||
return new HashBag();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,212 +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.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Tests LRUMap.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author James Strachan
|
||||
* @author Morgan Delagrange
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public class TestLRUMap extends TestSequencedHashMap {
|
||||
|
||||
public TestLRUMap(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestLRUMap.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestLRUMap.class.getName() };
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public Map makeEmptyMap() {
|
||||
LRUMap map = new LRUMap();
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override as test uses iterator() and getKey() in combination which doesn't work.
|
||||
*/
|
||||
public String[] ignoredTests() {
|
||||
return new String[] {"TestLRUMap.bulkTestMapEntrySet.testMapEntrySetIteratorEntry"};
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testRemoveLRU() {
|
||||
LRUMap map2 = new LRUMap(3);
|
||||
map2.put(new Integer(1),"foo");
|
||||
map2.put(new Integer(2),"foo");
|
||||
map2.put(new Integer(3),"foo");
|
||||
map2.put(new Integer(4),"foo"); // removes 1 since max size exceeded
|
||||
map2.removeLRU(); // should be Integer(2)
|
||||
|
||||
assertTrue("Second to last value should exist",map2.get(new Integer(3)).equals("foo"));
|
||||
assertTrue("First value inserted should not exist", map2.get(new Integer(1)) == null);
|
||||
}
|
||||
|
||||
public void testMultiplePuts() {
|
||||
LRUMap map2 = new LRUMap(2);
|
||||
map2.put(new Integer(1),"foo");
|
||||
map2.put(new Integer(2),"bar");
|
||||
map2.put(new Integer(3),"foo");
|
||||
map2.put(new Integer(4),"bar");
|
||||
|
||||
assertTrue("last value should exist",map2.get(new Integer(4)).equals("bar"));
|
||||
assertTrue("LRU should not exist", map2.get(new Integer(1)) == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that putAll(Map) does not cause the LRUMap
|
||||
* to exceed its maxiumum size.
|
||||
*/
|
||||
public void testPutAll() {
|
||||
LRUMap map2 = new LRUMap(3);
|
||||
map2.put(new Integer(1),"foo");
|
||||
map2.put(new Integer(2),"foo");
|
||||
map2.put(new Integer(3),"foo");
|
||||
|
||||
HashMap hashMap = new HashMap();
|
||||
hashMap.put(new Integer(4),"foo");
|
||||
|
||||
map2.putAll(hashMap);
|
||||
|
||||
assertTrue("max size is 3, but actual size is " + map2.size(),
|
||||
map2.size() == 3);
|
||||
assertTrue("map should contain the Integer(4) object",
|
||||
map2.containsKey(new Integer(4)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the size of the map is reduced immediately
|
||||
* when setMaximumSize(int) is called
|
||||
*/
|
||||
public void testSetMaximumSize() {
|
||||
LRUMap map = new LRUMap(6);
|
||||
map.put("1","1");
|
||||
map.put("2","2");
|
||||
map.put("3","3");
|
||||
map.put("4","4");
|
||||
map.put("5","5");
|
||||
map.put("6","6");
|
||||
map.setMaximumSize(3);
|
||||
|
||||
assertTrue("map should have size = 3, but actually = " + map.size(),
|
||||
map.size() == 3);
|
||||
}
|
||||
|
||||
public void testGetPromotion() {
|
||||
LRUMap map = new LRUMap(3);
|
||||
map.put("1","1");
|
||||
map.put("2","2");
|
||||
map.put("3","3");
|
||||
// LRU is now 1 (then 2 then 3)
|
||||
|
||||
// promote 1 to top
|
||||
// eviction order is now 2,3,1
|
||||
map.get("1");
|
||||
|
||||
// add another value, forcing a remove
|
||||
// 2 should be evicted (then 3,1,4)
|
||||
map.put("4","4");
|
||||
|
||||
Iterator keyIterator = map.keySet().iterator();
|
||||
Object[] keys = new Object[3];
|
||||
for (int i = 0; keyIterator.hasNext() ; ++i) {
|
||||
keys[i] = keyIterator.next();
|
||||
}
|
||||
|
||||
assertTrue("first evicted should be 3, was " + keys[0], keys[0].equals("3"));
|
||||
assertTrue("second evicted should be 1, was " + keys[1], keys[1].equals("1"));
|
||||
assertTrue("third evicted should be 4, was " + keys[2], keys[2].equals("4"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* You should be able to subclass LRUMap and perform a
|
||||
* custom action when items are removed automatically
|
||||
* by the LRU algorithm (the removeLRU() method).
|
||||
*/
|
||||
public void testLRUSubclass() {
|
||||
LRUCounter counter = new LRUCounter(3);
|
||||
// oldest <--> newest
|
||||
// 1
|
||||
counter.put("1","foo");
|
||||
// 1 2
|
||||
counter.put("2","foo");
|
||||
// 1 2 3
|
||||
counter.put("3","foo");
|
||||
// 2 3 1
|
||||
counter.put("1","foo");
|
||||
// 3 1 4 (2 goes out)
|
||||
counter.put("4","foo");
|
||||
// 1 4 5 (3 goes out)
|
||||
counter.put("5","foo");
|
||||
// 4 5 2 (1 goes out)
|
||||
counter.put("2","foo");
|
||||
// 4 2
|
||||
counter.remove("5");
|
||||
|
||||
assertTrue("size should be 2, but was " + counter.size(), counter.size() == 2);
|
||||
assertTrue("removedCount should be 3 but was " + counter.removedCount,
|
||||
counter.removedCount == 3);
|
||||
|
||||
assertTrue("first removed was '2'",counter.list.get(0).equals("2"));
|
||||
assertTrue("second removed was '3'",counter.list.get(1).equals("3"));
|
||||
assertTrue("third removed was '1'",counter.list.get(2).equals("1"));
|
||||
|
||||
assertTrue("oldest key is '4'",counter.get(0).equals("4"));
|
||||
assertTrue("newest key is '2'",counter.get(1).equals("2"));
|
||||
}
|
||||
|
||||
|
||||
protected void entrySetEqualsMap(Set set, Map m) {
|
||||
// Overridden because LRUMap.get(Object) actually alters the map,
|
||||
// so there's no way to verify that the entry set and map contain
|
||||
// the same entries
|
||||
}
|
||||
|
||||
private class LRUCounter extends LRUMap {
|
||||
int removedCount = 0;
|
||||
ArrayList list = new ArrayList(3);
|
||||
|
||||
LRUCounter(int i) {
|
||||
super(i);
|
||||
}
|
||||
|
||||
protected void processRemovedLRU(Object key, Object value) {
|
||||
++removedCount;
|
||||
list.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,475 +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.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.apache.commons.collections.map.AbstractTestMap;
|
||||
|
||||
/**
|
||||
* Unit Tests for <code>MultiHashMap</code>.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Unknown
|
||||
*/
|
||||
public class TestMultiHashMap extends AbstractTestMap {
|
||||
|
||||
public TestMultiHashMap(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return new TestSuite(TestMultiHashMap.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestMultiHashMap.class.getName()};
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
// MutltiHashMap was introduced in Collections 2.x
|
||||
public String getCompatibilityVersion() {
|
||||
return "2";
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
return new MultiHashMap();
|
||||
}
|
||||
|
||||
//----------------------------
|
||||
// Tests
|
||||
//----------------------------
|
||||
public void testPutNGet() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
loadMap(map);
|
||||
checkMap(map);
|
||||
|
||||
assertTrue(map.get(new Integer(99)) == null);
|
||||
|
||||
map.clear();
|
||||
assertTrue(map.size() == 0);
|
||||
}
|
||||
|
||||
public void testContainsValue() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
loadMap(map);
|
||||
|
||||
assertTrue(map.containsValue("uno"));
|
||||
assertTrue(map.containsValue("quatro"));
|
||||
assertTrue(map.containsValue("two"));
|
||||
|
||||
assertTrue(!map.containsValue("uggaBugga"));
|
||||
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public void testValues() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
loadMap(map);
|
||||
|
||||
Collection vals = map.values();
|
||||
assertTrue(vals.size() == getFullSize());
|
||||
|
||||
map.clear();
|
||||
}
|
||||
|
||||
static private class MapPair {
|
||||
MapPair(int key, String val) {
|
||||
mKey = new Integer(key);
|
||||
mValue = val;
|
||||
}
|
||||
|
||||
Integer mKey = null;
|
||||
String mValue = null;
|
||||
}
|
||||
|
||||
static private MapPair[][] sMapPairs =
|
||||
{
|
||||
{new MapPair(0,"zero")},
|
||||
{new MapPair(1,"one"), new MapPair(1,"ONE"), new MapPair(1,"uno")},
|
||||
{new MapPair(2,"two"), new MapPair(2,"two") },
|
||||
{new MapPair(3,"three"), new MapPair(3,"THREE"), new MapPair(3,"tres")},
|
||||
{new MapPair(4,"four"), new MapPair(4,"quatro")}
|
||||
};
|
||||
|
||||
private void loadMap(MultiHashMap map) {
|
||||
// Set up so that we load the keys "randomly"
|
||||
// (i.e. we don't want to load int row-order, so that all like keys
|
||||
// load together. We want to mix it up...)
|
||||
|
||||
int numRows = sMapPairs.length;
|
||||
int maxCols = 0;
|
||||
for (int ii = 0; ii < sMapPairs.length; ii++) {
|
||||
if (sMapPairs[ii].length > maxCols) {
|
||||
maxCols = sMapPairs[ii].length;
|
||||
}
|
||||
}
|
||||
for (int ii = 0; ii < maxCols; ii++) {
|
||||
for (int jj = 0; jj < numRows; jj++) {
|
||||
if (ii < sMapPairs[jj].length) {
|
||||
map.put(sMapPairs[jj][ii].mKey, sMapPairs[jj][ii].mValue);
|
||||
//---------------------------------------------------------
|
||||
}
|
||||
}
|
||||
}
|
||||
assertTrue(map.size() == sMapPairs.length);
|
||||
}
|
||||
|
||||
private void checkMap(MultiHashMap map) {
|
||||
for (int ii = 0; ii < sMapPairs.length; ii++) {
|
||||
checkKeyList(map, ii);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkKeyList(MultiHashMap map, int index) {
|
||||
assertTrue(index < sMapPairs.length);
|
||||
Integer key = sMapPairs[index][0].mKey;
|
||||
|
||||
Object obj = map.get(key);
|
||||
//--------------------------
|
||||
|
||||
assertTrue(obj != null);
|
||||
assertTrue(obj instanceof Collection);
|
||||
Collection keyList = (Collection) obj;
|
||||
|
||||
assertTrue(keyList.size() == sMapPairs[index].length);
|
||||
Iterator iter = keyList.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Object oval = iter.next();
|
||||
assertTrue(oval != null);
|
||||
assertTrue(oval instanceof String);
|
||||
String val = (String) oval;
|
||||
boolean foundIt = false;
|
||||
for (int ii = 0; ii < sMapPairs[index].length; ii++) {
|
||||
if (val.equals(sMapPairs[index][ii].mValue)) {
|
||||
foundIt = true;
|
||||
}
|
||||
}
|
||||
assertTrue(foundIt);
|
||||
}
|
||||
}
|
||||
|
||||
public int getFullSize() {
|
||||
int len = 0;
|
||||
for (int ii = 0; ii < sMapPairs.length; ii++) {
|
||||
len += sMapPairs[ii].length;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
public void testEntrySetIterator() {
|
||||
}
|
||||
public void testEntrySetContainsProperMappings() {
|
||||
}
|
||||
public void testEntrySetIteratorHasProperMappings() {
|
||||
// override and ignore test -- it will fail when verifying the iterator for
|
||||
// the set contains the right value -- we're not returning the value, we're
|
||||
// returning a collection.
|
||||
// TODO: re-implement this test to ensure the values of the iterator match
|
||||
// the proper collection rather than the value the superclass is checking
|
||||
// for.
|
||||
return;
|
||||
}
|
||||
|
||||
// Next methods are overriden because MultiHashMap values are always a
|
||||
// collection, and deviate from the Map contract because of this.
|
||||
|
||||
// TODO: implement the tests to ensure that Map.get(Object) returns the
|
||||
// appropriate collection of values
|
||||
|
||||
public void testMapGet() {
|
||||
}
|
||||
|
||||
public void testMapPut() {
|
||||
}
|
||||
|
||||
public void testMapPutAll() {
|
||||
}
|
||||
|
||||
public void testMapRemove() {
|
||||
}
|
||||
|
||||
public void testMapEquals() {
|
||||
MultiHashMap one = new MultiHashMap();
|
||||
Integer value = new Integer(1);
|
||||
one.put("One", value);
|
||||
one.remove("One", value);
|
||||
|
||||
MultiHashMap two = new MultiHashMap();
|
||||
assertEquals(two, one);
|
||||
}
|
||||
|
||||
public void testMapHashCode() {
|
||||
}
|
||||
|
||||
// The verification for the map and its entry set must also be overridden
|
||||
// because the values are not going to be the same as the values in the
|
||||
// confirmed map (they're going to be collections of values instead).
|
||||
public void verifyMap() {
|
||||
// TODO: implement test to ensure that map is the same as confirmed if
|
||||
// its values were converted into collections.
|
||||
}
|
||||
|
||||
public void verifyEntrySet() {
|
||||
// TODO: implement test to ensure that each entry is the same as one in
|
||||
// the confirmed map, but with the value wrapped in a collection.
|
||||
}
|
||||
|
||||
// The verification method must be overridden because MultiHashMap's
|
||||
// values() is not properly backed by the map (Bug 9573).
|
||||
|
||||
public void verifyValues() {
|
||||
// update the values view to the latest version, then proceed to verify
|
||||
// as usual.
|
||||
values = map.values();
|
||||
super.verifyValues();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testGetCollection() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
map.put("A", "AA");
|
||||
assertSame(map.get("A"), map.getCollection("A"));
|
||||
}
|
||||
|
||||
public void testTotalSize() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
assertEquals(0, map.totalSize());
|
||||
map.put("A", "AA");
|
||||
assertEquals(1, map.totalSize());
|
||||
map.put("B", "BA");
|
||||
assertEquals(2, map.totalSize());
|
||||
map.put("B", "BB");
|
||||
assertEquals(3, map.totalSize());
|
||||
map.put("B", "BC");
|
||||
assertEquals(4, map.totalSize());
|
||||
map.remove("A");
|
||||
assertEquals(3, map.totalSize());
|
||||
map.remove("B", "BC");
|
||||
assertEquals(2, map.totalSize());
|
||||
}
|
||||
|
||||
public void testSize_Key() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
assertEquals(0, map.size("A"));
|
||||
assertEquals(0, map.size("B"));
|
||||
map.put("A", "AA");
|
||||
assertEquals(1, map.size("A"));
|
||||
assertEquals(0, map.size("B"));
|
||||
map.put("B", "BA");
|
||||
assertEquals(1, map.size("A"));
|
||||
assertEquals(1, map.size("B"));
|
||||
map.put("B", "BB");
|
||||
assertEquals(1, map.size("A"));
|
||||
assertEquals(2, map.size("B"));
|
||||
map.put("B", "BC");
|
||||
assertEquals(1, map.size("A"));
|
||||
assertEquals(3, map.size("B"));
|
||||
map.remove("A");
|
||||
assertEquals(0, map.size("A"));
|
||||
assertEquals(3, map.size("B"));
|
||||
map.remove("B", "BC");
|
||||
assertEquals(0, map.size("A"));
|
||||
assertEquals(2, map.size("B"));
|
||||
}
|
||||
|
||||
public void testIterator_Key() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
assertEquals(false, map.iterator("A").hasNext());
|
||||
map.put("A", "AA");
|
||||
Iterator it = map.iterator("A");
|
||||
assertEquals(true, it.hasNext());
|
||||
it.next();
|
||||
assertEquals(false, it.hasNext());
|
||||
}
|
||||
|
||||
public void testContainsValue_Key() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
assertEquals(false, map.containsValue("A", "AA"));
|
||||
assertEquals(false, map.containsValue("B", "BB"));
|
||||
map.put("A", "AA");
|
||||
assertEquals(true, map.containsValue("A", "AA"));
|
||||
assertEquals(false, map.containsValue("A", "AB"));
|
||||
}
|
||||
|
||||
public void testPutAll_Map1() {
|
||||
MultiMap original = new MultiHashMap();
|
||||
original.put("key", "object1");
|
||||
original.put("key", "object2");
|
||||
|
||||
MultiHashMap test = new MultiHashMap();
|
||||
test.put("keyA", "objectA");
|
||||
test.put("key", "object0");
|
||||
test.putAll(original);
|
||||
|
||||
assertEquals(2, test.size());
|
||||
assertEquals(4, test.totalSize());
|
||||
assertEquals(1, test.getCollection("keyA").size());
|
||||
assertEquals(3, test.getCollection("key").size());
|
||||
assertEquals(true, test.containsValue("objectA"));
|
||||
assertEquals(true, test.containsValue("object0"));
|
||||
assertEquals(true, test.containsValue("object1"));
|
||||
assertEquals(true, test.containsValue("object2"));
|
||||
}
|
||||
|
||||
public void testPutAll_Map2() {
|
||||
Map original = new HashMap();
|
||||
original.put("keyX", "object1");
|
||||
original.put("keyY", "object2");
|
||||
|
||||
MultiHashMap test = new MultiHashMap();
|
||||
test.put("keyA", "objectA");
|
||||
test.put("keyX", "object0");
|
||||
test.putAll(original);
|
||||
|
||||
assertEquals(3, test.size());
|
||||
assertEquals(4, test.totalSize());
|
||||
assertEquals(1, test.getCollection("keyA").size());
|
||||
assertEquals(2, test.getCollection("keyX").size());
|
||||
assertEquals(1, test.getCollection("keyY").size());
|
||||
assertEquals(true, test.containsValue("objectA"));
|
||||
assertEquals(true, test.containsValue("object0"));
|
||||
assertEquals(true, test.containsValue("object1"));
|
||||
assertEquals(true, test.containsValue("object2"));
|
||||
}
|
||||
|
||||
public void testPutAll_KeyCollection() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
Collection coll = Arrays.asList(new Object[] {"X", "Y", "Z"});
|
||||
|
||||
assertEquals(true, map.putAll("A", coll));
|
||||
assertEquals(3, map.size("A"));
|
||||
assertEquals(true, map.containsValue("A", "X"));
|
||||
assertEquals(true, map.containsValue("A", "Y"));
|
||||
assertEquals(true, map.containsValue("A", "Z"));
|
||||
|
||||
assertEquals(false, map.putAll("A", null));
|
||||
assertEquals(3, map.size("A"));
|
||||
assertEquals(true, map.containsValue("A", "X"));
|
||||
assertEquals(true, map.containsValue("A", "Y"));
|
||||
assertEquals(true, map.containsValue("A", "Z"));
|
||||
|
||||
assertEquals(false, map.putAll("A", new ArrayList()));
|
||||
assertEquals(3, map.size("A"));
|
||||
assertEquals(true, map.containsValue("A", "X"));
|
||||
assertEquals(true, map.containsValue("A", "Y"));
|
||||
assertEquals(true, map.containsValue("A", "Z"));
|
||||
|
||||
coll = Arrays.asList(new Object[] {"M"});
|
||||
assertEquals(true, map.putAll("A", coll));
|
||||
assertEquals(4, map.size("A"));
|
||||
assertEquals(true, map.containsValue("A", "X"));
|
||||
assertEquals(true, map.containsValue("A", "Y"));
|
||||
assertEquals(true, map.containsValue("A", "Z"));
|
||||
assertEquals(true, map.containsValue("A", "M"));
|
||||
}
|
||||
|
||||
public void testClone() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
map.put("A", "1");
|
||||
map.put("A", "2");
|
||||
Collection coll = (Collection) map.get("A");
|
||||
assertEquals(1, map.size());
|
||||
assertEquals(2, coll.size());
|
||||
|
||||
MultiHashMap cloned = (MultiHashMap) map.clone();
|
||||
Collection clonedColl = (Collection) cloned.get("A");
|
||||
assertNotSame(map, cloned);
|
||||
assertNotSame(coll, clonedColl);
|
||||
assertEquals(1, map.size());
|
||||
assertEquals(2, coll.size());
|
||||
assertEquals(1, cloned.size());
|
||||
assertEquals(2, clonedColl.size());
|
||||
map.put("A", "3");
|
||||
assertEquals(1, map.size());
|
||||
assertEquals(3, coll.size());
|
||||
assertEquals(1, cloned.size());
|
||||
assertEquals(2, clonedColl.size());
|
||||
}
|
||||
|
||||
public void testConstructorCopy1() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
map.put("A", "1");
|
||||
map.put("A", "2");
|
||||
Collection coll = (Collection) map.get("A");
|
||||
assertEquals(1, map.size());
|
||||
assertEquals(2, coll.size());
|
||||
|
||||
MultiHashMap newMap = new MultiHashMap(map);
|
||||
Collection newColl = (Collection) newMap.get("A");
|
||||
assertNotSame(map, newMap);
|
||||
assertNotSame(coll, newColl);
|
||||
assertEquals(1, map.size());
|
||||
assertEquals(2, coll.size());
|
||||
assertEquals(1, newMap.size());
|
||||
assertEquals(2, newColl.size());
|
||||
|
||||
map.put("A", "3");
|
||||
assertEquals(1, map.size());
|
||||
assertEquals(3, coll.size());
|
||||
assertEquals(1, newMap.size());
|
||||
assertEquals(2, newColl.size());
|
||||
}
|
||||
|
||||
public void testConstructorCopy2() {
|
||||
Map map = new HashMap();
|
||||
map.put("A", "1");
|
||||
map.put("B", "2");
|
||||
assertEquals(2, map.size());
|
||||
|
||||
MultiHashMap newMap = new MultiHashMap(map);
|
||||
Collection newColl = (Collection) newMap.get("A");
|
||||
assertNotSame(map, newMap);
|
||||
assertEquals(2, map.size());
|
||||
assertEquals(2, newMap.size());
|
||||
assertEquals(1, newColl.size());
|
||||
|
||||
map.put("A", "3");
|
||||
assertEquals(2, map.size());
|
||||
assertEquals(2, newMap.size());
|
||||
assertEquals(1, newColl.size());
|
||||
|
||||
map.put("C", "4");
|
||||
assertEquals(3, map.size());
|
||||
assertEquals(2, newMap.size());
|
||||
assertEquals(1, newColl.size());
|
||||
}
|
||||
|
||||
public void testRemove_KeyItem() {
|
||||
MultiHashMap map = new MultiHashMap();
|
||||
map.put("A", "AA");
|
||||
map.put("A", "AB");
|
||||
map.put("A", "AC");
|
||||
assertEquals(null, map.remove("C", "CA"));
|
||||
assertEquals(null, map.remove("A", "AD"));
|
||||
assertEquals("AC", map.remove("A", "AC"));
|
||||
assertEquals("AB", map.remove("A", "AB"));
|
||||
assertEquals("AA", map.remove("A", "AA"));
|
||||
assertEquals(new MultiHashMap(), map);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,212 +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.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.apache.commons.collections.map.AbstractTestMap;
|
||||
|
||||
/**
|
||||
* Tests for ReferenceMap.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Paul Jack
|
||||
* @author Guilhem Lavaux
|
||||
*/
|
||||
public class TestReferenceMap extends AbstractTestMap {
|
||||
|
||||
public TestReferenceMap(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestReferenceMap.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestReferenceMap.class.getName() };
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
|
||||
return map;
|
||||
}
|
||||
|
||||
public boolean isAllowNullKey() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAllowNullValue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getCompatibilityVersion() {
|
||||
return "2.1";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testNullHandling() {
|
||||
resetFull();
|
||||
assertEquals(null, map.get(null));
|
||||
assertEquals(false, map.containsKey(null));
|
||||
assertEquals(false, map.containsValue(null));
|
||||
assertEquals(null, map.remove(null));
|
||||
assertEquals(false, map.entrySet().contains(null));
|
||||
assertEquals(false, map.keySet().contains(null));
|
||||
assertEquals(false, map.values().contains(null));
|
||||
try {
|
||||
map.put(null, null);
|
||||
fail();
|
||||
} catch (NullPointerException ex) {}
|
||||
try {
|
||||
map.put(new Object(), null);
|
||||
fail();
|
||||
} catch (NullPointerException ex) {}
|
||||
try {
|
||||
map.put(null, new Object());
|
||||
fail();
|
||||
} catch (NullPointerException ex) {}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/*
|
||||
// Tests often fail because gc is uncontrollable
|
||||
|
||||
public void testPurge() {
|
||||
ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
|
||||
Object[] hard = new Object[10];
|
||||
for (int i = 0; i < hard.length; i++) {
|
||||
hard[i] = new Object();
|
||||
map.put(hard[i], new Object());
|
||||
}
|
||||
gc();
|
||||
assertTrue("map should be empty after purge of weak values", map.isEmpty());
|
||||
|
||||
for (int i = 0; i < hard.length; i++) {
|
||||
map.put(new Object(), hard[i]);
|
||||
}
|
||||
gc();
|
||||
assertTrue("map should be empty after purge of weak keys", map.isEmpty());
|
||||
|
||||
for (int i = 0; i < hard.length; i++) {
|
||||
map.put(new Object(), hard[i]);
|
||||
map.put(hard[i], new Object());
|
||||
}
|
||||
|
||||
gc();
|
||||
assertTrue("map should be empty after purge of weak keys and values", map.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
public void testGetAfterGC() {
|
||||
ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
map.put(new Integer(i), new Integer(i));
|
||||
}
|
||||
|
||||
gc();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Integer I = new Integer(i);
|
||||
assertTrue("map.containsKey should return false for GC'd element", !map.containsKey(I));
|
||||
assertTrue("map.get should return null for GC'd element", map.get(I) == null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testEntrySetIteratorAfterGC() {
|
||||
ReferenceMap map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
|
||||
Object[] hard = new Object[10];
|
||||
for (int i = 0; i < 10; i++) {
|
||||
hard[i] = new Integer(10 + i);
|
||||
map.put(new Integer(i), new Integer(i));
|
||||
map.put(hard[i], hard[i]);
|
||||
}
|
||||
|
||||
gc();
|
||||
Iterator iterator = map.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry)iterator.next();
|
||||
Integer key = (Integer)entry.getKey();
|
||||
Integer value = (Integer)entry.getValue();
|
||||
assertTrue("iterator should skip GC'd keys", key.intValue() >= 10);
|
||||
assertTrue("iterator should skip GC'd values", value.intValue() >= 10);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
WeakReference keyReference;
|
||||
WeakReference valueReference;
|
||||
|
||||
public Map buildRefMap() {
|
||||
Object key = new Object();
|
||||
Object value = new Object();
|
||||
|
||||
keyReference = new WeakReference(key);
|
||||
valueReference = new WeakReference(value);
|
||||
|
||||
Map testMap = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD, true);
|
||||
testMap.put(key, value);
|
||||
|
||||
assertEquals("In map", value, testMap.get(key));
|
||||
assertNotNull("Weak reference released early (1)", keyReference.get());
|
||||
assertNotNull("Weak reference released early (2)", valueReference.get());
|
||||
return testMap;
|
||||
}
|
||||
|
||||
/** Tests whether purge values setting works */
|
||||
public void testPurgeValues() throws Exception {
|
||||
// many thanks to Juozas Baliuka for suggesting this method
|
||||
|
||||
Map testMap = buildRefMap();
|
||||
|
||||
int iterations = 0;
|
||||
int bytz = 2;
|
||||
while(true) {
|
||||
System.gc();
|
||||
if(iterations++ > 50){
|
||||
fail("Max iterations reached before resource released.");
|
||||
}
|
||||
testMap.isEmpty();
|
||||
if(
|
||||
keyReference.get() == null &&
|
||||
valueReference.get() == null) {
|
||||
break;
|
||||
|
||||
} else {
|
||||
// create garbage:
|
||||
byte[] b = new byte[bytz];
|
||||
bytz = bytz * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void gc() {
|
||||
try {
|
||||
// trigger GC
|
||||
byte[][] tooLarge = new byte[1000000000][1000000000];
|
||||
fail("you have too much RAM");
|
||||
} catch (OutOfMemoryError ex) {
|
||||
System.gc(); // ignore
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,194 +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.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.apache.commons.collections.map.AbstractTestMap;
|
||||
|
||||
/**
|
||||
* Unit tests
|
||||
* {@link org.apache.commons.collections.SequencedHashMap}.
|
||||
* Be sure to use the "labRat" instance whenever possible,
|
||||
* so that subclasses will be tested correctly.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Morgan Delagrange
|
||||
* @author Daniel Rall
|
||||
* @author Henning P. Schmiedehausen
|
||||
* @author James Strachan
|
||||
*/
|
||||
public class TestSequencedHashMap extends AbstractTestMap {
|
||||
/**
|
||||
* The instance to experiment on.
|
||||
*/
|
||||
protected SequencedHashMap labRat;
|
||||
|
||||
public TestSequencedHashMap(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestSequencedHashMap.class);
|
||||
}
|
||||
|
||||
// current versions of SequencedHashMap and subclasses are not
|
||||
// compatible with Collections 1.x
|
||||
public String getCompatibilityVersion() {
|
||||
return "2";
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String[] testCaseName = { TestSequencedHashMap.class.getName() };
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
// use makeMap and cast the result to a SeqHashMap
|
||||
// so that subclasses of SeqHashMap can share these tests
|
||||
labRat = (SequencedHashMap) makeEmptyMap();
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
return new SequencedHashMap();
|
||||
}
|
||||
|
||||
protected Object[] getKeys() {
|
||||
return new Object[] { "foo", "baz", "eek" };
|
||||
}
|
||||
|
||||
protected Object[] getValues() {
|
||||
return new Object[] { "bar", "frob", new Object() };
|
||||
}
|
||||
|
||||
public void testSequenceMap() throws Throwable {
|
||||
Object[] keys = getKeys();
|
||||
int expectedSize = keys.length;
|
||||
Object[] values = getValues();
|
||||
for (int i = 0; i < expectedSize; i++) {
|
||||
labRat.put(keys[i], values[i]);
|
||||
}
|
||||
|
||||
// Test size().
|
||||
assertEquals("size() does not match expected size",
|
||||
expectedSize, labRat.size());
|
||||
|
||||
// Test clone(), iterator(), and get(Object).
|
||||
SequencedHashMap clone = (SequencedHashMap) labRat.clone();
|
||||
assertEquals("Size of clone does not match original",
|
||||
labRat.size(), clone.size());
|
||||
Iterator origEntries = labRat.entrySet().iterator();
|
||||
Iterator copiedEntries = clone.entrySet().iterator();
|
||||
while (origEntries.hasNext()) {
|
||||
Map.Entry origEntry = (Map.Entry)origEntries.next();
|
||||
Map.Entry copiedEntry = (Map.Entry)copiedEntries.next();
|
||||
assertEquals("Cloned key does not match original",
|
||||
origEntry.getKey(), copiedEntry.getKey());
|
||||
assertEquals("Cloned value does not match original",
|
||||
origEntry.getValue(), copiedEntry.getValue());
|
||||
assertEquals("Cloned entry does not match original",
|
||||
origEntry, copiedEntry);
|
||||
}
|
||||
assertTrue("iterator() returned different number of elements than keys()",
|
||||
!copiedEntries.hasNext());
|
||||
|
||||
// Test sequence()
|
||||
List seq = labRat.sequence();
|
||||
assertEquals("sequence() returns more keys than in the Map",
|
||||
expectedSize, seq.size());
|
||||
|
||||
for (int i = 0; i < seq.size(); i++) {
|
||||
assertEquals("Key " + i + " is not the same as the key in the Map",
|
||||
keys[i], seq.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void testYoungest() {
|
||||
labRat.put(new Integer(1),"foo");
|
||||
labRat.put(new Integer(2),"bar");
|
||||
assertTrue("first key is correct",labRat.get(0).equals(new Integer(1)));
|
||||
labRat.put(new Integer(1),"boo");
|
||||
assertTrue("second key is reassigned to first",labRat.get(0).equals(new Integer(2)));
|
||||
}
|
||||
|
||||
public void testYoungestReplaceNullWithValue() {
|
||||
labRat.put(new Integer(1),null);
|
||||
labRat.put(new Integer(2),"foo");
|
||||
assertTrue("first key is correct",labRat.get(0).equals(new Integer(1)));
|
||||
labRat.put(new Integer(1),"bar");
|
||||
assertTrue("second key is reassigned to first",labRat.get(0).equals(new Integer(2)));
|
||||
}
|
||||
|
||||
public void testYoungestReplaceValueWithNull() {
|
||||
labRat.put(new Integer(1),"bar");
|
||||
labRat.put(new Integer(2),"foo");
|
||||
assertTrue("first key is correct",labRat.get(0).equals(new Integer(1)));
|
||||
labRat.put(new Integer(1),null);
|
||||
assertTrue("second key is reassigned to first",labRat.get(0).equals(new Integer(2)));
|
||||
}
|
||||
|
||||
// override TestMap method with more specific tests
|
||||
public void testFullMapSerialization()
|
||||
throws IOException, ClassNotFoundException {
|
||||
SequencedHashMap map = (SequencedHashMap) makeFullMap();
|
||||
|
||||
if (!(map instanceof Serializable)) return;
|
||||
|
||||
byte[] objekt = writeExternalFormToBytes((Serializable) map);
|
||||
SequencedHashMap map2 = (SequencedHashMap) readExternalFormFromBytes(objekt);
|
||||
|
||||
assertEquals("Both maps are same size",map.size(), getSampleKeys().length);
|
||||
assertEquals("Both maps are same size",map2.size(),getSampleKeys().length);
|
||||
|
||||
assertEquals("Both maps have the same first key",
|
||||
map.getFirstKey(),getSampleKeys()[0]);
|
||||
assertEquals("Both maps have the same first key",
|
||||
map2.getFirstKey(),getSampleKeys()[0]);
|
||||
assertEquals("Both maps have the same last key",
|
||||
map.getLastKey(),getSampleKeys()[getSampleKeys().length - 1]);
|
||||
assertEquals("Both maps have the same last key",
|
||||
map2.getLastKey(),getSampleKeys()[getSampleKeys().length - 1]);
|
||||
}
|
||||
|
||||
public void testIndexOf() throws Exception {
|
||||
Object[] keys = getKeys();
|
||||
int expectedSize = keys.length;
|
||||
Object[] values = getValues();
|
||||
for (int i = 0; i < expectedSize; i++) {
|
||||
labRat.put(keys[i], values[i]);
|
||||
}
|
||||
// test that the index returned are in the same order that they were
|
||||
// placed in the map
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
assertEquals("indexOf with existing key failed", i, labRat.indexOf(keys[i]));
|
||||
}
|
||||
// test non existing key..
|
||||
assertEquals("test with non-existing key failed", -1, labRat.indexOf("NonExistingKey"));
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
labRat = null;
|
||||
}
|
||||
}
|
|
@ -1,96 +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;
|
||||
|
||||
/**
|
||||
* Unit tests.
|
||||
* {@link org.apache.commons.collections.StaticBucketMap}.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Michael A. Smith
|
||||
*/
|
||||
public class TestStaticBucketMap extends AbstractTestMap {
|
||||
|
||||
public TestStaticBucketMap(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestStaticBucketMap.class);
|
||||
}
|
||||
|
||||
public static void main(String[] args[]) {
|
||||
String[] testCaseName = { TestStaticBucketMap.class.getName() };
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
return new StaticBucketMap(30);
|
||||
}
|
||||
|
||||
public String[] ignoredTests() {
|
||||
String pre = "TestStaticBucketMap.bulkTestMap";
|
||||
String post = ".testCollectionIteratorFailFast";
|
||||
return new String[] {
|
||||
pre + "EntrySet" + post,
|
||||
pre + "KeySet" + post,
|
||||
pre + "Values" + post
|
||||
};
|
||||
}
|
||||
|
||||
// Bugzilla 37567
|
||||
public void test_get_nullMatchesIncorrectly() {
|
||||
StaticBucketMap map = new StaticBucketMap(17);
|
||||
map.put(null, "A");
|
||||
assertEquals("A", map.get(null));
|
||||
// loop so we find a string that is in the same bucket as the null
|
||||
for (int i = 'A'; i <= 'Z'; i++) {
|
||||
String str = String.valueOf((char) i);
|
||||
assertEquals("String: " + str, null, map.get(str));
|
||||
}
|
||||
}
|
||||
|
||||
public void test_containsKey_nullMatchesIncorrectly() {
|
||||
StaticBucketMap map = new StaticBucketMap(17);
|
||||
map.put(null, "A");
|
||||
assertEquals(true, map.containsKey(null));
|
||||
// loop so we find a string that is in the same bucket as the null
|
||||
for (int i = 'A'; i <= 'Z'; i++) {
|
||||
String str = String.valueOf((char) i);
|
||||
assertEquals("String: " + str, false, map.containsKey(str));
|
||||
}
|
||||
}
|
||||
|
||||
public void test_containsValue_nullMatchesIncorrectly() {
|
||||
StaticBucketMap map = new StaticBucketMap(17);
|
||||
map.put("A", null);
|
||||
assertEquals(true, map.containsValue(null));
|
||||
// loop so we find a string that is in the same bucket as the null
|
||||
for (int i = 'A'; i <= 'Z'; i++) {
|
||||
String str = String.valueOf((char) i);
|
||||
assertEquals("String: " + str, false, map.containsValue(str));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,73 +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 junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.apache.commons.collections.bag.AbstractTestBag;
|
||||
|
||||
/**
|
||||
* Extension of {@link TestBag} for exercising the {@link TreeBag}
|
||||
* implementation.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Chuck Burdick
|
||||
*/
|
||||
public class TestTreeBag extends AbstractTestBag {
|
||||
|
||||
public TestTreeBag(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return new TestSuite(TestTreeBag.class);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestTreeBag.class.getName() };
|
||||
junit.textui.TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public Bag makeBag() {
|
||||
return new TreeBag();
|
||||
}
|
||||
|
||||
public SortedBag setupBag() {
|
||||
SortedBag bag = (SortedBag)makeBag();
|
||||
bag.add("C");
|
||||
bag.add("A");
|
||||
bag.add("B");
|
||||
bag.add("D");
|
||||
return bag;
|
||||
}
|
||||
|
||||
public void testOrdering() {
|
||||
Bag bag = setupBag();
|
||||
assertEquals("Should get elements in correct order",
|
||||
"A", bag.toArray()[0]);
|
||||
assertEquals("Should get elements in correct order",
|
||||
"B", bag.toArray()[1]);
|
||||
assertEquals("Should get elements in correct order",
|
||||
"C", bag.toArray()[2]);
|
||||
assertEquals("Should get first key",
|
||||
"A", ((SortedBag)bag).first());
|
||||
assertEquals("Should get last key",
|
||||
"D", ((SortedBag)bag).last());
|
||||
}
|
||||
}
|
|
@ -1,414 +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.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.apache.commons.collections.collection.AbstractTestCollection;
|
||||
|
||||
/**
|
||||
* Test cases for UnboundedFifoBuffer.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @author Unknown
|
||||
*/
|
||||
public class TestUnboundedFifoBuffer extends AbstractTestCollection {
|
||||
|
||||
public TestUnboundedFifoBuffer(String n) {
|
||||
super(n);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return BulkTest.makeSuite(TestUnboundedFifoBuffer.class);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Verifies that the ArrayList has the same elements in the same
|
||||
* sequence as the UnboundedFifoBuffer.
|
||||
*/
|
||||
public void verify() {
|
||||
super.verify();
|
||||
Iterator iterator1 = collection.iterator();
|
||||
Iterator iterator2 = confirmed.iterator();
|
||||
while (iterator2.hasNext()) {
|
||||
assertTrue(iterator1.hasNext());
|
||||
Object o1 = iterator1.next();
|
||||
Object o2 = iterator2.next();
|
||||
assertEquals(o1, o2);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Overridden because UnboundedFifoBuffer doesn't allow null elements.
|
||||
* @return false
|
||||
*/
|
||||
public boolean isNullSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden because UnboundedFifoBuffer isn't fail fast.
|
||||
* @return false
|
||||
*/
|
||||
public boolean isFailFastSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns an empty ArrayList.
|
||||
*
|
||||
* @return an empty ArrayList
|
||||
*/
|
||||
public Collection makeConfirmedCollection() {
|
||||
return new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full ArrayList.
|
||||
*
|
||||
* @return a full ArrayList
|
||||
*/
|
||||
public Collection makeConfirmedFullCollection() {
|
||||
Collection c = makeConfirmedCollection();
|
||||
c.addAll(java.util.Arrays.asList(getFullElements()));
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty UnboundedFifoBuffer with a small capacity.
|
||||
*
|
||||
* @return an empty UnboundedFifoBuffer
|
||||
*/
|
||||
public Collection makeCollection() {
|
||||
return new UnboundedFifoBuffer(5);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Tests that UnboundedFifoBuffer removes elements in the right order.
|
||||
*/
|
||||
public void testUnboundedFifoBufferRemove() {
|
||||
resetFull();
|
||||
int size = confirmed.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object o1 = ((UnboundedFifoBuffer)collection).remove();
|
||||
Object o2 = ((ArrayList)confirmed).remove(0);
|
||||
assertEquals("Removed objects should be equal", o1, o2);
|
||||
verify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the constructor correctly throws an exception.
|
||||
*/
|
||||
public void testConstructorException1() {
|
||||
try {
|
||||
new UnboundedFifoBuffer(0);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the constructor correctly throws an exception.
|
||||
*/
|
||||
public void testConstructorException2() {
|
||||
try {
|
||||
new UnboundedFifoBuffer(-20);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testInternalStateAdd() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(2);
|
||||
assertEquals(3, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(0, test.m_tail);
|
||||
test.add("A");
|
||||
assertEquals(3, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(1, test.m_tail);
|
||||
test.add("B");
|
||||
assertEquals(3, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(2, test.m_tail);
|
||||
test.add("C"); // forces m_buffer increase
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
test.add("D");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(4, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateAddWithWrap() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(3);
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(0, test.m_tail);
|
||||
test.add("A");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(1, test.m_tail);
|
||||
test.add("B");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(2, test.m_tail);
|
||||
test.add("C");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
test.remove("A");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
test.remove("B");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(2, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
test.add("D");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(2, test.m_head);
|
||||
assertEquals(0, test.m_tail);
|
||||
test.add("E");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(2, test.m_head);
|
||||
assertEquals(1, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateRemove1() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(4);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
|
||||
test.remove("A");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
|
||||
test.add("D");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(4, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateRemove2() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(4);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
|
||||
test.remove("B");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(2, test.m_tail);
|
||||
|
||||
test.add("D");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateIteratorRemove1() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(4);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
|
||||
Iterator it = test.iterator();
|
||||
it.next();
|
||||
it.remove();
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
|
||||
test.add("D");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(4, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateIteratorRemove2() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(4);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
|
||||
Iterator it = test.iterator();
|
||||
it.next();
|
||||
it.next();
|
||||
it.remove();
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(2, test.m_tail);
|
||||
|
||||
test.add("D");
|
||||
assertEquals(5, test.m_buffer.length);
|
||||
assertEquals(0, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateIteratorRemoveWithTailAtEnd1() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(3);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
test.remove("A");
|
||||
test.add("D");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(0, test.m_tail);
|
||||
|
||||
Iterator it = test.iterator();
|
||||
assertEquals("B", it.next());
|
||||
it.remove();
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(2, test.m_head);
|
||||
assertEquals(0, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateIteratorRemoveWithTailAtEnd2() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(3);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
test.remove("A");
|
||||
test.add("D");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(0, test.m_tail);
|
||||
|
||||
Iterator it = test.iterator();
|
||||
assertEquals("B", it.next());
|
||||
assertEquals("C", it.next());
|
||||
it.remove();
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateIteratorRemoveWithTailAtEnd3() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(3);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
test.remove("A");
|
||||
test.add("D");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(0, test.m_tail);
|
||||
|
||||
Iterator it = test.iterator();
|
||||
assertEquals("B", it.next());
|
||||
assertEquals("C", it.next());
|
||||
assertEquals("D", it.next());
|
||||
it.remove();
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(1, test.m_head);
|
||||
assertEquals(3, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateIteratorRemoveWithWrap1() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(3);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
test.remove("A");
|
||||
test.remove("B");
|
||||
test.add("D");
|
||||
test.add("E");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(2, test.m_head);
|
||||
assertEquals(1, test.m_tail);
|
||||
|
||||
Iterator it = test.iterator();
|
||||
assertEquals("C", it.next());
|
||||
it.remove();
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(3, test.m_head);
|
||||
assertEquals(1, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateIteratorRemoveWithWrap2() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(3);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
test.remove("A");
|
||||
test.remove("B");
|
||||
test.add("D");
|
||||
test.add("E");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(2, test.m_head);
|
||||
assertEquals(1, test.m_tail);
|
||||
|
||||
Iterator it = test.iterator();
|
||||
assertEquals("C", it.next());
|
||||
assertEquals("D", it.next());
|
||||
it.remove();
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(2, test.m_head);
|
||||
assertEquals(0, test.m_tail);
|
||||
}
|
||||
|
||||
public void testInternalStateIteratorRemoveWithWrap3() {
|
||||
UnboundedFifoBuffer test = new UnboundedFifoBuffer(3);
|
||||
test.add("A");
|
||||
test.add("B");
|
||||
test.add("C");
|
||||
test.remove("A");
|
||||
test.remove("B");
|
||||
test.add("D");
|
||||
test.add("E");
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(2, test.m_head);
|
||||
assertEquals(1, test.m_tail);
|
||||
|
||||
Iterator it = test.iterator();
|
||||
assertEquals("C", it.next());
|
||||
assertEquals("D", it.next());
|
||||
assertEquals("E", it.next());
|
||||
it.remove();
|
||||
assertEquals(4, test.m_buffer.length);
|
||||
assertEquals(2, test.m_head);
|
||||
assertEquals(0, test.m_tail);
|
||||
}
|
||||
|
||||
}
|
|
@ -1473,4 +1473,15 @@ public class TestCursorableLinkedList extends TestAbstractLinkedList {
|
|||
return (String[])list.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public String getCompatibilityVersion() {
|
||||
return "4.0";
|
||||
}
|
||||
|
||||
// public void testCreate() throws Exception {
|
||||
// resetEmpty();
|
||||
// writeExternalFormToDisk((java.io.Serializable) collection, "C:/commons/collections/data/test/CursorableLinkedList.emptyCollection.version4.0.obj");
|
||||
// resetFull();
|
||||
// writeExternalFormToDisk((java.io.Serializable) collection, "C:/commons/collections/data/test/CursorableLinkedList.fullCollection.version4.0.obj");
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue