Add MultiKeyMap implementation
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@131664 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
07a0768664
commit
9cfe01cf6d
|
@ -26,6 +26,7 @@ No interface changes, or deprecations have occurred.
|
||||||
<center><h3>NEW CLASSES</h3></center>
|
<center><h3>NEW CLASSES</h3></center>
|
||||||
<ul>
|
<ul>
|
||||||
<li>SingletonMap - fully featured singleton Map implementation</li>
|
<li>SingletonMap - fully featured singleton Map implementation</li>
|
||||||
|
<li>MultiKeyMap - A map that allows multiple keys to be used to map the value</li>
|
||||||
<li>TransformedPredicate - A predicate where the input object is transformed [26946]</li>
|
<li>TransformedPredicate - A predicate where the input object is transformed [26946]</li>
|
||||||
<li>ObjectGraphIterator - An iterator that can iterate over a graph of objects</li>
|
<li>ObjectGraphIterator - An iterator that can iterate over a graph of objects</li>
|
||||||
<li>AbstractReferenceMap - New base class for reference maps [26503]</li>
|
<li>AbstractReferenceMap - New base class for reference maps [26503]</li>
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,816 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2004 The Apache Software Foundation
|
||||||
|
*
|
||||||
|
* Licensed 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.map;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.MapIterator;
|
||||||
|
import org.apache.commons.collections.keyvalue.MultiKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A <code>Map</code> implementation that uses multiple keys to map the value.
|
||||||
|
* <p>
|
||||||
|
* This class is the most efficient way to uses multiple keys to map to a value.
|
||||||
|
* The best way to use this class is via the additional map-style methods.
|
||||||
|
* These provide <code>get</code>, <code>containsKey</code>, <code>put</code> and
|
||||||
|
* <code>remove</code> for individual keys which operate without extra object creation.
|
||||||
|
* <p>
|
||||||
|
* The additional methods are the main interface of this map.
|
||||||
|
* As such, you will not mormally hold this map in a variable of type <code>Map</code>.
|
||||||
|
* The normal map methods take in and return a {@link MultiKey}.
|
||||||
|
* <p>
|
||||||
|
* As an example, consider a cache that uses a String airline code and a Locale
|
||||||
|
* to lookup the airline's name:
|
||||||
|
* <pre>
|
||||||
|
* public String getAirlineName(String code, String locale) {
|
||||||
|
* MultiKeyMap cache = getCache();
|
||||||
|
* String name = (String) cache.get(code, locale);
|
||||||
|
* if (name == null) {
|
||||||
|
* name = getAirlineNameFromDB(code, locale);
|
||||||
|
* cache.put(code, locale, name);
|
||||||
|
* }
|
||||||
|
* return name;
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @since Commons Collections 3.1
|
||||||
|
* @version $Revision: 1.1 $ $Date: 2004/04/12 12:05:30 $
|
||||||
|
*
|
||||||
|
* @author Stephen Colebourne
|
||||||
|
*/
|
||||||
|
public class MultiKeyMap
|
||||||
|
extends AbstractHashedMap implements Serializable, Cloneable {
|
||||||
|
|
||||||
|
/** Serialisation version */
|
||||||
|
private static final long serialVersionUID = -1788199231038721040L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new empty map with default size and load factor.
|
||||||
|
*/
|
||||||
|
public MultiKeyMap() {
|
||||||
|
super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new, empty map with the specified initial capacity.
|
||||||
|
*
|
||||||
|
* @param initialCapacity the initial capacity
|
||||||
|
* @throws IllegalArgumentException if the initial capacity is less than one
|
||||||
|
*/
|
||||||
|
public MultiKeyMap(int initialCapacity) {
|
||||||
|
super(initialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new, empty map with the specified initial capacity and
|
||||||
|
* load factor.
|
||||||
|
*
|
||||||
|
* @param initialCapacity the initial capacity
|
||||||
|
* @param loadFactor the load factor
|
||||||
|
* @throws IllegalArgumentException if the initial capacity is less than one
|
||||||
|
* @throws IllegalArgumentException if the load factor is less than zero
|
||||||
|
*/
|
||||||
|
public MultiKeyMap(int initialCapacity, float loadFactor) {
|
||||||
|
super(initialCapacity, loadFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor copying elements from another map.
|
||||||
|
*
|
||||||
|
* @param map the map to copy
|
||||||
|
* @throws NullPointerException if the map is null
|
||||||
|
*/
|
||||||
|
public MultiKeyMap(Map map) {
|
||||||
|
super(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Clones the map without cloning the keys or values.
|
||||||
|
*
|
||||||
|
* @return a shallow clone
|
||||||
|
*/
|
||||||
|
public Object clone() {
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the map out using a custom routine.
|
||||||
|
*/
|
||||||
|
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||||
|
out.defaultWriteObject();
|
||||||
|
doWriteObject(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the map in using a custom routine.
|
||||||
|
*/
|
||||||
|
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
in.defaultReadObject();
|
||||||
|
doReadObject(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Gets the value mapped to the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @return the mapped value, null if no match
|
||||||
|
*/
|
||||||
|
public Object get(Object key1, Object key2) {
|
||||||
|
int hashCode = hash(key1, key2);
|
||||||
|
HashEntry entry = data[hashIndex(hashCode, data.length)];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
|
||||||
|
return entry.getValue();
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the map contains the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @return true if the map contains the key
|
||||||
|
*/
|
||||||
|
public boolean containsKey(Object key1, Object key2) {
|
||||||
|
int hashCode = hash(key1, key2);
|
||||||
|
HashEntry entry = data[hashIndex(hashCode, data.length)];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the value against the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param value the value to store
|
||||||
|
* @return the value previously mapped to this combined key, null if none
|
||||||
|
*/
|
||||||
|
public Object put(Object key1, Object key2, Object value) {
|
||||||
|
int hashCode = hash(key1, key2);
|
||||||
|
int index = hashIndex(hashCode, data.length);
|
||||||
|
HashEntry entry = data[index];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
|
||||||
|
Object oldValue = entry.getValue();
|
||||||
|
updateEntry(entry, value);
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
addMapping(index, hashCode, new MultiKey(key1, key2), value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified multi-key from this map.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @return the value mapped to the removed key, null if key not in map
|
||||||
|
*/
|
||||||
|
public Object remove(Object key1, Object key2) {
|
||||||
|
int hashCode = hash(key1, key2);
|
||||||
|
int index = hashIndex(hashCode, data.length);
|
||||||
|
HashEntry entry = data[index];
|
||||||
|
HashEntry previous = null;
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
|
||||||
|
Object oldValue = entry.getValue();
|
||||||
|
removeMapping(entry, index, previous);
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
previous = entry;
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hash code for the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @return the hash code
|
||||||
|
*/
|
||||||
|
protected int hash(Object key1, Object key2) {
|
||||||
|
int h = 0;
|
||||||
|
if (key1 != null) {
|
||||||
|
h ^= key1.hashCode();
|
||||||
|
}
|
||||||
|
if (key2 != null) {
|
||||||
|
h ^= key2.hashCode();
|
||||||
|
}
|
||||||
|
h += ~(h << 9);
|
||||||
|
h ^= (h >>> 14);
|
||||||
|
h += (h << 4);
|
||||||
|
h ^= (h >>> 10);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the key equal to the combined key.
|
||||||
|
*
|
||||||
|
* @param entry the entry to compare to
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @return true if the key matches
|
||||||
|
*/
|
||||||
|
protected boolean isEqualKey(HashEntry entry, Object key1, Object key2) {
|
||||||
|
MultiKey multi = (MultiKey) entry.getKey();
|
||||||
|
return
|
||||||
|
multi.size() == 2 &&
|
||||||
|
(key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
|
||||||
|
(key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Gets the value mapped to the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @return the mapped value, null if no match
|
||||||
|
*/
|
||||||
|
public Object get(Object key1, Object key2, Object key3) {
|
||||||
|
int hashCode = hash(key1, key2, key3);
|
||||||
|
HashEntry entry = data[hashIndex(hashCode, data.length)];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
|
||||||
|
return entry.getValue();
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the map contains the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @return true if the map contains the key
|
||||||
|
*/
|
||||||
|
public boolean containsKey(Object key1, Object key2, Object key3) {
|
||||||
|
int hashCode = hash(key1, key2, key3);
|
||||||
|
HashEntry entry = data[hashIndex(hashCode, data.length)];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the value against the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param value the value to store
|
||||||
|
* @return the value previously mapped to this combined key, null if none
|
||||||
|
*/
|
||||||
|
public Object put(Object key1, Object key2, Object key3, Object value) {
|
||||||
|
int hashCode = hash(key1, key2, key3);
|
||||||
|
int index = hashIndex(hashCode, data.length);
|
||||||
|
HashEntry entry = data[index];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
|
||||||
|
Object oldValue = entry.getValue();
|
||||||
|
updateEntry(entry, value);
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
addMapping(index, hashCode, new MultiKey(key1, key2, key3), value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified multi-key from this map.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @return the value mapped to the removed key, null if key not in map
|
||||||
|
*/
|
||||||
|
public Object remove(Object key1, Object key2, Object key3) {
|
||||||
|
int hashCode = hash(key1, key2, key3);
|
||||||
|
int index = hashIndex(hashCode, data.length);
|
||||||
|
HashEntry entry = data[index];
|
||||||
|
HashEntry previous = null;
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
|
||||||
|
Object oldValue = entry.getValue();
|
||||||
|
removeMapping(entry, index, previous);
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
previous = entry;
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hash code for the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @return the hash code
|
||||||
|
*/
|
||||||
|
protected int hash(Object key1, Object key2, Object key3) {
|
||||||
|
int h = 0;
|
||||||
|
if (key1 != null) {
|
||||||
|
h ^= key1.hashCode();
|
||||||
|
}
|
||||||
|
if (key2 != null) {
|
||||||
|
h ^= key2.hashCode();
|
||||||
|
}
|
||||||
|
if (key3 != null) {
|
||||||
|
h ^= key3.hashCode();
|
||||||
|
}
|
||||||
|
h += ~(h << 9);
|
||||||
|
h ^= (h >>> 14);
|
||||||
|
h += (h << 4);
|
||||||
|
h ^= (h >>> 10);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the key equal to the combined key.
|
||||||
|
*
|
||||||
|
* @param entry the entry to compare to
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @return true if the key matches
|
||||||
|
*/
|
||||||
|
protected boolean isEqualKey(HashEntry entry, Object key1, Object key2, Object key3) {
|
||||||
|
MultiKey multi = (MultiKey) entry.getKey();
|
||||||
|
return
|
||||||
|
multi.size() == 3 &&
|
||||||
|
(key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
|
||||||
|
(key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
|
||||||
|
(key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Gets the value mapped to the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @return the mapped value, null if no match
|
||||||
|
*/
|
||||||
|
public Object get(Object key1, Object key2, Object key3, Object key4) {
|
||||||
|
int hashCode = hash(key1, key2, key3, key4);
|
||||||
|
HashEntry entry = data[hashIndex(hashCode, data.length)];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
|
||||||
|
return entry.getValue();
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the map contains the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @return true if the map contains the key
|
||||||
|
*/
|
||||||
|
public boolean containsKey(Object key1, Object key2, Object key3, Object key4) {
|
||||||
|
int hashCode = hash(key1, key2, key3, key4);
|
||||||
|
HashEntry entry = data[hashIndex(hashCode, data.length)];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the value against the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @param value the value to store
|
||||||
|
* @return the value previously mapped to this combined key, null if none
|
||||||
|
*/
|
||||||
|
public Object put(Object key1, Object key2, Object key3, Object key4, Object value) {
|
||||||
|
int hashCode = hash(key1, key2, key3, key4);
|
||||||
|
int index = hashIndex(hashCode, data.length);
|
||||||
|
HashEntry entry = data[index];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
|
||||||
|
Object oldValue = entry.getValue();
|
||||||
|
updateEntry(entry, value);
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
addMapping(index, hashCode, new MultiKey(key1, key2, key3, key4), value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified multi-key from this map.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @return the value mapped to the removed key, null if key not in map
|
||||||
|
*/
|
||||||
|
public Object remove(Object key1, Object key2, Object key3, Object key4) {
|
||||||
|
int hashCode = hash(key1, key2, key3, key4);
|
||||||
|
int index = hashIndex(hashCode, data.length);
|
||||||
|
HashEntry entry = data[index];
|
||||||
|
HashEntry previous = null;
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
|
||||||
|
Object oldValue = entry.getValue();
|
||||||
|
removeMapping(entry, index, previous);
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
previous = entry;
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hash code for the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @return the hash code
|
||||||
|
*/
|
||||||
|
protected int hash(Object key1, Object key2, Object key3, Object key4) {
|
||||||
|
int h = 0;
|
||||||
|
if (key1 != null) {
|
||||||
|
h ^= key1.hashCode();
|
||||||
|
}
|
||||||
|
if (key2 != null) {
|
||||||
|
h ^= key2.hashCode();
|
||||||
|
}
|
||||||
|
if (key3 != null) {
|
||||||
|
h ^= key3.hashCode();
|
||||||
|
}
|
||||||
|
if (key4 != null) {
|
||||||
|
h ^= key4.hashCode();
|
||||||
|
}
|
||||||
|
h += ~(h << 9);
|
||||||
|
h ^= (h >>> 14);
|
||||||
|
h += (h << 4);
|
||||||
|
h ^= (h >>> 10);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the key equal to the combined key.
|
||||||
|
*
|
||||||
|
* @param entry the entry to compare to
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @return true if the key matches
|
||||||
|
*/
|
||||||
|
protected boolean isEqualKey(HashEntry entry, Object key1, Object key2, Object key3, Object key4) {
|
||||||
|
MultiKey multi = (MultiKey) entry.getKey();
|
||||||
|
return
|
||||||
|
multi.size() == 4 &&
|
||||||
|
(key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
|
||||||
|
(key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
|
||||||
|
(key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) &&
|
||||||
|
(key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Gets the value mapped to the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @param key5 the fifth key
|
||||||
|
* @return the mapped value, null if no match
|
||||||
|
*/
|
||||||
|
public Object get(Object key1, Object key2, Object key3, Object key4, Object key5) {
|
||||||
|
int hashCode = hash(key1, key2, key3, key4, key5);
|
||||||
|
HashEntry entry = data[hashIndex(hashCode, data.length)];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
|
||||||
|
return entry.getValue();
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the map contains the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @param key5 the fifth key
|
||||||
|
* @return true if the map contains the key
|
||||||
|
*/
|
||||||
|
public boolean containsKey(Object key1, Object key2, Object key3, Object key4, Object key5) {
|
||||||
|
int hashCode = hash(key1, key2, key3, key4, key5);
|
||||||
|
HashEntry entry = data[hashIndex(hashCode, data.length)];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the value against the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @param key5 the fifth key
|
||||||
|
* @param value the value to store
|
||||||
|
* @return the value previously mapped to this combined key, null if none
|
||||||
|
*/
|
||||||
|
public Object put(Object key1, Object key2, Object key3, Object key4, Object key5, Object value) {
|
||||||
|
int hashCode = hash(key1, key2, key3, key4, key5);
|
||||||
|
int index = hashIndex(hashCode, data.length);
|
||||||
|
HashEntry entry = data[index];
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
|
||||||
|
Object oldValue = entry.getValue();
|
||||||
|
updateEntry(entry, value);
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
addMapping(index, hashCode, new MultiKey(key1, key2, key3, key4, key5), value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified multi-key from this map.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @param key5 the fifth key
|
||||||
|
* @return the value mapped to the removed key, null if key not in map
|
||||||
|
*/
|
||||||
|
public Object remove(Object key1, Object key2, Object key3, Object key4, Object key5) {
|
||||||
|
int hashCode = hash(key1, key2, key3, key4, key5);
|
||||||
|
int index = hashIndex(hashCode, data.length);
|
||||||
|
HashEntry entry = data[index];
|
||||||
|
HashEntry previous = null;
|
||||||
|
while (entry != null) {
|
||||||
|
if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
|
||||||
|
Object oldValue = entry.getValue();
|
||||||
|
removeMapping(entry, index, previous);
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
previous = entry;
|
||||||
|
entry = entry.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hash code for the specified multi-key.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @param key5 the fifth key
|
||||||
|
* @return the hash code
|
||||||
|
*/
|
||||||
|
protected int hash(Object key1, Object key2, Object key3, Object key4, Object key5) {
|
||||||
|
int h = 0;
|
||||||
|
if (key1 != null) {
|
||||||
|
h ^= key1.hashCode();
|
||||||
|
}
|
||||||
|
if (key2 != null) {
|
||||||
|
h ^= key2.hashCode();
|
||||||
|
}
|
||||||
|
if (key3 != null) {
|
||||||
|
h ^= key3.hashCode();
|
||||||
|
}
|
||||||
|
if (key4 != null) {
|
||||||
|
h ^= key4.hashCode();
|
||||||
|
}
|
||||||
|
if (key5 != null) {
|
||||||
|
h ^= key5.hashCode();
|
||||||
|
}
|
||||||
|
h += ~(h << 9);
|
||||||
|
h ^= (h >>> 14);
|
||||||
|
h += (h << 4);
|
||||||
|
h ^= (h >>> 10);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the key equal to the combined key.
|
||||||
|
*
|
||||||
|
* @param entry the entry to compare to
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @param key5 the fifth key
|
||||||
|
* @return true if the key matches
|
||||||
|
*/
|
||||||
|
protected boolean isEqualKey(HashEntry entry, Object key1, Object key2, Object key3, Object key4, Object key5) {
|
||||||
|
MultiKey multi = (MultiKey) entry.getKey();
|
||||||
|
return
|
||||||
|
multi.size() == 5 &&
|
||||||
|
(key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
|
||||||
|
(key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
|
||||||
|
(key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) &&
|
||||||
|
(key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3))) &&
|
||||||
|
(key5 == null ? multi.getKey(4) == null : key5.equals(multi.getKey(4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Removes all mappings where the first key is that specified.
|
||||||
|
* <p>
|
||||||
|
* This method removes all the mappings where the <code>MultiKey</code>
|
||||||
|
* has one or more keys, and the first matches that specified.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @return true if any elements were removed
|
||||||
|
*/
|
||||||
|
public boolean removeAll(Object key1) {
|
||||||
|
boolean modified = false;
|
||||||
|
MapIterator it = mapIterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
MultiKey multi = (MultiKey) it.next();
|
||||||
|
if (multi.size() >= 1 &&
|
||||||
|
(key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0)))) {
|
||||||
|
it.remove();
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all mappings where the first two keys are those specified.
|
||||||
|
* <p>
|
||||||
|
* This method removes all the mappings where the <code>MultiKey</code>
|
||||||
|
* has two or more keys, and the first two match those specified.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @return true if any elements were removed
|
||||||
|
*/
|
||||||
|
public boolean removeAll(Object key1, Object key2) {
|
||||||
|
boolean modified = false;
|
||||||
|
MapIterator it = mapIterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
MultiKey multi = (MultiKey) it.next();
|
||||||
|
if (multi.size() >= 2 &&
|
||||||
|
(key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
|
||||||
|
(key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1)))) {
|
||||||
|
it.remove();
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all mappings where the first three keys are those specified.
|
||||||
|
* <p>
|
||||||
|
* This method removes all the mappings where the <code>MultiKey</code>
|
||||||
|
* has three or more keys, and the first three match those specified.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @return true if any elements were removed
|
||||||
|
*/
|
||||||
|
public boolean removeAll(Object key1, Object key2, Object key3) {
|
||||||
|
boolean modified = false;
|
||||||
|
MapIterator it = mapIterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
MultiKey multi = (MultiKey) it.next();
|
||||||
|
if (multi.size() >= 3 &&
|
||||||
|
(key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
|
||||||
|
(key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
|
||||||
|
(key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2)))) {
|
||||||
|
it.remove();
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all mappings where the first four keys are those specified.
|
||||||
|
* <p>
|
||||||
|
* This method removes all the mappings where the <code>MultiKey</code>
|
||||||
|
* has four or more keys, and the first four match those specified.
|
||||||
|
*
|
||||||
|
* @param key1 the first key
|
||||||
|
* @param key2 the second key
|
||||||
|
* @param key3 the third key
|
||||||
|
* @param key4 the fourth key
|
||||||
|
* @return true if any elements were removed
|
||||||
|
*/
|
||||||
|
public boolean removeAll(Object key1, Object key2, Object key3, Object key4) {
|
||||||
|
boolean modified = false;
|
||||||
|
MapIterator it = mapIterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
MultiKey multi = (MultiKey) it.next();
|
||||||
|
if (multi.size() >= 4 &&
|
||||||
|
(key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
|
||||||
|
(key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
|
||||||
|
(key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) &&
|
||||||
|
(key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3)))) {
|
||||||
|
it.remove();
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Override superclass to ensure that input keys are valid MultiKey objects.
|
||||||
|
*
|
||||||
|
* @param key the key to check
|
||||||
|
* @return the validated key
|
||||||
|
*/
|
||||||
|
protected Object convertKey(Object key) {
|
||||||
|
if (key == null) {
|
||||||
|
throw new NullPointerException("Key must not be null");
|
||||||
|
}
|
||||||
|
if (key instanceof MultiKey == false) {
|
||||||
|
throw new ClassCastException("Key must be a MultiKey");
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ import junit.framework.TestSuite;
|
||||||
* Entry point for tests.
|
* Entry point for tests.
|
||||||
*
|
*
|
||||||
* @since Commons Collections 3.0
|
* @since Commons Collections 3.0
|
||||||
* @version $Revision: 1.16 $ $Date: 2004/04/10 21:24:21 $
|
* @version $Revision: 1.17 $ $Date: 2004/04/12 12:05:29 $
|
||||||
*
|
*
|
||||||
* @author Stephen Colebourne
|
* @author Stephen Colebourne
|
||||||
*/
|
*/
|
||||||
|
@ -48,6 +48,7 @@ public class TestAll extends TestCase {
|
||||||
suite.addTest(TestIdentityMap.suite());
|
suite.addTest(TestIdentityMap.suite());
|
||||||
suite.addTest(TestLinkedMap.suite());
|
suite.addTest(TestLinkedMap.suite());
|
||||||
suite.addTest(TestLRUMap.suite());
|
suite.addTest(TestLRUMap.suite());
|
||||||
|
suite.addTest(TestMultiKeyMap.suite());
|
||||||
suite.addTest(TestReferenceMap.suite());
|
suite.addTest(TestReferenceMap.suite());
|
||||||
suite.addTest(TestStaticBucketMap.suite());
|
suite.addTest(TestStaticBucketMap.suite());
|
||||||
suite.addTest(TestSingletonMap.suite());
|
suite.addTest(TestSingletonMap.suite());
|
||||||
|
|
|
@ -0,0 +1,407 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2004 The Apache Software Foundation
|
||||||
|
*
|
||||||
|
* Licensed 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.map;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.textui.TestRunner;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.BulkTest;
|
||||||
|
import org.apache.commons.collections.MapIterator;
|
||||||
|
import org.apache.commons.collections.keyvalue.MultiKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JUnit tests.
|
||||||
|
*
|
||||||
|
* @version $Revision: 1.1 $ $Date: 2004/04/12 12:05:30 $
|
||||||
|
*
|
||||||
|
* @author Stephen Colebourne
|
||||||
|
*/
|
||||||
|
public class TestMultiKeyMap extends AbstractTestIterableMap {
|
||||||
|
|
||||||
|
static final Integer I1 = new Integer(1);
|
||||||
|
static final Integer I2 = new Integer(2);
|
||||||
|
static final Integer I3 = new Integer(3);
|
||||||
|
static final Integer I4 = new Integer(4);
|
||||||
|
static final Integer I5 = new Integer(5);
|
||||||
|
static final Integer I6 = new Integer(6);
|
||||||
|
static final Integer I7 = new Integer(7);
|
||||||
|
static final Integer I8 = new Integer(8);
|
||||||
|
|
||||||
|
public TestMultiKeyMap(String testName) {
|
||||||
|
super(testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
TestRunner.run(suite());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() {
|
||||||
|
return BulkTest.makeSuite(TestMultiKeyMap.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map makeEmptyMap() {
|
||||||
|
return new MultiKeyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getSampleKeys() {
|
||||||
|
return getMultiKeyKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MultiKey[] getMultiKeyKeys() {
|
||||||
|
return new MultiKey[] {
|
||||||
|
new MultiKey(I1, I2),
|
||||||
|
new MultiKey(I2, I3),
|
||||||
|
new MultiKey(I3, I4),
|
||||||
|
new MultiKey(I1, I1, I2),
|
||||||
|
new MultiKey(I2, I3, I4),
|
||||||
|
new MultiKey(I3, I7, I6),
|
||||||
|
new MultiKey(I1, I1, I2, I3),
|
||||||
|
new MultiKey(I2, I4, I5, I6),
|
||||||
|
new MultiKey(I3, I6, I7, I8),
|
||||||
|
new MultiKey(I1, I1, I2, I3, I4),
|
||||||
|
new MultiKey(I2, I3, I4, I5, I6),
|
||||||
|
new MultiKey(I3, I5, I6, I7, I8),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getSampleValues() {
|
||||||
|
return new Object[] {
|
||||||
|
"2A", "2B", "2C",
|
||||||
|
"3D", "3E", "3F",
|
||||||
|
"4G", "4H", "4I",
|
||||||
|
"5J", "5K", "5L",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getNewSampleValues() {
|
||||||
|
return new Object[] {
|
||||||
|
"1a", "1b", "1c",
|
||||||
|
"2d", "2e", "2f",
|
||||||
|
"3g", "3h", "3i",
|
||||||
|
"4j", "4k", "4l",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getOtherKeys() {
|
||||||
|
return new Object[] {
|
||||||
|
new MultiKey(I1, I7),
|
||||||
|
new MultiKey(I1, I8),
|
||||||
|
new MultiKey(I2, I4),
|
||||||
|
new MultiKey(I2, I5),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllowNullKey() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
public void testMultiKeyGet() {
|
||||||
|
resetFull();
|
||||||
|
MultiKeyMap multimap = (MultiKeyMap) map;
|
||||||
|
MultiKey[] keys = getMultiKeyKeys();
|
||||||
|
Object[] values = getSampleValues();
|
||||||
|
|
||||||
|
for (int i = 0; i < keys.length; i++) {
|
||||||
|
MultiKey key = keys[i];
|
||||||
|
Object value = values[i];
|
||||||
|
|
||||||
|
switch (key.size()) {
|
||||||
|
case 2:
|
||||||
|
assertEquals(value, multimap.get(key.getKey(0), key.getKey(1)));
|
||||||
|
assertEquals(null, multimap.get(null, key.getKey(1)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), null));
|
||||||
|
assertEquals(null, multimap.get(null, null));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null, null));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null, null, null));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(null, multimap.get(null, key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), null, key.getKey(2)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null));
|
||||||
|
assertEquals(null, multimap.get(null, null, null));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null, null));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(null, multimap.get(null, key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), null, key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null, key.getKey(3)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null));
|
||||||
|
assertEquals(null, multimap.get(null, null, null, null));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(null, multimap.get(null, key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), null, key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null, key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null, key.getKey(4)));
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
|
||||||
|
assertEquals(null, multimap.get(null, null, null, null, null));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fail("Invalid key size");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiKeyContainsKey() {
|
||||||
|
resetFull();
|
||||||
|
MultiKeyMap multimap = (MultiKeyMap) map;
|
||||||
|
MultiKey[] keys = getMultiKeyKeys();
|
||||||
|
Object[] values = getSampleValues();
|
||||||
|
|
||||||
|
for (int i = 0; i < keys.length; i++) {
|
||||||
|
MultiKey key = keys[i];
|
||||||
|
Object value = values[i];
|
||||||
|
|
||||||
|
switch (key.size()) {
|
||||||
|
case 2:
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1)));
|
||||||
|
assertEquals(false, multimap.containsKey(null, key.getKey(1)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), null));
|
||||||
|
assertEquals(false, multimap.containsKey(null, null));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null, null));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null, null, null));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(false, multimap.containsKey(null, key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), null, key.getKey(2)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null));
|
||||||
|
assertEquals(false, multimap.containsKey(null, null, null));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null, null));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(false, multimap.containsKey(null, key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), null, key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null, key.getKey(3)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null));
|
||||||
|
assertEquals(false, multimap.containsKey(null, null, null, null));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(false, multimap.containsKey(null, key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), null, key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null, key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null, key.getKey(4)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
|
||||||
|
assertEquals(false, multimap.containsKey(null, null, null, null, null));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fail("Invalid key size");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiKeyPut() {
|
||||||
|
MultiKey[] keys = getMultiKeyKeys();
|
||||||
|
Object[] values = getSampleValues();
|
||||||
|
|
||||||
|
for (int i = 0; i < keys.length; i++) {
|
||||||
|
MultiKeyMap multimap = new MultiKeyMap();
|
||||||
|
|
||||||
|
MultiKey key = keys[i];
|
||||||
|
Object value = values[i];
|
||||||
|
|
||||||
|
switch (key.size()) {
|
||||||
|
case 2:
|
||||||
|
assertEquals(null, multimap.put(key.getKey(0), key.getKey(1), value));
|
||||||
|
assertEquals(1, multimap.size());
|
||||||
|
assertEquals(value, multimap.get(key.getKey(0), key.getKey(1)));
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1)));
|
||||||
|
assertEquals(true, multimap.containsKey(new MultiKey(key.getKey(0), key.getKey(1))));
|
||||||
|
assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), null));
|
||||||
|
assertEquals(1, multimap.size());
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1)));
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1)));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
assertEquals(null, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), value));
|
||||||
|
assertEquals(1, multimap.size());
|
||||||
|
assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(true, multimap.containsKey(new MultiKey(key.getKey(0), key.getKey(1), key.getKey(2))));
|
||||||
|
assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), null));
|
||||||
|
assertEquals(1, multimap.size());
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
assertEquals(null, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), value));
|
||||||
|
assertEquals(1, multimap.size());
|
||||||
|
assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(true, multimap.containsKey(new MultiKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3))));
|
||||||
|
assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
|
||||||
|
assertEquals(1, multimap.size());
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
assertEquals(null, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4), value));
|
||||||
|
assertEquals(1, multimap.size());
|
||||||
|
assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(true, multimap.containsKey(new MultiKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4))));
|
||||||
|
assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4), null));
|
||||||
|
assertEquals(1, multimap.size());
|
||||||
|
assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fail("Invalid key size");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiKeyRemove() {
|
||||||
|
MultiKey[] keys = getMultiKeyKeys();
|
||||||
|
Object[] values = getSampleValues();
|
||||||
|
|
||||||
|
for (int i = 0; i < keys.length; i++) {
|
||||||
|
resetFull();
|
||||||
|
MultiKeyMap multimap = (MultiKeyMap) map;
|
||||||
|
int size = multimap.size();
|
||||||
|
|
||||||
|
MultiKey key = keys[i];
|
||||||
|
Object value = values[i];
|
||||||
|
|
||||||
|
switch (key.size()) {
|
||||||
|
case 2:
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1)));
|
||||||
|
assertEquals(value, multimap.remove(key.getKey(0), key.getKey(1)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1)));
|
||||||
|
assertEquals(size - 1, multimap.size());
|
||||||
|
assertEquals(null, multimap.remove(key.getKey(0), key.getKey(1)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1)));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(value, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(size - 1, multimap.size());
|
||||||
|
assertEquals(null, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(value, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(size - 1, multimap.size());
|
||||||
|
assertEquals(null, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(value, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(size - 1, multimap.size());
|
||||||
|
assertEquals(null, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fail("Invalid key size");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiKeyRemoveAll1() {
|
||||||
|
resetFull();
|
||||||
|
MultiKeyMap multimap = (MultiKeyMap) map;
|
||||||
|
assertEquals(12, multimap.size());
|
||||||
|
|
||||||
|
multimap.removeAll(I1);
|
||||||
|
assertEquals(8, multimap.size());
|
||||||
|
for (MapIterator it = multimap.mapIterator(); it.hasNext();) {
|
||||||
|
MultiKey key = (MultiKey) it.next();
|
||||||
|
assertEquals(false, I1.equals(key.getKey(0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiKeyRemoveAll2() {
|
||||||
|
resetFull();
|
||||||
|
MultiKeyMap multimap = (MultiKeyMap) map;
|
||||||
|
assertEquals(12, multimap.size());
|
||||||
|
|
||||||
|
multimap.removeAll(I2, I3);
|
||||||
|
assertEquals(9, multimap.size());
|
||||||
|
for (MapIterator it = multimap.mapIterator(); it.hasNext();) {
|
||||||
|
MultiKey key = (MultiKey) it.next();
|
||||||
|
assertEquals(false, I2.equals(key.getKey(0)) && I3.equals(key.getKey(1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiKeyRemoveAll3() {
|
||||||
|
resetFull();
|
||||||
|
MultiKeyMap multimap = (MultiKeyMap) map;
|
||||||
|
assertEquals(12, multimap.size());
|
||||||
|
|
||||||
|
multimap.removeAll(I1, I1, I2);
|
||||||
|
assertEquals(9, multimap.size());
|
||||||
|
for (MapIterator it = multimap.mapIterator(); it.hasNext();) {
|
||||||
|
MultiKey key = (MultiKey) it.next();
|
||||||
|
assertEquals(false, I1.equals(key.getKey(0)) && I1.equals(key.getKey(1)) && I2.equals(key.getKey(2)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiKeyRemoveAll4() {
|
||||||
|
resetFull();
|
||||||
|
MultiKeyMap multimap = (MultiKeyMap) map;
|
||||||
|
assertEquals(12, multimap.size());
|
||||||
|
|
||||||
|
multimap.removeAll(I1, I1, I2, I3);
|
||||||
|
assertEquals(10, multimap.size());
|
||||||
|
for (MapIterator it = multimap.mapIterator(); it.hasNext();) {
|
||||||
|
MultiKey key = (MultiKey) it.next();
|
||||||
|
assertEquals(false, I1.equals(key.getKey(0)) && I1.equals(key.getKey(1)) && I2.equals(key.getKey(2)) && key.size() >= 4 && I3.equals(key.getKey(3)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
public void testClone() {
|
||||||
|
MultiKeyMap map = new MultiKeyMap();
|
||||||
|
map.put(new MultiKey(I1, I2), "1-2");
|
||||||
|
Map cloned = (Map) map.clone();
|
||||||
|
assertEquals(map.size(), cloned.size());
|
||||||
|
assertSame(map.get(new MultiKey(I1, I2)), cloned.get(new MultiKey(I1, I2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCompatibilityVersion() {
|
||||||
|
return "3.1";
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void testCreate() throws Exception {
|
||||||
|
// resetEmpty();
|
||||||
|
// writeExternalFormToDisk(
|
||||||
|
// (java.io.Serializable) map,
|
||||||
|
// "D:/dev/collections/data/test/MultiKeyMap.emptyCollection.version3.1.obj");
|
||||||
|
// resetFull();
|
||||||
|
// writeExternalFormToDisk(
|
||||||
|
// (java.io.Serializable) map,
|
||||||
|
// "D:/dev/collections/data/test/MultiKeyMap.fullCollection.version3.1.obj");
|
||||||
|
// }
|
||||||
|
}
|
Loading…
Reference in New Issue