Mariusz Sieroń 6 éve
szülő
commit
b4b2e6d0a7

+ 75 - 1
assira/src/main/java/net/ranides/assira/collection/maps/MapUtils.java

@@ -8,6 +8,7 @@ package net.ranides.assira.collection.maps;
 
 import java.io.Serializable;
 import java.util.*;
+import java.util.AbstractMap.SimpleEntry;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.function.Predicate;
@@ -65,6 +66,79 @@ public final class MapUtils {
         return new KeyMapAdapter<>(content, acceptor, function);
     }
 
+    public static <TK, RK, V> Map<RK,V> view(Map<TK, ? extends V> map, Function<TK, RK> keyMapper) {
+        return view(map, keyMapper, Function.identity());
+    }
+
+    public static <TK, RK, TV, RV> Map<RK, RV> view(Map<TK,? extends TV> map, Function<TK, RK> keyMapper, Function<TV, RV> valueMapper) {
+        return new ViewAdapter<>(map, keyMapper, valueMapper);
+    }
+
+    private static class ViewAdapter<TK, RK, TV, RV> extends AMap<RK, RV> {
+
+        private final Map<TK,? extends TV> content;
+
+        private final Function<TK, RK> kmap;
+
+        private final Function<TV, RV> vmap;
+
+        public ViewAdapter(Map<TK,? extends TV> content, Function<TK, RK> kmap, Function<TV, RV> vmap) {
+            this.content = content;
+            this.kmap = kmap;
+            this.vmap = vmap;
+        }
+
+        @Override
+        public int size() {
+            return content.size();
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public boolean containsKey(Object key) {
+            try {
+                return content.containsKey(kmap.apply((TK) key));
+            } catch (ClassCastException e) {
+                return false;
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public RV get(Object key) {
+            try {
+                return vmap.apply(content.get(kmap.apply((TK) key)));
+            } catch (ClassCastException e) {
+                return null;
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public boolean containsValue(Object value) {
+            try {
+                return content.containsValue(vmap.apply((TV) value));
+            } catch (ClassCastException e) {
+                return false;
+            }
+        }
+
+        @Override
+        public Set<RK> keySet() {
+            return SetUtils.map(content.keySet(), kmap);
+        }
+
+        @Override
+        public Collection<RV> values() {
+            return CollectionUtils.map(content.values(), vmap);
+        }
+
+        @Override
+        public Set<Entry<RK, RV>> entrySet() {
+            return SetUtils.map(content.entrySet(), e -> new SimpleEntry<>(kmap.apply(e.getKey()), vmap.apply(e.getValue())));
+        }
+    }
+
     private static class MMapAdapter<K, TV, RV> extends MapAdapter<K, TV, RV> implements MultiMap<K, RV> {
         
         private static final long serialVersionUID = 1L;
@@ -560,7 +634,7 @@ public final class MapUtils {
         private Entry<K, V> $toSimpleEntry(Entry<?,?> entry) {
             K k = (K)entry.getKey();
             V v = (V)entry.getValue();
-            return new AbstractMap.SimpleEntry<>(k, v);
+            return new SimpleEntry<>(k, v);
         }
 
         private final class KeyMapEntrySet extends ACollection<Entry<K, V>> implements Set<Map.Entry<K, V>>, Serializable {

+ 17 - 1
assira/src/test/java/net/ranides/assira/collection/maps/MapUtilsTest.java

@@ -15,6 +15,7 @@ import net.ranides.assira.collection.mockup.TMaps;
 import net.ranides.assira.collection.mockup.TPoint;
 import net.ranides.assira.test.TMap;
 import net.ranides.assira.test.TWrapper;
+import org.junit.Assert;
 import org.junit.Test;
 
 /**
@@ -22,7 +23,22 @@ import org.junit.Test;
  * @author Ranides Atterwim <ranides@gmail.com>
  */
 public class MapUtilsTest {
-    
+
+    @Test
+    public void view() {
+        Map<Object,Number> a = new HashMap<>();
+        Map<Object,?> b = a;
+        Map<?,?> c = a;
+
+        Map<String, Number> ma = MapUtils.view(a, String::valueOf);
+        Map<String, Object> mb = MapUtils.view(b, String::valueOf);
+        Map<String, Object> mc = MapUtils.view(c, String::valueOf);
+
+        Assert.assertNotNull(ma);
+        Assert.assertNotNull(mb);
+        Assert.assertNotNull(mc);
+    }
+
     @Test
     public void testMap_Projection() {
         TMap<TPoint, Integer> tmap = TMaps.MAP_PI;