blob: fcf28ac548dfca82045e57105f92ea35d782cccc [file] [log] [blame]
package aQute.lib.collections;
import java.util.*;
public class MultiMap<K,V> extends HashMap<K,List<V>> {
private static final long serialVersionUID = 1L;
final boolean noduplicates;
final Class<?> keyClass;
final Class<?> valueClass;
final Set<V> EMPTY = Collections.emptySet();
public MultiMap() {
noduplicates = false;
keyClass = Object.class;
valueClass = Object.class;
}
public MultiMap(Class<K> keyClass, Class<V> valueClass, boolean noduplicates ) {
this.noduplicates = noduplicates;
this.keyClass = keyClass;
this.valueClass = valueClass;
}
@SuppressWarnings("unchecked") public boolean add( K key, V value ) {
assert keyClass.isInstance(key);
assert valueClass.isInstance(value);
List<V> set = get(key);
if ( set == null) {
set=new ArrayList<V>();
if ( valueClass != Object.class) {
set = Collections.checkedList(set, (Class<V>)valueClass);
}
put(key,set);
}else {
if (noduplicates) {
if ( set.contains(value))
return false;
}
}
return set.add(value);
}
@SuppressWarnings("unchecked") public boolean addAll( K key, Collection<? extends V> value ) {
assert keyClass.isInstance(key);
List<V> set = get(key);
if ( set == null) {
set=new ArrayList<V>();
if ( valueClass != Object.class) {
set = Collections.checkedList(set, (Class<V>)valueClass);
}
put(key,set);
} else
if ( noduplicates) {
boolean r=false;
for ( V v : value) {
assert valueClass.isInstance(v);
if ( !set.contains(value))
r|=set.add(v);
}
return r;
}
return set.addAll(value);
}
public boolean remove( K key, V value ) {
assert keyClass.isInstance(key);
assert valueClass.isInstance(value);
List<V> set = get(key);
if ( set == null) {
return false;
}
boolean result = set.remove(value);
if ( set.isEmpty())
remove(key);
return result;
}
public boolean removeAll( K key, Collection<V> value ) {
assert keyClass.isInstance(key);
List<V> set = get(key);
if ( set == null) {
return false;
}
boolean result = set.removeAll(value);
if ( set.isEmpty())
remove(key);
return result;
}
public Iterator<V> iterate(K key) {
assert keyClass.isInstance(key);
List<V> set = get(key);
if ( set == null)
return EMPTY.iterator();
return set.iterator();
}
public Iterator<V> all() {
return new Iterator<V>() {
Iterator<List<V>> master = values().iterator();
Iterator<V> current = null;
public boolean hasNext() {
if ( current == null || !current.hasNext()) {
if ( master.hasNext()) {
current = master.next().iterator();
return current.hasNext();
}
return false;
}
return true;
}
public V next() {
return current.next();
}
public void remove() {
current.remove();
}
};
}
public Map<K,V> flatten() {
Map<K,V> map = new LinkedHashMap<K,V>();
for ( Map.Entry<K, List<V>> entry : entrySet()) {
List<V> v = entry.getValue();
if ( v == null || v.isEmpty())
continue;
map.put(entry.getKey(), v.get(0));
}
return map;
}
public MultiMap<V,K> transpose() {
MultiMap<V,K> inverted = new MultiMap<V,K>();
for ( Map.Entry<K, List<V>> entry : entrySet()) {
K key = entry.getKey();
List<V> value = entry.getValue();
if ( value == null)
continue;
for ( V v : value)
inverted.add(v, key);
}
return inverted;
}
}