Jelajahi Sumber

PrototypeMap is concrete class

Ranides Atterwim 5 tahun lalu
induk
melakukan
759c95a399

+ 0 - 590
assira/src/main/java/net/ranides/assira/collection/prototype/AbstractPrototype.java

@@ -1,590 +0,0 @@
-package net.ranides.assira.collection.prototype;
-
-import lombok.experimental.UtilityClass;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import net.ranides.assira.collection.iterators.RemoveIterator;
-import net.ranides.assira.collection.maps.AEntry;
-import net.ranides.assira.collection.maps.AMap;
-import net.ranides.assira.collection.sets.SetUtils;
-import net.ranides.assira.reflection.*;
-
-import java.util.*;
-import java.util.function.Consumer;
-
-@UtilityClass
-public class AbstractPrototype {
-
-    public static class DeclaredMap extends AbstractMap {
-
-        private final PrototypeMap parent;
-        private final Map<Object, Object> data;
-
-        public DeclaredMap(PrototypeMap parent, Map<Object, Object> data) {
-            this.parent = parent;
-            this.data = data;
-        }
-
-        @Override
-        public PrototypeMap getParentMap() {
-            return parent;
-        }
-
-        @Override
-        public PrototypeMap getDeclaredMap() {
-            return this;
-        }
-
-        @Override
-        public boolean containsKey(Object key) {
-            return data.containsKey(key);
-        }
-
-        @Override
-        public Object put(Object key, Object value) {
-            return data.put(key, value);
-        }
-
-        @Override
-        public Object get(Object key) {
-            return data.get(key);
-        }
-
-        @Override
-        public Object remove(Object key) {
-            return data.remove(key);
-        }
-
-        @Override
-        public int size() {
-            return data.size();
-        }
-
-        @Override
-        public boolean isEmpty() {
-            return data.isEmpty();
-        }
-
-        @Override
-        public boolean containsValue(Object value) {
-            return data.containsValue(value);
-        }
-
-        @Override
-        public void putAll(Map<?, ?> m) {
-            data.putAll(m);
-        }
-
-        @Override
-        public void clear() {
-            data.clear();
-        }
-
-        @Override
-        public Set<Object> keySet() {
-            return data.keySet();
-        }
-
-        @Override
-        public Collection<Object> values() {
-            return data.values();
-        }
-
-        @Override
-        public Set<Entry<Object, Object>> entrySet() {
-            return data.entrySet();
-        }
-
-        @Override
-        public int hashCode() {
-            return data.hashCode();
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if(other instanceof DeclaredMap) {
-                return data.equals(((DeclaredMap)other).data);
-            }
-            return super.equals(other);
-        }
-    }
-
-    public static class CompositeMap extends AbstractMap {
-
-        private final PrototypeMap parent;
-
-        private final DeclaredMap declared;
-
-        private transient KeysView keys;
-        private transient EntryView entries;
-        private transient ValuesView values;
-
-        protected CompositeMap(PrototypeMap parent, Map<Object, Object> content) {
-            this.parent = parent;
-            this.declared = new DeclaredMap(this, content);
-        }
-
-        @Override
-        public PrototypeMap getParentMap() {
-            return parent;
-        }
-
-        @Override
-        public PrototypeMap getDeclaredMap() {
-            return declared;
-        }
-
-        @Override
-        public int size() {
-            return keySet().size();
-        }
-
-        @Override
-        public boolean isEmpty() {
-            return declared.isEmpty() && (parent==null || parent.isEmpty());
-        }
-
-        @Override
-        public boolean containsKey(Object key) {
-            return declared.containsKey(key) || (parent!=null && parent.containsKey(key));
-        }
-
-        @Override
-        public boolean containsValue(Object value) {
-            return declared.containsValue(value) || (parent!=null && parent.containsKey(value));
-        }
-
-        @Override
-        public Object get(Object key) {
-            for(PrototypeMap scope = this; scope != null; scope = scope.getParentMap()) {
-                Object out = scope.getDeclaredMap().get(key);
-                if(out != null) {
-                    return out;
-                }
-            }
-            return null;
-        }
-
-        @Nullable
-        @Override
-        public Object put(Object key, Object value) {
-            return declared.put(key, value);
-        }
-
-        @Override
-        public Object remove(Object key) {
-            Object[] out = {null};
-            forEachScope(scope -> {
-                Object rem = scope.remove(key);
-                if (rem != null && out[0] == null) {
-                    out[0] = rem;
-                }
-            });
-            return out[0];
-        }
-
-        @Override
-        public void putAll(Map<?, ?> m) {
-            declared.putAll(m);
-        }
-
-        @Override
-        public void clear() {
-            forEachScope(Map::clear);
-        }
-
-        @Override
-        public Set<Object> keySet() {
-            if (keys == null) {
-                keys = new KeysView();
-            }
-            return keys;
-        }
-
-        @NotNull
-        @Override
-        public Collection<Object> values() {
-            if (values == null) {
-                values = new ValuesView();
-            }
-            return values;
-        }
-
-        @NotNull
-        @Override
-        public Set<Entry<Object, Object>> entrySet() {
-            if (entries == null) {
-                entries = new EntryView();
-            }
-            return entries;
-        }
-
-        protected void forEachScope(Consumer<PrototypeMap> consumer) {
-            for(PrototypeMap scope = this; scope != null; scope = scope.getParentMap()) {
-                consumer.accept(scope.getDeclaredMap());
-            }
-        }
-
-        private class EntryView extends AbstractSet<Entry<Object, Object>> {
-            @Override
-            public boolean contains(Object other) {
-                if(other instanceof Entry<?,?>) {
-                    Entry<?,?> entry = (Entry<?,?>)other;
-                    return Objects.equals(declared.get(entry.getKey()), entry.getValue());
-                }
-                return false;
-            }
-
-            @Override
-            public boolean add(Entry<Object, Object> entry) {
-                Object key = entry.getKey();
-                Object val = entry.getValue();
-
-                if(key instanceof PrototypeField<?>) {
-                    PrototypeField<?> field = (PrototypeField<?>) key;
-                    if(!field.type().isInstance(val)) {
-                        throw new ClassCastException(val + " can't be cast to " + field.type());
-                    }
-                }
-                declared.put(key, val);
-                return true;
-            }
-
-            @Override
-            public boolean remove(Object other) {
-                if(other instanceof Entry<?,?>) {
-                    Entry<?,?> entry = (Entry<?,?>)other;
-                    return declared.remove(entry.getKey(), entry.getValue());
-                }
-                return false;
-            }
-
-            @Override
-            public void clear() {
-                CompositeMap.this.clear();
-            }
-
-            @Override
-            public Iterator<Entry<Object, Object>> iterator() {
-                return new RemoveIterator<>(aggregate().iterator(), this::remove);
-            }
-
-            @Override
-            public int size() {
-                return aggregate().size();
-            }
-
-            public Set<Entry<Object, Object>> aggregate() {
-                Set<Entry<Object, Object>> set = new HashSet<>();
-                forEachScope(scope -> set.addAll(scope.entrySet()));
-                return set;
-            }
-        }
-
-        private class ValuesView extends AbstractSet<Object> {
-            @Override
-            public boolean contains(Object other) {
-                return CompositeMap.this.containsValue(other);
-            }
-
-            @Override
-            public void clear() {
-                CompositeMap.this.clear();
-            }
-
-            @Override
-            public Iterator<Object> iterator() {
-                return aggregate().iterator();
-            }
-
-            @Override
-            public int size() {
-                return aggregate().size();
-            }
-
-            public Collection<Object> aggregate() {
-                if(parent == null) {
-                    return declared.values();
-                }
-                Set<Object> inserted = new HashSet<>();
-                List<Object> list = new ArrayList<>();
-                forEachScope(scope -> {
-                    scope.forEach((key, value) -> {
-                        if(inserted.add(key)) {
-                            list.add(value);
-                        }
-                    });
-                });
-
-                return list;
-            }
-        }
-
-        private class KeysView extends AbstractSet<Object> {
-            @Override
-            public boolean contains(Object other) {
-                return CompositeMap.this.containsKey(other);
-            }
-
-            @Override
-            public boolean remove(Object key) {
-                return CompositeMap.this.remove(key) != null;
-            }
-
-            @Override
-            public void clear() {
-                CompositeMap.this.clear();
-            }
-
-            @Override
-            public Iterator<Object> iterator() {
-                return new RemoveIterator<>(aggregate().iterator(), this::remove);
-            }
-
-            @Override
-            public int size() {
-                return aggregate().size();
-            }
-
-            public Set<Object> aggregate() {
-                Set<Object> set = new HashSet<>();
-                forEachScope(scope -> set.addAll(scope.keySet()));
-                return set;
-            }
-        }
-
-    }
-
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    private static abstract class AbstractMap extends AMap<Object, Object> implements PrototypeMap {
-
-        @Override
-        public final Optional<PrototypeEntry<?>> getProperty(Object key) {
-            if(containsKey(key)) {
-                return Optional.of(PrototypeEntry.of(this, key));
-            }
-            return Optional.empty();
-        }
-
-        @Override
-        public final Optional<PrototypeEntry<Object>> getProperty(String key) {
-            return (Optional)getProperty((Object)key);
-        }
-
-        @Override
-        public final <V> Optional<PrototypeEntry<V>> getProperty(PrototypeField<V> key) {
-            return (Optional)getProperty((Object)key);
-        }
-
-        @Override
-        public final Set<PrototypeEntry<?>> propertySet() {
-            return SetUtils.map(keySet(), key -> PrototypeEntry.of(this, key));
-        }
-
-        @Override
-        public final boolean containsKey(String key) {
-            return containsKey((Object)key);
-        }
-
-        @Override
-        public final boolean containsKey(PrototypeField<?> key) {
-            return containsKey((Object)key);
-        }
-
-        @Override
-        public final Object put(String key, Object value) {
-            return put((Object)key, value);
-        }
-
-        @Override
-        public final <V> V put(PrototypeField<V> key, V value) {
-            return (V)put((Object)key, value);
-        }
-
-        @Override
-        public final Object get(String key) {
-            return get((Object)key);
-        }
-
-        @Override
-        public final <V> V get(PrototypeField<V> key) {
-            return (V)get((Object)key);
-        }
-
-        @Override
-        public final Optional<Object> getOptional(Object key) {
-            return Optional.ofNullable(get(key));
-        }
-
-        @Override
-        public final Optional<Object> getOptional(String key) {
-            return Optional.ofNullable(get(key));
-        }
-
-        @Override
-        public final <V> Optional<V> getOptional(PrototypeField<V> key) {
-            return Optional.ofNullable(get(key));
-        }
-
-        @Override
-        public final Object remove(String key) {
-            return remove((Object)key);
-        }
-
-        @Override
-        public final <V> V remove(PrototypeField<V> key) {
-            return (V)remove((Object)key);
-        }
-
-    }
-
-    public static final class SimpleEntry<V> extends AEntry<Object, V> implements PrototypeEntry<V> {
-        private final PrototypeMap scope;
-        private final PrototypeField<V> field;
-        private final IClass<V> type;
-        private final String name;
-        private final V value;
-
-        public SimpleEntry(PrototypeMap scope, PrototypeField<V> field, V value) {
-            this.scope = scope;
-            this.field = field;
-            this.type = field.type();
-            this.name = field.name();
-            this.value = value;
-        }
-
-        public SimpleEntry(PrototypeMap scope, IClass<V> type, String name, V value) {
-            this.scope = scope;
-            this.field = PrototypeField.of(type, name);
-            this.type = field.type();
-            this.name = field.name();
-            this.value = value;
-        }
-
-        @Override
-        public PrototypeMap getScope() {
-            return scope;
-        }
-
-        @Override
-        public Object getKey() {
-            return field;
-        }
-
-        @Override
-        public PrototypeField<V> getField() {
-            return field;
-        }
-
-        @Override
-        public IClass<V> getType() {
-            return type;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public V getValue() {
-            return value;
-        }
-
-        @Override
-        public V setValue(V value) {
-            throw new UnsupportedOperationException("SimpleEntry is immutable");
-        }
-    }
-
-    public static final class NameEntry extends AEntry<Object, Object> implements PrototypeEntry<Object> {
-        private final PrototypeMap scope;
-        private final String name;
-
-        public NameEntry(PrototypeMap scope, String name) {
-            this.scope = scope.getDeclaredMap();
-            this.name = name;
-        }
-
-        @Override
-        public PrototypeMap getScope() {
-            return scope;
-        }
-
-        @Override
-        public PrototypeField<Object> getField() {
-            return PrototypeField.of(name);
-        }
-
-        @Override
-        public IClass<Object> getType() {
-            return IClass.OBJECT;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public Object getKey() {
-            return name;
-        }
-
-        @Override
-        public Object getValue() {
-            return scope.get(name);
-        }
-
-        @Override
-        public Object setValue(Object value) {
-            return scope.put(name, value);
-        }
-    }
-
-    public static final class FieldEntry<V> extends AEntry<Object, V> implements PrototypeEntry<V> {
-        private final PrototypeMap scope;
-        private final PrototypeField<V> field;
-
-        public FieldEntry(PrototypeMap scope, PrototypeField<V> field) {
-            this.scope = scope.getDeclaredMap();
-            this.field = field;
-        }
-
-        @Override
-        public PrototypeMap getScope() {
-            return scope;
-        }
-
-        @Override
-        public PrototypeField<V> getField() {
-            return field;
-        }
-
-        @Override
-        public IClass<V> getType() {
-            return field.type();
-        }
-
-        @Override
-        public String getName() {
-            return field.name();
-        }
-
-        @Override
-        public Object getKey() {
-            return field;
-        }
-
-        @Override
-        public V getValue() {
-            return scope.get(field);
-        }
-
-        @Override
-        public V setValue(V value) {
-            return scope.put(field, value);
-        }
-    }
-}

+ 0 - 28
assira/src/main/java/net/ranides/assira/collection/prototype/PrototypeEntry.java

@@ -6,36 +6,8 @@ import java.util.Map;
 
 
 public interface PrototypeEntry<V> extends Map.Entry<Object, V> {
 public interface PrototypeEntry<V> extends Map.Entry<Object, V> {
 
 
-    PrototypeMap getScope();
-
-    PrototypeField<V> getField();
-
     IClass<V> getType();
     IClass<V> getType();
 
 
     String getName();
     String getName();
 
 
-    static PrototypeEntry<?> of(PrototypeMap scope, Object key) {
-        if(key instanceof String) {
-            return PrototypeEntry.of(scope, (String) key);
-        } else {
-            return PrototypeEntry.of(scope, (PrototypeField<?>)key);
-        }
-    }
-
-    static <V> PrototypeEntry<V> of(PrototypeMap scope, PrototypeField<V> field) {
-        return new AbstractPrototype.FieldEntry<>(scope, field);
-    }
-
-    static PrototypeEntry<Object> of(PrototypeMap scope, String name) {
-        return new AbstractPrototype.NameEntry(scope, name);
-    }
-
-    static <V> PrototypeEntry<V> of(PrototypeMap scope, PrototypeField<V> field, V value) {
-        return new AbstractPrototype.SimpleEntry<>(scope, field, value);
-    }
-
-    static PrototypeEntry<Object> of(PrototypeMap scope, String name, Object value) {
-        return new AbstractPrototype.SimpleEntry<>(scope, IClass.OBJECT, name, value);
-    }
-
 }
 }

+ 0 - 37
assira/src/main/java/net/ranides/assira/collection/prototype/PrototypeField.java

@@ -1,37 +0,0 @@
-package net.ranides.assira.collection.prototype;
-
-import lombok.EqualsAndHashCode;
-import net.ranides.assira.reflection.IClass;
-
-@EqualsAndHashCode
-public final class PrototypeField<V> {
-
-    private final IClass<V> type;
-    private final String name;
-
-    private PrototypeField(IClass<V> type, String name) {
-        this.type = type;
-        this.name = name;
-    }
-
-    public IClass<V> type() {
-        return type;
-    }
-
-    public String name() {
-        return name;
-    }
-
-    public static <V> PrototypeField<V> of(Class<V> type, String name) {
-        return new PrototypeField<>(IClass.typeinfo(type), name);
-    }
-
-    public static <V> PrototypeField<V> of(IClass<V> type, String name) {
-        return new PrototypeField<>(type, name);
-    }
-
-    public static PrototypeField<Object> of(String name) {
-        return new PrototypeField<>(IClass.OBJECT, name);
-    }
-
-}

+ 0 - 24
assira/src/main/java/net/ranides/assira/collection/prototype/PrototypeHashMap.java

@@ -1,24 +0,0 @@
-package net.ranides.assira.collection.prototype;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class PrototypeHashMap extends AbstractPrototype.CompositeMap {
-
-    public PrototypeHashMap() {
-        super(null, new HashMap<>());
-    }
-
-    public PrototypeHashMap(PrototypeMap parent) {
-        super(parent, new HashMap<>());
-    }
-
-    public PrototypeHashMap(Map<Object, ?> content) {
-        super(null, new HashMap<>(content));
-    }
-
-    public PrototypeHashMap(PrototypeMap parent, Map<Object, ?> content) {
-        super(parent, new HashMap<>(content));
-    }
-
-}

+ 39 - 0
assira/src/main/java/net/ranides/assira/collection/prototype/PrototypeKey.java

@@ -0,0 +1,39 @@
+package net.ranides.assira.collection.prototype;
+
+import lombok.EqualsAndHashCode;
+import net.ranides.assira.reflection.IClass;
+
+@EqualsAndHashCode
+public final class PrototypeKey<V> {
+
+    // TODO merge with net.ranides.assira.collection.maps.GenericKey ?
+
+    private final IClass<V> type;
+    private final String name;
+
+    private PrototypeKey(IClass<V> type, String name) {
+        this.type = type;
+        this.name = name;
+    }
+
+    public IClass<V> type() {
+        return type;
+    }
+
+    public String name() {
+        return name;
+    }
+
+    public static <V> PrototypeKey<V> of(Class<V> type, String name) {
+        return new PrototypeKey<>(IClass.typeinfo(type), name);
+    }
+
+    public static <V> PrototypeKey<V> of(IClass<V> type, String name) {
+        return new PrototypeKey<>(type, name);
+    }
+
+    public static PrototypeKey<Object> of(String name) {
+        return new PrototypeKey<>(IClass.OBJECT, name);
+    }
+
+}

+ 401 - 26
assira/src/main/java/net/ranides/assira/collection/prototype/PrototypeMap.java

@@ -1,51 +1,426 @@
 package net.ranides.assira.collection.prototype;
 package net.ranides.assira.collection.prototype;
 
 
-import org.jetbrains.annotations.NotNull;
+import net.ranides.assira.collection.iterators.RemoveIterator;
+import net.ranides.assira.collection.maps.AEntry;
+import net.ranides.assira.collection.sets.SetUtils;
+import net.ranides.assira.reflection.*;
 
 
-import net.ranides.assira.reflection.IClass;
+import java.util.*;
+import java.util.function.Consumer;
 
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
+public class PrototypeMap implements Map<Object, Object> {
 
 
-public interface PrototypeMap extends Map<Object, Object> {
+    public static final PrototypeMap EMPTY = new PrototypeMap(true);
 
 
-    PrototypeMap EMPTY = new AbstractPrototype.DeclaredMap(null, Collections.emptyMap());
+    private final PrototypeMap parent;
 
 
-    PrototypeMap getParentMap();
+    private final Map<Object, Object> declared;
 
 
-    PrototypeMap getDeclaredMap();
+    private transient KeysView keys;
+    private transient EntryView entries;
+    private transient ValuesView values;
 
 
-    Optional<PrototypeEntry<?>> getProperty(Object key);
+    public PrototypeMap() {
+        this(null, new HashMap<>());
+    }
 
 
-    Optional<PrototypeEntry<Object>> getProperty(String key);
+    public PrototypeMap(PrototypeMap parent) {
+        this(parent, new HashMap<>());
+    }
 
 
-    <V> Optional<PrototypeEntry<V>> getProperty(PrototypeField<V> key);
+    public PrototypeMap(Map<Object, ?> content) {
+        this(null, new HashMap<>(content));
+    }
 
 
-    Set<PrototypeEntry<?>> propertySet();
+    public PrototypeMap(PrototypeMap parent, Map<Object, ?> content) {
+        this.parent = parent;
+        this.declared = new HashMap<>(content);
+    }
 
 
-    boolean containsKey(String key);
+    private PrototypeMap(boolean empty) {
+        assert empty : "this is constructor for empty map";
+        this.parent = null;
+        this.declared = Collections.emptyMap();
+    }
 
 
-    boolean containsKey(PrototypeField<?> key);
+    public PrototypeMap getParentMap() {
+        return parent;
+    }
 
 
-    Object put(String key, Object value);
+    public Map<Object, Object> getDeclaredMap() {
+        return declared;
+    }
 
 
-    <V> V put(PrototypeField<V> key, V value);
+    @Override
+    public int size() {
+        return keySet().size();
+    }
 
 
-    Object get(String key);
+    @Override
+    public boolean isEmpty() {
+        return declared.isEmpty() && (parent==null || parent.isEmpty());
+    }
 
 
-    <V> V get(PrototypeField<V> key);
+    @Override
+    public boolean containsKey(Object key) {
+        return declared.containsKey(key) || (parent!=null && parent.containsKey(key));
+    }
 
 
-    Object remove(String key);
+    @Override
+    public boolean containsValue(Object value) {
+        return declared.containsValue(value) || (parent!=null && parent.containsKey(value));
+    }
 
 
-    <V> V remove(PrototypeField<V> key);
+    @Override
+    public Object get(Object key) {
+        for(PrototypeMap scope = this; scope != null; scope = scope.getParentMap()) {
+            Object out = scope.getDeclaredMap().get(key);
+            if(out != null) {
+                return out;
+            }
+        }
+        return null;
+    }
 
 
-    Optional<Object> getOptional(Object key);
+    @Override
+    public Object put(Object key, Object value) {
+        return declared.put(key, value);
+    }
 
 
-    Optional<Object> getOptional(String key);
+    @Override
+    public Object remove(Object key) {
+        Object[] out = {null};
+        forEachScope(scope -> {
+            Object rem = scope.remove(key);
+            if (rem != null && out[0] == null) {
+                out[0] = rem;
+            }
+        });
+        return out[0];
+    }
 
 
-    <V> Optional<V> getOptional(PrototypeField<V> key);
+    @Override
+    public void putAll(Map<?, ?> m) {
+        declared.putAll(m);
+    }
 
 
+    @Override
+    public void clear() {
+        forEachScope(Map::clear);
+    }
+
+    @Override
+    public Set<Object> keySet() {
+        if (keys == null) {
+            keys = new KeysView();
+        }
+        return keys;
+    }
+
+    @Override
+    public Collection<Object> values() {
+        if (values == null) {
+            values = new ValuesView();
+        }
+        return values;
+    }
+
+    @Override
+    public Set<Map.Entry<Object, Object>> entrySet() {
+        if (entries == null) {
+            entries = new EntryView();
+        }
+        return entries;
+    }
+
+    public final Optional<PrototypeEntry<?>> getProperty(Object key) {
+        if(containsKey(key)) {
+            if(key instanceof PrototypeKey<?>) {
+                return Optional.of(new FieldEntry<>((PrototypeKey<?>)key));
+            }
+            if(key instanceof String) {
+                return Optional.of(new NameEntry((String)key));
+            }
+        }
+        return Optional.empty();
+    }
+
+    public final Optional<PrototypeEntry<Object>> getProperty(String key) {
+        if(containsKey(key)) {
+            return Optional.of(new NameEntry(key));
+        }
+        return Optional.empty();
+    }
+
+    public final <V> Optional<PrototypeEntry<V>> getProperty(PrototypeKey<V> key) {
+        if(containsKey(key)) {
+            return Optional.of(new FieldEntry<>(key));
+        }
+        return Optional.empty();
+    }
+
+    public final Set<PrototypeEntry<?>> propertySet() {
+        return SetUtils.map(keySet(), this::newEntry);
+    }
+
+    public final boolean containsKey(String key) {
+        return containsKey((Object)key);
+    }
+
+    public final boolean containsKey(PrototypeKey<?> key) {
+        return containsKey((Object)key);
+    }
+
+    public final Object put(String key, Object value) {
+        return put((Object)key, value);
+    }
+
+    public final <V> V put(PrototypeKey<V> key, V value) {
+        if(key == null) {
+            return null;
+        }
+        return key.type().cast(put((Object)key, value));
+    }
+
+    public final Object get(String key) {
+        return get((Object)key);
+    }
+
+    public final <V> V get(PrototypeKey<V> key) {
+        if(key == null) {
+            return null;
+        }
+        return key.type().cast(get((Object)key));
+    }
+
+    public final Optional<Object> getOptional(Object key) {
+        return Optional.ofNullable(get(key));
+    }
+
+    public final Optional<Object> getOptional(String key) {
+        return Optional.ofNullable(get(key));
+    }
+
+    public final <V> Optional<V> getOptional(PrototypeKey<V> key) {
+        return Optional.ofNullable(get(key));
+    }
+
+    public final Object remove(String key) {
+        return remove((Object)key);
+    }
+
+    public final <V> V remove(PrototypeKey<V> key) {
+        if(key == null) {
+            return null;
+        }
+        return key.type().cast(remove((Object)key));
+    }
+
+    protected void forEachScope(Consumer<Map<Object, Object>> consumer) {
+        for(PrototypeMap scope = this; scope != null; scope = scope.getParentMap()) {
+            consumer.accept(scope.getDeclaredMap());
+        }
+    }
+
+    protected PrototypeEntry<?> newEntry(Object key) {
+        if(key instanceof String) {
+            return new NameEntry((String) key);
+        } else {
+            return new FieldEntry<>((PrototypeKey<?>)key);
+        }
+    }
+
+    private class EntryView extends AbstractSet<Map.Entry<Object, Object>> {
+        @Override
+        public boolean contains(Object other) {
+            if(other instanceof Map.Entry<?,?>) {
+                Map.Entry<?,?> entry = (Map.Entry<?,?>)other;
+                return Objects.equals(declared.get(entry.getKey()), entry.getValue());
+            }
+            return false;
+        }
+
+        @Override
+        public boolean add(Map.Entry<Object, Object> entry) {
+            Object key = entry.getKey();
+            Object val = entry.getValue();
+
+            if(key instanceof PrototypeKey<?>) {
+                PrototypeKey<?> field = (PrototypeKey<?>) key;
+                if(!field.type().isInstance(val)) {
+                    throw new ClassCastException(val + " can't be cast to " + field.type());
+                }
+            }
+            declared.put(key, val);
+            return true;
+        }
+
+        @Override
+        public boolean remove(Object other) {
+            if(other instanceof Map.Entry<?,?>) {
+                Map.Entry<?,?> entry = (Map.Entry<?,?>)other;
+                return declared.remove(entry.getKey(), entry.getValue());
+            }
+            return false;
+        }
+
+        @Override
+        public void clear() {
+            PrototypeMap.this.clear();
+        }
+
+        @Override
+        public Iterator<Map.Entry<Object, Object>> iterator() {
+            return new RemoveIterator<>(aggregate().iterator(), this::remove);
+        }
+
+        @Override
+        public int size() {
+            return aggregate().size();
+        }
+
+        public Set<Map.Entry<Object, Object>> aggregate() {
+            Set<Map.Entry<Object, Object>> set = new HashSet<>();
+            forEachScope(scope -> set.addAll(scope.entrySet()));
+            return set;
+        }
+    }
+
+    private class ValuesView extends AbstractSet<Object> {
+        @Override
+        public boolean contains(Object other) {
+            return PrototypeMap.this.containsValue(other);
+        }
+
+        @Override
+        public void clear() {
+            PrototypeMap.this.clear();
+        }
+
+        @Override
+        public Iterator<Object> iterator() {
+            return aggregate().iterator();
+        }
+
+        @Override
+        public int size() {
+            return aggregate().size();
+        }
+
+        public Collection<Object> aggregate() {
+            if(parent == null) {
+                return declared.values();
+            }
+            Set<Object> inserted = new HashSet<>();
+            List<Object> list = new ArrayList<>();
+            forEachScope(scope -> {
+                scope.forEach((key, value) -> {
+                    if(inserted.add(key)) {
+                        list.add(value);
+                    }
+                });
+            });
+
+            return list;
+        }
+    }
+
+    private class KeysView extends AbstractSet<Object> {
+        @Override
+        public boolean contains(Object other) {
+            return PrototypeMap.this.containsKey(other);
+        }
+
+        @Override
+        public boolean remove(Object key) {
+            return PrototypeMap.this.remove(key) != null;
+        }
+
+        @Override
+        public void clear() {
+            PrototypeMap.this.clear();
+        }
+
+        @Override
+        public Iterator<Object> iterator() {
+            return new RemoveIterator<>(aggregate().iterator(), this::remove);
+        }
+
+        @Override
+        public int size() {
+            return aggregate().size();
+        }
+
+        public Set<Object> aggregate() {
+            Set<Object> set = new HashSet<>();
+            forEachScope(scope -> set.addAll(scope.keySet()));
+            return set;
+        }
+    }
+
+    private final class NameEntry extends AEntry<Object, Object> implements PrototypeEntry<Object> {
+        private final String name;
+
+        public NameEntry(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public IClass<Object> getType() {
+            return IClass.OBJECT;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public Object getKey() {
+            return name;
+        }
+
+        @Override
+        public Object getValue() {
+            return declared.get(name);
+        }
+
+        @Override
+        public Object setValue(Object value) {
+            return declared.put(name, value);
+        }
+    }
+
+    private final class FieldEntry<V> extends AEntry<Object, V> implements PrototypeEntry<V> {
+        private final PrototypeKey<V> field;
+
+        public FieldEntry(PrototypeKey<V> field) {
+            this.field = field;
+        }
+
+        @Override
+        public IClass<V> getType() {
+            return field.type();
+        }
+
+        @Override
+        public String getName() {
+            return field.name();
+        }
+
+        @Override
+        public Object getKey() {
+            return field;
+        }
+
+        @Override
+        public V getValue() {
+            return field.type().cast(declared.get(field));
+        }
+
+        @Override
+        public V setValue(V value) {
+            return field.type().cast(declared.put(field, value));
+        }
+    }
 }
 }

+ 3 - 4
assira/src/main/java/net/ranides/assira/reflection/walker/ObjectVisitor.java

@@ -1,8 +1,7 @@
 package net.ranides.assira.reflection.walker;
 package net.ranides.assira.reflection.walker;
 
 
-import net.ranides.assira.collection.prototype.PrototypeHashMap;
 import net.ranides.assira.collection.prototype.PrototypeMap;
 import net.ranides.assira.collection.prototype.PrototypeMap;
-import net.ranides.assira.reflection.ResolveContext;
+import net.ranides.assira.reflection.*;
 import net.ranides.assira.reflection.walker.WalkerContexts.ObjectContext;
 import net.ranides.assira.reflection.walker.WalkerContexts.ObjectContext;
 
 
 import java.io.PrintWriter;
 import java.io.PrintWriter;
@@ -66,11 +65,11 @@ public interface ObjectVisitor {
 
 
     abstract class PrintVisitor implements ObjectVisitor {
     abstract class PrintVisitor implements ObjectVisitor {
         private final PrintWriter target;
         private final PrintWriter target;
-        private final PrototypeHashMap scope;
+        private final PrototypeMap scope;
 
 
         protected PrintVisitor(PrintWriter target, Map<Object, ?> map) {
         protected PrintVisitor(PrintWriter target, Map<Object, ?> map) {
             this.target = target;
             this.target = target;
-            this.scope = new PrototypeHashMap(map);
+            this.scope = new PrototypeMap(map);
         }
         }
 
 
         public PrintWriter writer() {
         public PrintWriter writer() {

+ 1 - 2
assira/src/main/java/net/ranides/assira/reflection/walker/ObjectWalker.java

@@ -1,7 +1,6 @@
 package net.ranides.assira.reflection.walker;
 package net.ranides.assira.reflection.walker;
 
 
 import net.ranides.assira.collection.arrays.NativeArray;
 import net.ranides.assira.collection.arrays.NativeArray;
-import net.ranides.assira.collection.prototype.PrototypeHashMap;
 import net.ranides.assira.collection.prototype.PrototypeMap;
 import net.ranides.assira.collection.prototype.PrototypeMap;
 import net.ranides.assira.functional.special.LazyFunction;
 import net.ranides.assira.functional.special.LazyFunction;
 import net.ranides.assira.generic.LazyReference;
 import net.ranides.assira.generic.LazyReference;
@@ -76,7 +75,7 @@ public class ObjectWalker {
         private final LazyFunction<String> idPath = LazyReference.concurrent();
         private final LazyFunction<String> idPath = LazyReference.concurrent();
 
 
         private final Supplier<PrototypeMap> custom = LazyReference.concurrent(() -> {
         private final Supplier<PrototypeMap> custom = LazyReference.concurrent(() -> {
-            return new PrototypeHashMap(visitor.scope().getResolveMap());
+            return new PrototypeMap(visitor.scope().getResolveMap());
         });
         });
 
 
         public CAbstract(ObjectContext<?> parent, IField field, Object value) {
         public CAbstract(ObjectContext<?> parent, IField field, Object value) {

+ 1 - 2
assira/src/main/java/net/ranides/assira/reflection/walker/WalkerRules.java

@@ -2,8 +2,7 @@ package net.ranides.assira.reflection.walker;
 
 
 import lombok.Data;
 import lombok.Data;
 
 
-import net.ranides.assira.collection.prototype.PrototypeHashMap;
-import net.ranides.assira.reflection.IClass;
+import net.ranides.assira.reflection.*;
 import net.ranides.assira.reflection.walker.ObjectVisitor.PrintVisitor;
 import net.ranides.assira.reflection.walker.ObjectVisitor.PrintVisitor;
 import net.ranides.assira.reflection.walker.WalkerContexts.ArrayContext;
 import net.ranides.assira.reflection.walker.WalkerContexts.ArrayContext;
 import net.ranides.assira.reflection.walker.WalkerContexts.ObjectContext;
 import net.ranides.assira.reflection.walker.WalkerContexts.ObjectContext;

+ 13 - 18
assira/src/test/java/net/ranides/assira/collection/prototype/PrototypeHashMapTest.java

@@ -1,40 +1,35 @@
 package net.ranides.assira.collection.prototype;
 package net.ranides.assira.collection.prototype;
 
 
+import org.junit.Before;
+import org.junit.Test;
+
 import net.ranides.assira.ContractTesters;
 import net.ranides.assira.ContractTesters;
-import net.ranides.assira.collection.maps.HashMap;
 import net.ranides.assira.collection.mockup.TMaps;
 import net.ranides.assira.collection.mockup.TMaps;
-import net.ranides.assira.collection.mockup.TPoint;
 import net.ranides.assira.collection.sets.HashSet;
 import net.ranides.assira.collection.sets.HashSet;
 import net.ranides.assira.test.TMap;
 import net.ranides.assira.test.TMap;
 
 
-import org.junit.Before;
-import org.junit.Test;
-
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.Map;
 import java.util.Set;
 import java.util.Set;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
 
 
-import static net.ranides.assira.junit.NewAssert.assertThrows;
 import static org.junit.Assert.*;
 import static org.junit.Assert.*;
-import static org.junit.Assert.assertNotNull;
 
 
-public class PrototypeHashMapTest {
+public class PrototypeMapTest {
 
 
     private final TMap<Object, Object> $map = TMaps.MAP_SI;
     private final TMap<Object, Object> $map = TMaps.MAP_SI;
 
 
-    PrototypeHashMap map1;
-    PrototypeHashMap map2;
-    PrototypeHashMap map3;
-    PrototypeHashMap map4;
+    PrototypeMap map1;
+    PrototypeMap map2;
+    PrototypeMap map3;
+    PrototypeMap map4;
 
 
     @Before
     @Before
     public void init() {
     public void init() {
-        map1 = new PrototypeHashMap();
-        map2 = new PrototypeHashMap(map1);
-        map3 = new PrototypeHashMap(map2);
-        map4 = new PrototypeHashMap(map3);
+        map1 = new PrototypeMap();
+        map2 = new PrototypeMap(map1);
+        map3 = new PrototypeMap(map2);
+        map4 = new PrototypeMap(map3);
 
 
         map1.getDeclaredMap().put("a", 11);
         map1.getDeclaredMap().put("a", 11);
         map1.getDeclaredMap().put("b", 12);
         map1.getDeclaredMap().put("b", 12);
@@ -49,7 +44,7 @@ public class PrototypeHashMapTest {
         ContractTesters.runner()
         ContractTesters.runner()
             .param("map!", $map)
             .param("map!", $map)
             .ignore(Pattern.compile(".*_HC"))
             .ignore(Pattern.compile(".*_HC"))
-            .function(new int[0], array -> $map.list(array).into(new PrototypeHashMap()))
+            .function(new int[0], array -> $map.list(array).into(new PrototypeMap()))
             .run();
             .run();
     }
     }
 
 

+ 1 - 2
assira/src/test/java/net/ranides/assira/reflection/mockup/ForResolver.java

@@ -8,7 +8,6 @@
 package net.ranides.assira.reflection.mockup;
 package net.ranides.assira.reflection.mockup;
 
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import net.ranides.assira.collection.prototype.PrototypeHashMap;
 import net.ranides.assira.collection.prototype.PrototypeMap;
 import net.ranides.assira.collection.prototype.PrototypeMap;
 import net.ranides.assira.reflection.ResolveContext;
 import net.ranides.assira.reflection.ResolveContext;
 
 
@@ -49,7 +48,7 @@ public final class ForResolver {
     }
     }
 
 
     public static class APlus extends A implements ResolveContext {
     public static class APlus extends A implements ResolveContext {
-        private final PrototypeMap context = new PrototypeHashMap();
+        private final PrototypeMap context = new PrototypeMap();
 
 
         @Override
         @Override
         public PrototypeMap getResolveMap() {
         public PrototypeMap getResolveMap() {