package potemkin; import clojure.lang.*; import java.util.Iterator; import java.util.Set; public class PersistentMapProxy extends APersistentMap { public interface IMap { Object get(Object k, Object defaultValue); Set keySet(); IMap assoc(Object k, Object v); IMap dissoc(Object k); IMap empty(); } public interface IEquality { boolean eq(Object o); int hash(); } public static class MapEntry extends clojure.lang.MapEntry { private final Object _key; private final ILookup _lookup; public MapEntry(ILookup lookup, Object key) { super(key, null); _key = key; _lookup = lookup; } @Override public Object val() { return _lookup.valAt(_key, null); } } private final IMap _map; private final IPersistentMap _meta; public PersistentMapProxy(IMap map) { this._map = map; this._meta = null; } public PersistentMapProxy(IMap map, IPersistentMap meta) { this._map = map; this._meta = meta; } public IMap innerMap() { return _map; } public IPersistentMap meta() { return _meta; } public IPersistentMap withMeta(IPersistentMap meta) { return new PersistentMapProxy(_map, meta); } @Override public int hashCode() { return (_map instanceof IEquality) ? ((IEquality)_map).hash() : super.hashCode(); } public boolean equals(Object o) { if (_map instanceof IEquality) { IEquality map = (IEquality)_map; return (o instanceof PersistentMapProxy) ? map.eq(((PersistentMapProxy)o).innerMap()) : map.eq(o); } return super.equals(o); } @Override public boolean containsKey(Object k) { return _map.keySet().contains(k); } @Override public IMapEntry entryAt(Object k) { return containsKey(k) ? new MapEntry(this, k) : null; } @Override public IPersistentMap assoc(Object k, Object v) { return new PersistentMapProxy(_map.assoc(k, v)); } @Override public IPersistentMap assocEx(Object k, Object v) { if (containsKey(k)) { throw new IllegalStateException("key already contained in map"); } return assoc(k, v); } @Override public IPersistentMap without(Object k) { return new PersistentMapProxy(_map.dissoc(k)); } @Override public Object valAt(Object k) { return _map.get(k, null); } @Override public Object valAt(Object k, Object defaultValue) { return _map.get(k, defaultValue); } @Override public int count() { return _map.keySet().size(); } @Override public IPersistentCollection empty() { IMap empty = _map.empty(); return empty != null ? new PersistentMapProxy(_map.empty()) : PersistentHashMap.EMPTY; } @Override public Iterator iterator() { final Iterator i = _map.keySet().iterator(); final ILookup l = this; return new Iterator() { @Override public boolean hasNext() { return i.hasNext(); } @Override public Object next() { Object k = i.next(); return new clojure.lang.MapEntry(k, l.valAt(k, null)); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public ISeq seq() { return IteratorSeq.create(iterator()); } }