package bjc.utils.funcdata; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import bjc.utils.data.Pair; /** * Functional wrapper over map providing some useful things * * @author ben * * @param * The type of this map's keys * @param * The type of this map's values * */ public class FunctionalMap { private final class TransformedMap extends FunctionalMap { private FunctionalMap mapToTransform; private Function transformer; public TransformedMap(FunctionalMap destMap, Function transform) { mapToTransform = destMap; transformer = transform; } @Override public V2 get(K key) { return transformer.apply(mapToTransform.get(key)); } @Override public boolean containsKey(K key) { return mapToTransform.containsKey(key); } @Override public String toString() { return mapToTransform.toString(); } } private Map wrappedMap; /** * Create a new blank functional map */ public FunctionalMap() { wrappedMap = new HashMap<>(); } /** * Create a new functional map wrapping the specified map * * @param wrap * The map to wrap */ public FunctionalMap(Map wrap) { if (wrap == null) { throw new NullPointerException("Map to wrap must not be null"); } wrappedMap = wrap; } /** * Create a new functional map with the specified entries * * @param entries * The entries to put into the map */ @SafeVarargs public FunctionalMap(Pair... entries) { this(); for (Pair entry : entries) { entry.doWith((key, val) -> { wrappedMap.put(key, val); }); } } /** * Add an entry to the map * * @param key * The key to put the value under * @param val * The value to add * @return The previous value of the key in the map, or null if the key * wasn't in the map. However, note that it may also return * null if the key was set to null. * */ public V put(K key, V val) { if (key == null) { throw new NullPointerException("Key must not be null"); } return wrappedMap.put(key, val); } /** * Get the value assigned to the given key * * @param key * The key to look for a value under * @return The value of the key * * */ public V get(K key) { if (key == null) { throw new NullPointerException("Key must not be null"); } if (!wrappedMap.containsKey(key)) { throw new IllegalArgumentException( "Key " + key + " is not present in the map"); } return wrappedMap.get(key); } /** * Transform the values returned by this map. * * NOTE: This transform is applied once for each lookup of a value, so * the transform passed should be a proper function, or things will * likely not work as expected. * * @param * The new type of returned values * @param transformer * The function to use to transform values * @return The map where each value will be transformed after lookup */ public FunctionalMap mapValues( Function transformer) { if (transformer == null) { throw new NullPointerException("Transformer must not be null"); } return new TransformedMap<>(this, transformer); } /** * Check if this map contains the specified key * * @param key * The key to check * @return Whether or not the map contains the key */ public boolean containsKey(K key) { return wrappedMap.containsKey(key); } @Override public String toString() { return wrappedMap.toString(); } }