package com.googlecode.totallylazy.functions;
import com.googlecode.totallylazy.Either;
import com.googlecode.totallylazy.Memory;
import java.util.HashMap;
import java.util.Map;
import static com.googlecode.totallylazy.Closeables.safeClose;
public final class Lazy1<T, R> implements Function1<T, R>, Memory {
private final Function1<? super T, ? extends R> callable;
private final Map<T, Either<Exception, R>> state = new HashMap<>();
private final Object lock = new Object();
private Lazy1(Function1<? super T, ? extends R> callable) {
this.callable = callable;
}
public static <T, R> Lazy1<T, R> lazy(Function1<? super T, ? extends R> callable) {
return new Lazy1<>(callable);
}
public final R call(T instance) throws Exception{
synchronized (lock) {
if (!state.containsKey(instance)) {
try {
state.put(instance, Either.right(callable.call(instance)));
} catch (Exception e) {
state.put(instance, Either.left(e));
}
}
Either<Exception, R> either = state.get(instance);
if(either.isLeft()) {
throw either.left();
}
return either.right();
}
}
public void forget() {
close();
}
@Override
public void close() {
synchronized (lock) {
for (Either<Exception, R> r : state.values()) {
if(r != null) safeClose(r.value());
}
state.clear();
}
}
}