org.infinispan.commons.equivalence.EquivalentLinkedHashMap Maven / Gradle / Ivy
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 extends EquivalentHashMap {
private transient LinkedNode 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 eldest = header.after;
if (removeEldestEntry(eldest)) {
remove(eldest.getKey());
}
}
protected boolean removeEldestEntry(Map.Entry eldest) {
return false;
}
@SuppressWarnings("unchecked")
private LinkedNode createLinkedNode() {
return new LinkedNode(null, -1, null, null);
}
@Override
Node createNode(K key, V value, int hash, Node node) {
LinkedNode linkedNode = new LinkedNode(key, hash, value, node);
linkedNode.addBefore(header);
return linkedNode;
}
@Override
public V get(Object key) {
LinkedNode n = getNode(key);
return n == null ? null : n.recordAccess(this);
}
@Override
public V remove(Object key) {
LinkedNode 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 extends Node {
LinkedNode before;
LinkedNode after;
private LinkedNode(K key, int hash, V value, Node next) {
super(key, hash, value, next);
}
private V remove() {
before.after = after;
after.before = before;
return value;
}
private void addBefore(LinkedNode entry) {
after = entry;
before = entry.before;
before.after = this;
after.before = this;
}
V recordAccess(EquivalentHashMap m) {
EquivalentLinkedHashMap linkedMap = (EquivalentLinkedHashMap)m;
if (linkedMap.iterationOrder == IterationOrder.ACCESS_ORDER) {
linkedMap.modCount++;
remove();
addBefore(linkedMap.header);
}
return value;
}
@Override
protected V setValue(V value, EquivalentHashMap 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 extends MapEntry {
LinkedNode before;
LinkedNode after;
LinkedEntry(K key, V val, LinkedNode before, LinkedNode after, EquivalentHashMap map) {
super(key, val, map);
this.before = before;
this.after = after;
}
}
private abstract class EquivalentLinkedHashIterator implements Iterator {
final EquivalentHashMap map;
LinkedEntry nextEntry;
LinkedEntry lastReturned = null;
protected EquivalentLinkedHashIterator(EquivalentHashMap map) {
this.map = map;
nextEntry = new LinkedEntry(
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 nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (equals(nextEntry, header))
throw new NoSuchElementException();
LinkedEntry e = nextEntry;
lastReturned = nextEntry;
nextEntry = new LinkedEntry(
e.after.key, e.after.value,
e.after.before, e.after.after, map);
return e;
}
boolean equals(LinkedEntry entry, LinkedNode node) {
return entry.key == node.key
&& entry.val == node.value
&& entry.before == node.before
&& entry.after == node.after;
}
}
private class KeyIterator extends EquivalentLinkedHashIterator {
protected KeyIterator(EquivalentHashMap map) {
super(map);
}
public K next() {
return nextEntry().getKey();
}
}
private class ValueIterator extends EquivalentLinkedHashIterator {
protected ValueIterator(EquivalentHashMap map) {
super(map);
}
public V next() {
return nextEntry().val;
}
}
private class EntryIterator extends EquivalentLinkedHashIterator> {
protected EntryIterator(EquivalentHashMap map) {
super(map);
}
public Map.Entry next() {
return nextEntry();
}
}
Iterator newKeyIterator() {
return new KeyIterator(this);
}
Iterator newValueIterator() {
return new ValueIterator(this);
}
Iterator> newEntryIterator() {
return new EntryIterator(this);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy