
shz.cache.LruCache Maven / Gradle / Ivy
package shz.cache;
import shz.linked.ConcurrentLDNode;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class LruCache extends LocalCache {
private static final class Node {
private final ConcurrentLDNode node;
private Reference ref;
Node(K key, Reference ref) {
node = ConcurrentLDNode.of(key);
this.ref = ref;
}
}
private final int capacity;
private final ConcurrentHashMap> cache;
private final ConcurrentLDNode head;
private final ConcurrentLDNode tail;
public LruCache(int capacity, RefType refType, ReferenceQueue super V> queue) {
super(refType, queue);
this.capacity = capacity;
cache = new ConcurrentHashMap<>(capacity);
head = tail = ConcurrentLDNode.of(null);
head.next(tail);
tail.prev(head);
}
public LruCache(int capacity, RefType refType) {
this(capacity, refType, null);
}
public LruCache(int capacity) {
this(capacity, RefType.SOFT);
}
@Override
public V get(K key) {
Node node = cache.get(key);
if (node == null) return null;
poll(node.node);
if (node.ref == null || node.ref.isEnqueued()) {
cache.remove(key);
return null;
}
offer(node.node);
return node.ref.get();
}
private K poll(ConcurrentLDNode node) {
node.poll();
return node.val;
}
private void offer(ConcurrentLDNode node) {
tail.addPrev(node);
}
@Override
public void put(K key, V val) {
Node node = cache.get(key);
if (node == null) {
K k;
while (cache.size() >= capacity && (k = poll(head.next())) != null) cache.remove(k);
node = cache.computeIfAbsent(key, t -> new Node<>(key, getReference(val)));
}
poll(node.node);
if (node.ref == null || node.ref.isEnqueued()) {
cache.remove(key);
return;
}
node.ref = getReference(val);
offer(node.node);
}
@Override
public boolean containsKey(K key) {
return cache.containsKey(key);
}
@Override
public int size() {
int size = 0;
for (Map.Entry> kv : cache.entrySet()) {
Node node = kv.getValue();
if (node.ref == null || node.ref.isEnqueued()) {
poll(node.node);
cache.remove(kv.getKey());
} else ++size;
}
return size;
}
@Override
public void delete(K key) {
Node node = cache.get(key);
if (node == null) return;
poll(node.node);
if (node.ref != null) node.ref.clear();
cache.remove(key);
}
@Override
public void clear() {
cache.forEach((key, node) -> {
if (node == null) return;
poll(node.node);
if (node.ref != null) node.ref.clear();
});
cache.clear();
head.next(tail);
tail.prev(head);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy