package org.infinispan.commons.equivalence;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* Custom hash-based linked list map which accepts no null keys nor null values,
* where equality and hash code calculations are done based on passed
* {@link org.infinispan.commons.equivalence.Equivalence} function implementations for keys
* and values, as opposed to relying on their own equals/hashCode/toString
* implementations. This is handy when using key/values whose mentioned
* methods cannot be overriden, i.e. arrays, and in situations where users
* want to avoid using wrapper objects.
*
* In order to provide linked list behaviour, entries are linked with each
* other in a predictable order.
*
* @author Galder ZamarreƱo
* @since 6.0
* @deprecated
*/
public class EquivalentLinkedHashMap<K, V> extends EquivalentHashMap<K, V> {
private transient LinkedNode<K, V> header;
private final IterationOrder iterationOrder;
public EquivalentLinkedHashMap(int initialCapacity, float loadFactor,
IterationOrder iterationOrder,
Equivalence<? super K> keyEq, Equivalence<? super V> valueEq) {
super(initialCapacity, loadFactor, keyEq, valueEq);
this.iterationOrder = iterationOrder;
addFirstEntry();
}
private void addFirstEntry() {
header = createLinkedNode();
header.before = header;
header.after = header;
}
@Override
void addEntry(int index, K key, V value, int hash) {
super.addEntry(index, key, value, hash);
LinkedNode<K,V> eldest = header.after;
if (removeEldestEntry(eldest)) {
remove(eldest.getKey());
}
}
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return false;
}
@SuppressWarnings("unchecked")
private <K, V> LinkedNode<K, V> createLinkedNode() {
return new LinkedNode<K, V>(null, -1, null, null);
}
@Override
Node<K, V> createNode(K key, V value, int hash, Node<K, V> node) {
LinkedNode<K, V> linkedNode = new LinkedNode<K, V>(key, hash, value, node);
linkedNode.addBefore(header);
return linkedNode;
}
@Override
public V get(Object key) {
LinkedNode<K, V> n = getNode(key);
return n == null ? null : n.recordAccess(this);
}
@Override
public V remove(Object key) {
LinkedNode<K, V> prevNode = removeNode(key);
return prevNode == null ? null : prevNode.remove();
}
@Override
public void clear() {
super.clear();
header.before = header;
header.after = header;
}
private static final class LinkedNode<K, V> extends Node<K,V> {
LinkedNode<K, V> before;
LinkedNode<K, V> after;
private LinkedNode(K key, int hash, V value, Node<K, V> next) {
super(key, hash, value, next);
}
private V remove() {
before.after = after;
after.before = before;
return value;
}
private void addBefore(LinkedNode<K, V> entry) {
after = entry;
before = entry.before;
before.after = this;
after.before = this;
}
V recordAccess(EquivalentHashMap<K, V> m) {
EquivalentLinkedHashMap<K, V> linkedMap = (EquivalentLinkedHashMap<K, V>)m;
if (linkedMap.iterationOrder == IterationOrder.ACCESS_ORDER) {
linkedMap.modCount++;
remove();
addBefore(linkedMap.header);
}
return value;
}
@Override
protected V setValue(V value, EquivalentHashMap<K, V> map) {
V retValue = super.setValue(value, map);
recordAccess(map);
return retValue;
}
}
public enum IterationOrder {
ACCESS_ORDER, INSERT_ORDER;
public boolean toJdkAccessOrder() {
return this == ACCESS_ORDER;
}
}
/**
* Exported Entry for iterators
*/
private static class LinkedEntry<K,V> extends MapEntry<K,V> {
LinkedNode<K, V> before;
LinkedNode<K, V> after;
LinkedEntry(K key, V val, LinkedNode<K, V> before, LinkedNode<K, V> after, EquivalentHashMap<K, V> map) {
super(key, val, map);
this.before = before;
this.after = after;
}
}
private abstract class EquivalentLinkedHashIterator<T> implements Iterator<T> {
final EquivalentHashMap<K, V> map;
LinkedEntry<K, V> nextEntry;
LinkedEntry<K, V> lastReturned = null;
protected EquivalentLinkedHashIterator(EquivalentHashMap<K, V> map) {
this.map = map;
nextEntry = new LinkedEntry<K, V>(
header.after.key, header.after.value,
header.after.before, header.after.after, map);
}
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return !equals(nextEntry, header);
}
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
EquivalentLinkedHashMap.this.remove(lastReturned.key);
lastReturned = null;
expectedModCount = modCount;
}
LinkedEntry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (equals(nextEntry, header))
throw new NoSuchElementException();
LinkedEntry<K, V> e = nextEntry;
lastReturned = nextEntry;
nextEntry = new LinkedEntry<K, V>(
e.after.key, e.after.value,
e.after.before, e.after.after, map);
return e;
}
boolean equals(LinkedEntry<K, V> entry, LinkedNode<K, V> node) {
return entry.key == node.key
&& entry.val == node.value
&& entry.before == node.before
&& entry.after == node.after;
}
}
private class KeyIterator extends EquivalentLinkedHashIterator<K> {
protected KeyIterator(EquivalentHashMap<K, V> map) {
super(map);
}
public K next() {
return nextEntry().getKey();
}
}
private class ValueIterator extends EquivalentLinkedHashIterator<V> {
protected ValueIterator(EquivalentHashMap<K, V> map) {
super(map);
}
public V next() {
return nextEntry().val;
}
}
private class EntryIterator extends EquivalentLinkedHashIterator<Map.Entry<K, V>> {
protected EntryIterator(EquivalentHashMap<K, V> map) {
super(map);
}
public Map.Entry<K, V> next() {
return nextEntry();
}
}
Iterator<K> newKeyIterator() {
return new KeyIterator(this);
}
Iterator<V> newValueIterator() {
return new ValueIterator(this);
}
Iterator<Map.Entry<K,V>> newEntryIterator() {
return new EntryIterator(this);
}
}