/*
* 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.AbstractSequentialList;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.modeshape.common.util.ObjectUtil;
/**
* A {@link Multimap} implementation that uses an {@link LinkedList} to store the values associated with a key. This
* implementation allows duplicate values for a key, maintains the insertion-order of the {@link #get(Object) values for each key}
* , and maintains the insertion order of all {@link #entries() key-value pairs}.
*
* @param <K> the key type
* @param <V> the value type
*/
public final class LinkedListMultimap<K, V> implements ListMultimap<K, V> {
/**
* Creates a new, empty {@code LinkedListMultimap} with the default initial capacity.
*
* @param <K> the key type
* @param <V> the value type
* @return the new linked-list multimap; never null
*/
public static <K, V> LinkedListMultimap<K, V> create() {
return new LinkedListMultimap<K, V>();
}
protected static final class Entry<K, V> {
final K key;
V value;
Entry<K, V> nextWithKey;
Entry<K, V> previousWithKey;
Entry<K, V> next;
Entry<K, V> previous;
protected Entry( K key,
V value ) {
this.key = key;
this.value = value;
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "[" + key + "=" + value + "]";
}
}
protected Entry<K, V> firstEntry;
protected Entry<K, V> lastEntry;
protected int length;
protected final Map<K, AtomicInteger> numberOfEntriesForKey;
protected final Map<K, Entry<K, V>> firstEntryWithKey;
protected final Map<K, Entry<K, V>> lastEntryWithKey;
private transient Map<K, Collection<V>> mapView;
protected LinkedListMultimap() {
this.firstEntryWithKey = new HashMap<K, Entry<K, V>>();
this.lastEntryWithKey = new HashMap<K, Entry<K, V>>();
this.numberOfEntriesForKey = new HashMap<K, AtomicInteger>();
}
@Override
public void clear() {
length = 0;
firstEntryWithKey.clear();
lastEntryWithKey.clear();
}
@Override
public int size() {
return length;
}
@Override
public boolean isEmpty() {
return length == 0;
}
@Override
public boolean containsKey( K key ) {
return firstEntryWithKey.containsKey(key);
}
@Override
public boolean containsEntry( Object key,
Object value ) {
@SuppressWarnings( "unchecked" )
ValueIterator values = new ValueIterator((K)key);
while (values.hasNext()) {
if (ObjectUtil.isEqualWithNulls(values.next(), value)) return true;
}
return false;
}
@Override
public boolean containsValue( Object value ) {
EntryIterator entries = new EntryIterator();
while (entries.hasNext()) {
if (ObjectUtil.isEqualWithNulls(entries.next().value, value)) return true;
}
return false;
}
@Override
public List<V> get( final K key ) {
return new AbstractSequentialList<V>() {
@Override
public int size() {
return currentCountFor(key);
}
@Override
public ListIterator<V> listIterator( int index ) {
return new ValueIterator(key, index);
}
};
}
@Override
public boolean put( K key,
V value ) {
addEntryFor(key, value);
return true;
}
@Override
public boolean remove( K key,
V value ) {
// Find the entry with the value ...
ValueIterator values = new ValueIterator(key);
while (values.hasNext()) {
if (ObjectUtil.isEqualWithNulls(values.next(), value)) {
values.remove();
return true;
}
}
return false;
}
@Override
public Collection<V> removeAll( K key ) {
// Find the entries with the value ...
List<V> result = new ArrayList<V>(currentCountFor(key));
ValueIterator values = new ValueIterator(key);
while (values.hasNext()) {
result.add(values.next());
values.remove();
}
return result;
}
@Override
public Collection<Map.Entry<K, V>> entries() {
return new AbstractCollection<Map.Entry<K, V>>() {
@Override
public int size() {
return length;
}
@Override
public Iterator<Map.Entry<K, V>> iterator() {
return new Iterator<Map.Entry<K, V>>() {
private final EntryIterator iter = new EntryIterator();
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public Map.Entry<K, V> next() {
Entry<K, V> next = iter.next();
return new ImmutableMapEntry<K, V>(next.key, next.value);
}
@Override
public void remove() {
iter.remove();
}
};
}
};
}
@Override
public Set<K> keySet() {
return new AbstractSet<K>() {
@Override
public int size() {
return numberOfEntriesForKey.size();
}
@Override
public Iterator<K> iterator() {
return new KeyIterator();
}
};
}
@Override
public Collection<V> values() {
return new AbstractCollection<V>() {
@Override
public int size() {
return length;
}
@Override
public Iterator<V> iterator() {
return new Iterator<V>() {
private final EntryIterator iter = new EntryIterator();
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public V next() {
Entry<K, V> next = iter.next();
return next.value;
}
@Override
public void remove() {
iter.remove();
}
};
}
};
}
@Override
public Map<K, Collection<V>> asMap() {
if (mapView == null) mapView = new MapView();
return mapView;
}
protected class MapView extends AbstractMap<K, Collection<V>> {
private Set<Map.Entry<K, Collection<V>>> entries;
@Override
public Set<Map.Entry<K, Collection<V>>> entrySet() {
if (entries == null) entries = new MapEntries();
return entries;
}
}
protected class MapEntries extends AbstractSet<Map.Entry<K, Collection<V>>> {
@Override
public int size() {
return length;
}
@Override
public Iterator<Map.Entry<K, Collection<V>>> iterator() {
return new Iterator<Map.Entry<K, Collection<V>>>() {
private KeyIterator iter = new KeyIterator();
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public Map.Entry<K, Collection<V>> next() {
final K nextKey = iter.next();
return new ImmutableMapEntry<K, Collection<V>>(nextKey, null) {
@Override
public Collection<V> getValue() {
return get(nextKey);
}
};
}
@Override
public void remove() {
iter.remove();
}
};
}
}
@Override
public int hashCode() {
return asMap().hashCode();
}
@Override
public boolean equals( Object obj ) {
if (obj == this) return true;
if (obj instanceof Multimap) {
Multimap<?, ?> that = (Multimap<?, ?>)obj;
return this.asMap().equals(that.asMap());
}
return false;
}
@Override
public String toString() {
return asMap().toString();
}
protected int incrementEntryCountFor( K key ) {
AtomicInteger count = numberOfEntriesForKey.get(key);
if (count == null) {
count = new AtomicInteger(0);
numberOfEntriesForKey.put(key, count);
}
++length;
return count.incrementAndGet();
}
protected int decrementEntryCountFor( K key ) {
AtomicInteger count = numberOfEntriesForKey.get(key);
assert count != null;
int result = count.decrementAndGet();
if (result == 0) numberOfEntriesForKey.remove(key);
--length;
return result;
}
protected int currentCountFor( K key ) {
AtomicInteger count = numberOfEntriesForKey.get(key);
return count != null ? count.get() : 0;
}
protected Entry<K, V> addEntryFor( K key,
V value ) {
Entry<K, V> entry = new Entry<K, V>(key, value);
if (firstEntry == null) {
assert length == 0;
// This is the first entry ...
firstEntry = entry;
firstEntryWithKey.put(key, entry);
} else {
// Add this entry to the end ...
lastEntry.next = entry;
entry.previous = lastEntry;
// Find the last entry with this key ...
Entry<K, V> lastWithKey = lastEntryWithKey.get(key);
if (lastWithKey == null) {
// This is the first entry for this key ...
firstEntryWithKey.put(key, entry);
}
}
// This entry is always the last entry ...
Entry<K, V> previousLastWithKey = lastEntryWithKey.put(key, entry);
if (previousLastWithKey != null) {
previousLastWithKey.nextWithKey = entry;
entry.previousWithKey = previousLastWithKey;
}
lastEntry = entry;
incrementEntryCountFor(key);
return entry;
}
protected Entry<K, V> insertEntryBefore( K key,
V value,
Entry<K, V> nextEntryWithKey ) {
if (nextEntryWithKey == null) return addEntryFor(key, value);
// Otherwise the new entry will lever be last ...
Entry<K, V> entry = new Entry<K, V>(key, value);
assert firstEntry != null;
assert length != 0;
// Set the entry's references ...
entry.next = nextEntryWithKey;
entry.nextWithKey = nextEntryWithKey;
entry.previous = nextEntryWithKey.previous;
entry.previousWithKey = nextEntryWithKey.previousWithKey;
// Set the reference from the entry that WAS before the next entry ...
if (nextEntryWithKey.previousWithKey != null) {
// This will NOT be the first entry for this key ...
nextEntryWithKey.previousWithKey.nextWithKey = entry;
} else {
// This will be the first entry for this key ...
firstEntryWithKey.put(key, entry);
}
if (nextEntryWithKey.previous != null) {
// This will NOT be the first entry ...
nextEntryWithKey.previous.next = entry;
} else {
// This will be the first entry ...
firstEntry = entry;
}
// Set the reference from the next entry ...
nextEntryWithKey.previousWithKey = entry;
nextEntryWithKey.previous = entry;
incrementEntryCountFor(key);
return entry;
}
protected void removeEntry( Entry<K, V> entry ) {
if (entry.previous == null) {
// The entry was the first ...
assert firstEntry == entry;
firstEntry = entry.next;
} else {
// Just a normal entry that is not at the front ...
entry.previous.next = entry.next;
}
if (entry.next == null) {
// The entry was the last ...
assert lastEntry == entry;
lastEntry = entry.previous;
} else {
// Just a normal entry that is not at the ed ...
entry.next.previous = entry.previous;
}
if (entry.previousWithKey != null) {
entry.previousWithKey.nextWithKey = entry.nextWithKey;
} else if (entry.nextWithKey != null) {
// We're removing the first entry with the key, and there is a next entry with the key ..
firstEntryWithKey.put(entry.key, entry.nextWithKey);
} else {
// We're removing the first and only entry with the key ...
firstEntryWithKey.remove(entry.key);
}
if (entry.nextWithKey != null) {
entry.nextWithKey.previousWithKey = entry.previousWithKey;
} else if (entry.previousWithKey != null) {
// We're removing the last entry with the key, and there is a previoius entry with the key ..
lastEntryWithKey.put(entry.key, entry.previousWithKey);
} else {
// We're removing the last and only entry with the key ...
lastEntryWithKey.remove(entry.key);
}
decrementEntryCountFor(entry.key);
}
protected void isValid( Entry<K, V> entry ) {
if (entry == null) throw new NoSuchElementException();
}
protected class EntryIterator implements Iterator<Entry<K, V>> {
private Entry<K, V> nextEntry;
private Entry<K, V> currentEntry;
protected EntryIterator() {
nextEntry = firstEntry;
}
protected EntryIterator( Entry<K, V> first ) {
nextEntry = first;
}
@Override
public boolean hasNext() {
return nextEntry != null;
}
@Override
public Entry<K, V> next() {
isValid(nextEntry);
currentEntry = nextEntry;
nextEntry = nextEntry.next;
return currentEntry;
}
@Override
public void remove() {
if (currentEntry == null) throw new IllegalStateException();
removeEntry(currentEntry);
currentEntry = null;
}
}
protected class ValueIterator implements ListIterator<V> {
private Entry<K, V> previous;
private Entry<K, V> current;
private Entry<K, V> next;
private int nextIndex;
private final K key;
protected ValueIterator( K key ) {
this.key = key;
next = firstEntryWithKey.get(key);
nextIndex = 0;
}
protected ValueIterator( K key,
int index ) {
this.key = key;
int count = currentCountFor(key);
if (index > count / 2) {
// The index is closer to the end, so start at the end ..
previous = lastEntryWithKey.get(key);
nextIndex = count;
while (index++ < count) {
previous();
}
} else {
// The index is closer to the front, so start at the front ...
next = firstEntryWithKey.get(key);
nextIndex = 0;
while (index-- > 0) {
next();
}
}
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public V next() {
isValid(next);
current = next;
previous = next;
next = current.nextWithKey;
++nextIndex;
return current.value;
}
@Override
public int nextIndex() {
return nextIndex;
}
@Override
public boolean hasPrevious() {
return previous != null;
}
@Override
public V previous() {
isValid(previous);
current = previous;
next = previous;
previous = current.previousWithKey;
--nextIndex;
return current.value;
}
@Override
public int previousIndex() {
return nextIndex - 1;
}
@Override
public void remove() {
if (current == null) throw new IllegalStateException();
if (current != next) {
// removing next element
previous = current.previousWithKey;
nextIndex--;
} else {
next = current.nextWithKey;
}
removeEntry(current);
current = null;
}
@Override
public void add( V value ) {
if (next == null) {
previous = addEntryFor(key, value);
} else {
previous = insertEntryBefore(key, value, next);
}
nextIndex++;
current = null;
}
@Override
public void set( V value ) {
if (current == null) throw new IllegalStateException();
current.value = value;
}
}
protected class KeyIterator implements Iterator<K> {
private final Set<K> seen = new HashSet<K>();
private Entry<K, V> next = firstEntry;
private Entry<K, V> current = null;
@Override
public boolean hasNext() {
return next != null;
}
@Override
public K next() {
if (next == null) throw new NoSuchElementException();
current = next;
seen.add(current.key);
do {
next = next.next;
} while (next != null && !seen.add(next.key));
return current.key;
}
@Override
public void remove() {
if (current == null) throw new NoSuchElementException();
removeAll(current.key);
current = null;
}
}
}