All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 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