package de.take_weiland.mods.commons.util;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Supplier;
import com.google.common.collect.ForwardingMap;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* <p>A simple implementation of a map that computes missing values with a Function.</p>
* <p>It should be noted that this implementation violates the Map interface contract and in most cases
* a {@link com.google.common.cache.Cache} is more appropriate.</p>
* <p>This implementation supports null values and keys if the underlying map does,
* but is <i>not</i> thread-safe, even if the underlying Map is.</p>
* <p>Only the {@code get} method will compute new values.</p>
*
* @author diesieben07
*/
public final class ComputingMap<K, V> extends ForwardingMap<K, V> implements Map<K, V> {
public static <K, V> ComputingMap<K, V> of(@NotNull Function<? super K, ? extends V> function) {
return of(new HashMap<K, V>(), function);
}
public static <K, V> ComputingMap<K, V> of(@NotNull Map<K, V> map, @NotNull Function<? super K, ? extends V> function) {
return new ComputingMap<>(checkNotNull(map), checkNotNull(function));
}
public static <K, V> ComputingMap<K, V> of(@NotNull Map<K, V> map, @NotNull Supplier<? extends V> supplier) {
return new ComputingMap<>(checkNotNull(map), Functions.forSupplier(supplier));
}
private final Map<K, V> delegate;
private final Function<? super K, ? extends V> function;
private ComputingMap(Map<K, V> delegate, Function<? super K, ? extends V> function) {
this.delegate = delegate;
this.function = function;
}
@Override
protected Map<K, V> delegate() {
return delegate;
}
@Override
public V get(Object key) {
V value = delegate.get(key);
if (value != null || delegate.containsKey(key)) {
return value;
}
try {
//noinspection unchecked
delegate.put((K) key, (value = function.apply(((K) key))));
} catch (ClassCastException e) {
return null;
}
return value;
}
}