Bläddra i källkod

MapUtils: keyproxy

Ranides Atterwim 8 år sedan
förälder
incheckning
ca6b09dfb9
1 ändrade filer med 166 tillägg och 5 borttagningar
  1. 166 5
      assira/src/main/java/net/ranides/assira/collection/maps/MapUtils.java

+ 166 - 5
assira/src/main/java/net/ranides/assira/collection/maps/MapUtils.java

@@ -7,12 +7,13 @@
 package net.ranides.assira.collection.maps;
 
 import java.io.Serializable;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.function.BiFunction;
 import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+import net.ranides.assira.collection.ACollection;
 import net.ranides.assira.collection.CollectionUtils;
 import net.ranides.assira.collection.sets.SetUtils;
 import net.ranides.assira.functional.ProjectionFunction;
@@ -59,7 +60,11 @@ public final class MapUtils {
     public static <K, TV, RV> MultiMap<K,RV> wrap(MultiMap<K,TV> map, Function<? super TV, ? extends RV> getter, BiFunction<? super TV, ? super RV, ? extends RV> setter) {
         return new MMapWrapper<>(map, getter, setter);
     }
-    
+
+    public static <K,V> Map<K,V> keyproxy(Supplier<Map<K, V>> content, Predicate<Object> acceptor, Function<K, K> function) {
+        return new KeyMapAdapter<>(content, acceptor, function);
+    }
+
     private static class MMapAdapter<K, TV, RV> extends MapAdapter<K, TV, RV> implements MultiMap<K, RV> {
         
         private static final long serialVersionUID = 1L;
@@ -444,5 +449,161 @@ public final class MapUtils {
         }
 
     }
+
+    private static class KeyMapAdapter<K, V> extends AMap<K, V> {
+
+        protected final Map<K, V> content;
+        protected final Predicate<Object> acceptor;
+        protected final Function<K, K> function;
+
+        KeyMapAdapter(Supplier<Map<K, V>> content, Predicate<Object> acceptor, Function<K, K> function) {
+            this.content = content.get();
+            this.acceptor = acceptor;
+            this.function = function;
+        }
+
+        @Override
+        public Set<Entry<K, V>> entrySet() {
+            return new KeyMapEntrySet();
+        }
+
+        @Override
+        public int size() {
+            return content.size();
+        }
+
+        @Override
+        public boolean containsValue(Object value) {
+            return content.containsValue(value);
+        }
+
+        @Override
+        public V get(Object key) {
+            return acceptor.test(key) ? content.get(asKey(key)) : null;
+        }
+
+        @Override
+        public V getOrDefault(Object key, V defaultValue) {
+            return acceptor.test(key) ? content.getOrDefault(asKey(key), defaultValue) : defaultValue;
+        }
+
+        @Override
+        public boolean containsKey(Object key) {
+            return acceptor.test(key) ? content.containsKey(asKey(key)) : false;
+        }
+
+        @Override
+        public V put(K key, V value) {
+            return content.put(asKey(key), value);
+        }
+
+        @Override
+        public void putAll(Map<? extends K, ? extends V> m) {
+            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
+                K key = e.getKey();
+                V value = e.getValue();
+                content.put(asKey(key), value);
+            }
+        }
+
+        @Override
+        public V remove(Object key) {
+            return acceptor.test(key) ? content.remove(asKey(key)) : null;
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            return content.putIfAbsent(asKey(key), value);
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            return acceptor.test(key) && content.remove(asKey(key), value);
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            return content.replace(asKey(key), oldValue, newValue);
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            return content.replace(asKey(key), value);
+        }
+
+        @Override
+        public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+            return content.computeIfAbsent(asKey(key), mappingFunction);
+        }
+
+        @Override
+        public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return content.computeIfPresent(asKey(key), remappingFunction);
+        }
+
+        @Override
+        public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return content.compute(asKey(key), remappingFunction);
+        }
+
+        @Override
+        public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            return content.merge(asKey(key), value, remappingFunction);
+        }
+
+        private K asKey(Object key) {
+            return key!=null ? function.apply((K)key) : null;
+        }
+
+        private Entry<K, V> asEntry(Entry<K, V> entry) {
+            K k = asKey(entry.getKey());
+            V v = entry.getValue();
+            return new AbstractMap.SimpleEntry<>(k, v);
+        }
+
+        private final class KeyMapEntrySet extends ACollection<Entry<K, V>> implements Set<Map.Entry<K, V>>, Serializable {
+
+            private static final long serialVersionUID = 1L;
+
+            private final Set<Entry<K, V>> entries = content.entrySet();
+
+            @Override
+            public boolean contains(Object o) {
+                return o instanceof Entry<?,?> && entries.contains(asEntry((Entry<K, V>) o));
+            }
+
+            @Override
+            public boolean add(Entry<K, V> kvEntry) {
+                return entries.add(asEntry(kvEntry));
+            }
+
+            @Override
+            public Iterator<Map.Entry<K, V>> iterator() {
+                return entries.iterator();
+            }
+
+            @Override
+            public int size() {
+                return entries.size();
+            }
+
+            @Override
+            public int hashCode() {
+                return entries.hashCode();
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if(obj instanceof Set) {
+                    @SuppressWarnings("unchecked")
+                    Set<Entry<K, V>> that = (Set<Entry<K, V>>)obj;
+                    return this.size() == that.size() && this.containsAll(that);
+                }
+                return false;
+            }
+
+        }
+
+    }
     
 }