/*
* ModeShape (http://www.modeshape.org)
*
* 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.modeshape.common.collection;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
/**
* A {@link Multimap} implementation that uses an {@link ArrayList} to store the values associated with a key. This implementation
* allows duplicates.
*
* @param <K> the key type
* @param <V> the value type
*/
public abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
private final Map<K, Collection<V>> data;
private int totalSize;
private transient Set<K> keysView;
private transient Map<K, Collection<V>> mapView;
private transient Collection<V> valuesCollection;
private transient Collection<Map.Entry<K, V>> entriesCollection;
protected AbstractMultimap( Map<K, Collection<V>> entries ) {
assert entries != null;
this.data = entries;
}
protected Map<K, Collection<V>> rawData() {
return data;
}
protected abstract Collection<V> createCollection();
protected abstract Collection<V> createUnmodifiableEmptyCollection();
@SuppressWarnings( {"unchecked", "rawtypes"} )
protected Collection<V> createUnmodifiable( Collection<V> original ) {
if (original instanceof List) {
return Collections.unmodifiableList((List)original);
} else if (original instanceof Set) {
return Collections.unmodifiableSet((Set)original);
}
return Collections.unmodifiableCollection(original);
}
@Override
public int size() {
return totalSize;
}
void incrementSize( int n ) {
totalSize += n;
}
void decrementSize( int n ) {
totalSize -= n;
assert totalSize >= 0;
}
@Override
public boolean isEmpty() {
return totalSize == 0;
}
@Override
public boolean containsKey( K key ) {
return data.containsKey(key);
}
@Override
public boolean containsValue( Object value ) {
for (Collection<V> collection : data.values()) {
if (collection.contains(value)) return true;
}
return false;
}
@Override
public boolean containsEntry( Object key,
Object value ) {
Collection<V> values = data.get(key);
return values == null ? false : values.contains(value);
}
@Override
public java.util.Collection<V> get( K key ) {
Collection<V> collection = data.get(key);
if (collection == null) {
collection = createCollection();
}
return wrapCollection(key, collection);
}
@Override
public boolean put( K key,
V value ) {
if (getOrCreateCollection(key).add(value)) {
incrementSize(1);
return true;
}
return false;
}
protected Collection<V> getOrCreateCollection( K key ) {
Collection<V> values = data.get(key);
if (values == null) {
values = createCollection();
data.put(key, values);
}
return values;
}
@Override
public boolean remove( K key,
V value ) {
Collection<V> values = data.get(key);
if (values == null) return false;
if (!values.remove(value)) return false;
decrementSize(1);
if (values.isEmpty()) {
data.remove(key);
}
return true;
}
@Override
public java.util.Collection<V> removeAll( K key ) {
Collection<V> values = data.remove(key);
if (values == null) return createUnmodifiableEmptyCollection();
Collection<V> copy = createCollection();
copy.addAll(values);
decrementSize(values.size());
values.clear();
return createUnmodifiable(copy);
}
protected boolean removeAllValuesForKey( Object key ) {
Collection<V> values = data.remove(key);
if (values == null) return false;
decrementSize(values.size());
values.clear();
return true;
}
@Override
public int hashCode() {
return data.hashCode();
}
@Override
public boolean equals( Object obj ) {
if (obj == this) return true;
return data.equals(obj);
}
@Override
public String toString() {
return data.toString();
}
@Override
public Set<K> keySet() {
if (keysView == null) keysView = wrapKeySet();
return keysView;
}
@Override
public void clear() {
totalSize = 0;
data.clear();
}
@Override
public Map<K, Collection<V>> asMap() {
if (mapView == null) mapView = wrapMap(data);
return mapView;
}
/**
* Return an iterator over all entries in this multimap.
*
* @return the entry iterator; never null
*/
protected Iterator<Map.Entry<K, V>> createEntryIterator() {
return new EntryIterator();
}
protected Collection<V> wrapCollection( K key,
Collection<V> values ) {
// if (values instanceof Set) {
// return new WrappedSet(key, (Set<V>)values);
// } else
if (values instanceof List) {
return wrapList(key, (List<V>)values);
}
return new WrappedCollection(key, values);
}
protected List<V> wrapList( K key,
List<V> values ) {
return new WrappedList(key, values);
}
protected Map<K, Collection<V>> wrapMap( Map<K, Collection<V>> map ) {
return new WrappedMap(map);
}
protected Set<K> wrapKeySet() {
if (data instanceof SortedMap) {
return new WrappedSortedKeySet((SortedMap<K, Collection<V>>)data);
}
return new WrappedKeySet(data);
}
@Override
public Collection<V> values() {
if (valuesCollection == null) valuesCollection = new ValuesCollection();
return valuesCollection;
}
protected final class ValuesCollection extends AbstractCollection<V> {
@Override
public int size() {
return AbstractMultimap.this.size();
}
@Override
public Iterator<V> iterator() {
return new ValueIterator();
}
@Override
public void clear() {
AbstractMultimap.this.clear();
}
@Override
public boolean contains( Object o ) {
return AbstractMultimap.this.containsValue(o);
}
}
protected final class ValueIterator implements Iterator<V> {
private final Iterator<Map.Entry<K, V>> entryIterator = createEntryIterator();
@Override
public boolean hasNext() {
return entryIterator.hasNext();
}
@Override
public V next() {
return entryIterator.next().getValue();
}
@Override
public void remove() {
entryIterator.remove();
}
}
@Override
public Collection<Entry<K, V>> entries() {
if (entriesCollection == null) entriesCollection = new EntriesCollection();
return entriesCollection;
}
protected final class EntryIterator implements Iterator<Map.Entry<K, V>> {
private final Iterator<Map.Entry<K, Collection<V>>> iter;
protected K currentKey;
protected Collection<V> currentValues;
protected Iterator<V> currentValuesIterator;
EntryIterator() {
iter = rawData().entrySet().iterator();
if (iter.hasNext()) {
nextKey();
} else {
currentValuesIterator = new EmptyIterator<V>();
}
}
protected void nextKey() {
Map.Entry<K, Collection<V>> entry = iter.next();
currentKey = entry.getKey();
currentValues = entry.getValue();
currentValuesIterator = currentValues.iterator();
}
@Override
public boolean hasNext() {
return iter.hasNext() || currentValuesIterator.hasNext();
}
@Override
public Entry<K, V> next() {
if (!currentValuesIterator.hasNext()) {
nextKey();
}
return new ImmutableMapEntry<K, V>(currentKey, currentValuesIterator.next());
}
@SuppressWarnings( "synthetic-access" )
@Override
public void remove() {
currentValuesIterator.remove();
if (currentValues.isEmpty()) {
iter.remove();
}
--totalSize;
}
}
protected final class EntriesCollection extends AbstractCollection<Map.Entry<K, V>> {
@Override
public int size() {
return AbstractMultimap.this.size();
}
@Override
public Iterator<Map.Entry<K, V>> iterator() {
return new EntryIterator();
}
@Override
public void clear() {
AbstractMultimap.this.clear();
}
@Override
public boolean contains( Object o ) {
if (!(o instanceof Map.Entry)) return false;
Map.Entry<?, ?> that = (Map.Entry<?, ?>)o;
return AbstractMultimap.this.containsEntry(that.getKey(), that.getValue());
}
}
protected class WrappedCollection implements Collection<V> {
private Collection<V> delegate;
private final K key;
protected WrappedCollection( K key,
Collection<V> values ) {
this.key = key;
this.delegate = values;
}
public K getKey() {
return key;
}
protected Collection<V> delegate() {
if (delegate == null || delegate.isEmpty()) {
// Fetch the actual values from the multimap's raw data ...
Collection<V> rawValues = rawData().get(key);
if (rawValues != null) {
// Always use the raw values ...
delegate = rawValues;
}
}
return delegate;
}
protected final void removeIfEmpty() {
if (delegate != null && delegate.isEmpty()) {
AbstractMultimap.this.removeAll(key);
delegate = null;
}
}
protected final void addToMap() {
rawData().put(key, delegate);
}
@Override
public int size() {
return delegate().size();
}
@Override
public boolean isEmpty() {
return delegate().isEmpty();
}
@Override
public boolean contains( Object o ) {
return delegate().contains(o);
}
@Override
public Iterator<V> iterator() {
return delegate().iterator();
}
@Override
public Object[] toArray() {
// The size of the values (and thus the multimap) cannot be changed via the resulting array, so no need to wrap ...
return delegate().toArray();
}
@Override
public <T> T[] toArray( T[] a ) {
// The size of the values (and thus the multimap) cannot be changed via the resulting array, so no need to wrap ...
return delegate().toArray(a);
}
@Override
public boolean add( V e ) {
Collection<V> values = delegate();
boolean wasEmpty = values.isEmpty();
if (!values.add(e)) return false;
incrementSize(1);
if (wasEmpty) addToMap();
return true;
}
@Override
public boolean remove( Object o ) {
if (!delegate().remove(o)) return false;
decrementSize(1);
removeIfEmpty();
return true;
}
@Override
public boolean containsAll( Collection<?> c ) {
return delegate().containsAll(c);
}
@Override
public boolean addAll( Collection<? extends V> c ) {
if (c.isEmpty()) return false;
Collection<V> delegate = delegate();
int sizeBefore = delegate.size();
if (!delegate.addAll(c)) return false;
incrementSize(delegate.size() - sizeBefore);
if (sizeBefore == 0) addToMap();
return true;
}
@Override
public boolean removeAll( Collection<?> c ) {
if (c.isEmpty()) return false;
Collection<V> delegate = delegate();
int sizeBefore = delegate.size();
if (!delegate.removeAll(c)) return false;
incrementSize(delegate.size() - sizeBefore); // will be negative
removeIfEmpty();
return true;
}
@Override
public boolean retainAll( Collection<?> c ) {
if (c.isEmpty()) return false;
Collection<V> delegate = delegate();
int sizeBefore = delegate.size();
if (!delegate.retainAll(c)) return false;
int diff = delegate.size() - sizeBefore;
incrementSize(diff); // will change correctly if diff is negative
return true;
}
@Override
public void clear() {
Collection<V> delegate = delegate();
int sizeBefore = delegate.size();
delegate.clear();
decrementSize(sizeBefore);
removeIfEmpty();
}
@Override
public int hashCode() {
return delegate().hashCode();
}
@Override
public boolean equals( Object obj ) {
if (obj == this) return true;
return delegate().equals(obj);
}
@Override
public String toString() {
return delegate().toString();
}
protected class DelegateIterator implements Iterator<V> {
private final Collection<V> source;
private final Iterator<V> iterator;
protected DelegateIterator() {
source = delegate();
iterator = source instanceof List ? ((List<V>)source).listIterator() : source.iterator();
}
protected DelegateIterator( int index ) {
this.source = delegate();
iterator = source instanceof List ? ((List<V>)source).listIterator(index) : source.iterator();
}
protected Iterator<V> iterator() {
if (source != delegate()) {
throw new ConcurrentModificationException();
}
return iterator;
}
@Override
public boolean hasNext() {
return iterator().hasNext();
}
@Override
public V next() {
return iterator.next();
}
@Override
public void remove() {
iterator.remove();
decrementSize(1);
removeIfEmpty();
}
}
}
protected class WrappedList extends WrappedCollection implements List<V> {
protected WrappedList( K key,
Collection<V> values ) {
super(key, values);
}
@Override
protected List<V> delegate() {
return (List<V>)super.delegate();
}
@Override
public boolean addAll( int index,
Collection<? extends V> c ) {
if (c.isEmpty()) return false;
List<V> delegate = delegate();
int sizeBefore = delegate.size();
if (!delegate.addAll(index, c)) return false;
incrementSize(delegate.size() - sizeBefore);
if (sizeBefore == 0) addToMap();
return true;
}
@Override
public V get( int index ) {
return delegate().get(index);
}
@Override
public V set( int index,
V element ) {
return delegate().set(index, element);
}
@Override
public void add( int index,
V element ) {
List<V> values = delegate();
boolean wasEmpty = values.isEmpty();
values.add(index, element);
incrementSize(1);
if (wasEmpty) addToMap();
}
@Override
public V remove( int index ) {
V removed = delegate().remove(index);
decrementSize(1);
removeIfEmpty();
return removed;
}
@Override
public int indexOf( Object o ) {
return delegate().indexOf(o);
}
@Override
public int lastIndexOf( Object o ) {
return delegate().lastIndexOf(o);
}
@Override
public ListIterator<V> listIterator() {
return new DelegateListIterator();
}
@Override
public ListIterator<V> listIterator( int index ) {
return new DelegateListIterator(index);
}
@Override
public List<V> subList( int fromIndex,
int toIndex ) {
List<V> valueSublist = delegate().subList(fromIndex, toIndex);
return wrapList(getKey(), valueSublist);
}
protected class DelegateListIterator extends DelegateIterator implements ListIterator<V> {
protected DelegateListIterator() {
super();
}
protected DelegateListIterator( int index ) {
super(index);
}
@Override
protected ListIterator<V> iterator() {
return (ListIterator<V>)super.iterator();
}
@Override
public boolean hasPrevious() {
return iterator().hasPrevious();
}
@Override
public void add( V e ) {
iterator().add(e);
incrementSize(1);
}
@Override
public int nextIndex() {
return iterator().nextIndex();
}
@Override
public V previous() {
return iterator().previous();
}
@Override
public int previousIndex() {
return iterator().previousIndex();
}
@Override
public void set( V e ) {
iterator().set(e);
}
}
}
protected class WrappedMap extends AbstractMap<K, Collection<V>> {
private transient Set<Map.Entry<K, Collection<V>>> entries;
private Map<K, Collection<V>> delegate;
protected WrappedMap( Map<K, Collection<V>> wrapped ) {
this.delegate = wrapped;
}
@Override
public Set<Map.Entry<K, Collection<V>>> entrySet() {
if (entries == null) entries = new WrappedEntrySet();
return entries;
}
protected Map<K, Collection<V>> delegate() {
return delegate;
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals( Object o ) {
if (o == this) return true;
return delegate.equals(o);
}
@Override
public String toString() {
return delegate.toString();
}
@SuppressWarnings( "unchecked" )
@Override
public Collection<V> get( Object key ) {
return AbstractMultimap.this.get((K)key);
}
@Override
public Collection<V> remove( Object key ) {
Collection<V> values = rawData().remove(key);
if (values != null) {
// Now create a copy of the data, since someone might be holding a reference to the existing values ...
Collection<V> copy = createCollection();
copy.addAll(values);
decrementSize(values.size());
values.clear(); // in case anyone is holding onto this collection ...
values = copy;
}
return values; // may be null
}
protected class WrappedEntrySet extends AbstractSet<Map.Entry<K, Collection<V>>> {
@Override
public Iterator<Map.Entry<K, Collection<V>>> iterator() {
return new WrappedMapEntryIterator();
}
@Override
public int size() {
return delegate().size();
}
@Override
public boolean contains( Object o ) {
// Faster if we do this directly against the delegate ...
return delegate().entrySet().contains(o);
}
@Override
public boolean remove( Object o ) {
if (!contains(o)) return false;
// Faster if we do this directly against the delegate ...
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
removeAllValuesForKey(entry.getKey());
return true;
}
}
protected class WrappedMapEntryIterator implements Iterator<Map.Entry<K, Collection<V>>> {
private final Iterator<Map.Entry<K, Collection<V>>> delegateIterator = delegate().entrySet().iterator();
private Collection<V> currentValues = null;
@Override
public boolean hasNext() {
return delegateIterator.hasNext();
}
@Override
public Map.Entry<K, Collection<V>> next() {
Map.Entry<K, Collection<V>> currentEntry = delegateIterator.next();
currentValues = currentEntry.getValue();
K key = currentEntry.getKey();
return new ImmutableMapEntry<K, Collection<V>>(key, wrapCollection(key, currentValues));
}
@Override
public void remove() {
// Remove the current value collection ...
delegateIterator.remove();
// Update the total size of the multimap ...
decrementSize(currentValues.size());
// and clear the values ...
currentValues.clear();
}
}
}
protected class WrappedKeySet extends AbstractSet<K> {
private final Map<K, Collection<V>> delegate;
protected WrappedKeySet( Map<K, Collection<V>> wrapped ) {
this.delegate = wrapped;
}
@Override
public int size() {
return this.delegate.size();
}
@Override
public boolean remove( Object o ) {
return removeAllValuesForKey(o);
}
@Override
public boolean contains( Object o ) {
return this.delegate.containsKey(o);
}
@Override
public boolean containsAll( Collection<?> c ) {
return this.delegate.keySet().containsAll(c);
}
@SuppressWarnings( "synthetic-access" )
@Override
public void clear() {
this.delegate.clear();
totalSize = 0;
}
@Override
public Iterator<K> iterator() {
final Map<K, Collection<V>> delegate = this.delegate;
return new Iterator<K>() {
private final Iterator<Map.Entry<K, Collection<V>>> entryIter = delegate.entrySet().iterator();
private Map.Entry<K, Collection<V>> currentEntry;
@Override
public boolean hasNext() {
return entryIter.hasNext();
}
@Override
public K next() {
currentEntry = entryIter.next();
return currentEntry.getKey();
}
@Override
public void remove() {
entryIter.remove();
Collection<V> values = currentEntry.getValue();
decrementSize(values.size());
values.clear();
}
};
}
}
protected class WrappedSortedKeySet extends WrappedKeySet implements SortedSet<K> {
private SortedMap<K, Collection<V>> sortedDelegate;
protected WrappedSortedKeySet( SortedMap<K, Collection<V>> wrapped ) {
super(wrapped);
sortedDelegate = wrapped;
}
@Override
public Comparator<? super K> comparator() {
return sortedDelegate.comparator();
}
@Override
public SortedSet<K> subSet( K fromElement,
K toElement ) {
return new WrappedSortedKeySet(sortedDelegate.subMap(fromElement, toElement));
}
@Override
public SortedSet<K> headSet( K toElement ) {
return new WrappedSortedKeySet(sortedDelegate.headMap(toElement));
}
@Override
public SortedSet<K> tailSet( K fromElement ) {
return new WrappedSortedKeySet(sortedDelegate.tailMap(fromElement));
}
@Override
public K first() {
return sortedDelegate.firstKey();
}
@Override
public K last() {
return sortedDelegate.lastKey();
}
}
}