package bjc.utils.funcdata; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Function; import bjc.utils.data.Pair; /** * Basic implementation of {@link IFunctionalMap} * * @author ben * * @param * The type of the map's keys * @param * The type of the map's values */ public class FunctionalMap implements IFunctionalMap { /** * A map that transforms values from one type to another * * @author ben * * @param * The type of the map's keys * @param * The type of the map's values * @param * The type of the transformed values */ private static final class TransformedValueMap implements IFunctionalMap { private IFunctionalMap mapToTransform; private Function transformer; public TransformedValueMap(IFunctionalMap 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(); } @Override public V2 put(K key, V2 val) { throw new UnsupportedOperationException( "Can't add items to transformed map"); } @Override public IFunctionalMap mapValues( Function transform) { return new TransformedValueMap<>(this, transform); } @Override public IFunctionalList keyList() { return mapToTransform.keyList(); } @Override public void forEach(BiConsumer action) { mapToTransform.forEach((key, val) -> { action.accept(key, transformer.apply(val)); }); } @Override public V2 remove(K key) { return transformer.apply(mapToTransform.remove(key)); } @Override public int getSize() { return mapToTransform.getSize(); } } 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); }); } } /* * (non-Javadoc) * * @see bjc.utils.funcdata.IFunctionalMap#put(K, V) */ @Override public V put(K key, V val) { if (key == null) { throw new NullPointerException("Key must not be null"); } return wrappedMap.put(key, val); } /* * (non-Javadoc) * * @see bjc.utils.funcdata.IFunctionalMap#get(K) */ @Override 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); } /* * (non-Javadoc) * * @see bjc.utils.funcdata.IFunctionalMap#mapValues(java.util.function. * Function) */ @Override public IFunctionalMap mapValues( Function transformer) { if (transformer == null) { throw new NullPointerException("Transformer must not be null"); } return new TransformedValueMap<>(this, transformer); } /* * (non-Javadoc) * * @see bjc.utils.funcdata.IFunctionalMap#containsKey(K) */ @Override public boolean containsKey(K key) { return wrappedMap.containsKey(key); } @Override public String toString() { return wrappedMap.toString(); } @Override public IFunctionalList keyList() { FunctionalList keys = new FunctionalList<>(); wrappedMap.keySet().forEach((key) -> { keys.add(key); }); return keys; } @Override public void forEach(BiConsumer action) { wrappedMap.forEach(action); } @Override public V remove(K key) { return wrappedMap.remove(key); } @Override public int getSize() { return wrappedMap.size(); } }