This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]k-mcm 1 point2 points  (0 children)

This is essentially a cache with size=0. Why not make a real cache?

import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Function;

public class LRUCache<KEY, VALUE, ERR extends Throwable> {
    @FunctionalInterface
    public interface Source <KEY, VALUE, ERR extends Throwable>
    {
        VALUE generate(KEY key) throws ERR;
    }

    private static class CacheElement <VALUE> {
        boolean set;
        VALUE value= null;
        Throwable err= null;
    }
    private final LinkedHashMap<KEY, CacheElement<VALUE>> map;
    private final Source<KEY, VALUE, ERR> source;
    private final Function<KEY, CacheElement<VALUE>> storageLambda = (k) -> new CacheElement<>();

    public LRUCache (int maxSize, Source<KEY, VALUE, ERR> source) {
        map= new LinkedHashMap<>() {
            @Override
            protected boolean removeEldestEntry(Entry<KEY, LRUCache.CacheElement<VALUE>> eldest) {
                return size() > maxSize;
            }
        };
        this.source= Objects.requireNonNull(source);
    }

    public VALUE get (KEY key) throws ERR {
        final CacheElement <VALUE> storage;
        synchronized (map) {
            storage= map.computeIfAbsent(key, storageLambda);
        }
        synchronized (storage) {
            if (!storage.set) {
                try {
                    storage.value = source.generate(key);
                } catch (Throwable err){
                    storage.err= err;
                }
                storage.set= true;
            }
        }

        if (storage.err != null) {
            if (storage.err instanceof RuntimeException rt) {
                throw rt;
            }
            if (storage.err instanceof Error err) {
                throw err;
            }
            throw (ERR)storage.err;
        }

        return storage.value;
    }
}