diff options
author | Rich Hickey <richhickey@gmail.com> | 2008-10-06 13:26:31 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2008-10-06 13:26:31 +0000 |
commit | 7de158ba6ee7cbf73e9f91fce4d038dd73b40789 (patch) | |
tree | ddee07fa136e5e91fd2538bfe3f08d8bfa201c5d /src | |
parent | 2763e3f0dea103890bb6f8fe407186f257a29e35 (diff) |
made maps implement java.util.Map
unified equality and hashCode semantics for sets/maps/lists with java.util
enabled sort on all colls and strings
enabled to-array on Maps
Diffstat (limited to 'src')
-rw-r--r-- | src/clj/clojure/boot.clj | 8 | ||||
-rw-r--r-- | src/jvm/clojure/lang/AMapEntry.java | 50 | ||||
-rw-r--r-- | src/jvm/clojure/lang/APersistentMap.java | 151 | ||||
-rw-r--r-- | src/jvm/clojure/lang/APersistentSet.java | 21 | ||||
-rw-r--r-- | src/jvm/clojure/lang/APersistentVector.java | 44 | ||||
-rw-r--r-- | src/jvm/clojure/lang/MapEntry.java | 4 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentHashMap.java | 4 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentTreeMap.java | 4 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 2 |
9 files changed, 239 insertions, 49 deletions
diff --git a/src/clj/clojure/boot.clj b/src/clj/clojure/boot.clj index e0dd3040..40c90a03 100644 --- a/src/clj/clojure/boot.clj +++ b/src/clj/clojure/boot.clj @@ -1405,11 +1405,11 @@ "Returns a sorted sequence of the items in coll. If no comparator is supplied, uses compare. comparator must implement java.util.Comparator." - ([#^java.util.Collection coll] + ([coll] (sort compare coll)) - ([#^java.util.Comparator comp #^java.util.Collection coll] - (when (and coll (not (. coll (isEmpty)))) - (let [a (. coll (toArray))] + ([#^java.util.Comparator comp coll] + (when (and coll (not (zero? (count coll)))) + (let [a (to-array coll)] (. java.util.Arrays (sort a comp)) (seq a))))) diff --git a/src/jvm/clojure/lang/AMapEntry.java b/src/jvm/clojure/lang/AMapEntry.java index 5496f0eb..7481e0fd 100644 --- a/src/jvm/clojure/lang/AMapEntry.java +++ b/src/jvm/clojure/lang/AMapEntry.java @@ -14,18 +14,59 @@ package clojure.lang; import java.io.StringWriter; -public abstract class AMapEntry implements IMapEntry, IPersistentVector{ +public abstract class AMapEntry extends APersistentVector implements IMapEntry{ + +public Object nth(int i){ + if(i == 0) + return key(); + else if(i == 1) + return val(); + else + throw new IndexOutOfBoundsException(); +} + +private IPersistentVector asVector(){ + return LazilyPersistentVector.createOwning(key(), val()); +} + +public IPersistentVector assocN(int i, Object val){ + return asVector().assocN(i, val); +} + +public int count(){ + return 2; +} + +public ISeq seq(){ + return asVector().seq(); +} + +public IPersistentVector cons(Object o){ + return asVector().cons(o); +} + public IPersistentCollection empty(){ return null; } +public IPersistentStack pop(){ + return LazilyPersistentVector.createOwning(key()); +} + +public Object setValue(Object value){ + throw new UnsupportedOperationException(); +} + +/* + public boolean equals(Object obj){ return APersistentVector.doEquals(this, obj); } public int hashCode(){ //must match logic in APersistentVector - return Util.hashCombine(Util.hashCombine(0, Util.hash(key())), Util.hash(val())); + return 31 * (31 + Util.hash(key())) + Util.hash(val()); +// return Util.hashCombine(Util.hashCombine(0, Util.hash(key())), Util.hash(val())); } public String toString(){ @@ -99,11 +140,10 @@ public Object peek(){ return val(); } -public IPersistentStack pop(){ - return LazilyPersistentVector.createOwning(key()); -} public ISeq rseq() throws Exception{ return asVector().rseq(); } +*/ + } diff --git a/src/jvm/clojure/lang/APersistentMap.java b/src/jvm/clojure/lang/APersistentMap.java index b112d982..c9a617ed 100644 --- a/src/jvm/clojure/lang/APersistentMap.java +++ b/src/jvm/clojure/lang/APersistentMap.java @@ -10,10 +10,9 @@ package clojure.lang;
-import java.util.Collection;
-import java.util.Map;
+import java.util.*;
-public abstract class APersistentMap extends AFn implements IPersistentMap, Collection{
+public abstract class APersistentMap extends AFn implements IPersistentMap, Map, Iterable{
int _hash = -1;
@@ -54,19 +53,19 @@ public IPersistentCollection cons(Object o){ }
public boolean equals(Object obj){
- if(!(obj instanceof IPersistentMap))
+ if(!(obj instanceof Map))
return false;
- IPersistentMap m = (IPersistentMap) obj;
+ Map m = (Map) obj;
- if(m.count() != count() || m.hashCode() != hashCode())
+ if(m.size() != size() || m.hashCode() != hashCode())
return false;
for(ISeq s = seq(); s != null; s = s.rest())
{
Map.Entry e = (Map.Entry) s.first();
- Map.Entry me = m.entryAt(e.getKey());
+ boolean found = m.containsKey(e.getKey());
- if(me == null || !Util.equal(e.getValue(), me.getValue()))
+ if(!found || !Util.equal(e.getValue(), m.get(e.getKey())))
return false;
}
@@ -76,11 +75,14 @@ public boolean equals(Object obj){ public int hashCode(){
if(_hash == -1)
{
- int hash = count();
+ //int hash = count();
+ int hash = 0;
for(ISeq s = seq(); s != null; s = s.rest())
{
Map.Entry e = (Map.Entry) s.first();
- hash ^= Util.hashCombine(Util.hash(e.getKey()), Util.hash(e.getValue()));
+ hash += (e.getKey() == null ? 0 : e.getKey().hashCode()) ^
+ (e.getValue() == null ? 0 : e.getValue().hashCode());
+ //hash ^= Util.hashCombine(Util.hash(e.getKey()), Util.hash(e.getValue()));
}
this._hash = hash;
}
@@ -158,6 +160,133 @@ public Object invoke(Object arg1, Object notFound) throws Exception{ return valAt(arg1, notFound);
}
+// java.util.Map implementation
+
+public void clear(){
+ throw new UnsupportedOperationException();
+}
+
+public boolean containsValue(Object value){
+ return values().contains(value);
+}
+
+public Set entrySet(){
+ return new AbstractSet(){
+
+ public Iterator iterator(){
+ return APersistentMap.this.iterator();
+ }
+
+ public int size(){
+ return count();
+ }
+
+ public int hashCode(){
+ return APersistentMap.this.hashCode();
+ }
+
+ public boolean contains(Object o){
+ if(o instanceof Entry)
+ {
+ Entry e = (Entry) o;
+ Entry found = entryAt(e.getKey());
+ if(found != null && Util.equal(found.getValue(), e.getValue()))
+ return true;
+ }
+ return false;
+ }
+ };
+}
+
+public Object get(Object key){
+ return valAt(key);
+}
+
+public boolean isEmpty(){
+ return count() == 0;
+}
+
+public Set keySet(){
+ return new AbstractSet(){
+
+ public Iterator iterator(){
+ final Iterator mi = APersistentMap.this.iterator();
+
+ return new Iterator(){
+
+
+ public boolean hasNext(){
+ return mi.hasNext();
+ }
+
+ public Object next(){
+ Entry e = (Entry) mi.next();
+ return e.getKey();
+ }
+
+ public void remove(){
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public int size(){
+ return count();
+ }
+
+ public boolean contains(Object o){
+ return APersistentMap.this.containsKey(o);
+ }
+ };
+}
+
+public Object put(Object key, Object value){
+ throw new UnsupportedOperationException();
+}
+
+public void putAll(Map t){
+ throw new UnsupportedOperationException();
+}
+
+public Object remove(Object key){
+ throw new UnsupportedOperationException();
+}
+
+public int size(){
+ return count();
+}
+
+public Collection values(){
+ return new AbstractCollection(){
+
+ public Iterator iterator(){
+ final Iterator mi = APersistentMap.this.iterator();
+
+ return new Iterator(){
+
+
+ public boolean hasNext(){
+ return mi.hasNext();
+ }
+
+ public Object next(){
+ Entry e = (Entry) mi.next();
+ return e.getValue();
+ }
+
+ public void remove(){
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public int size(){
+ return count();
+ }
+ };
+}
+
+/*
// java.util.Collection implementation
public Object[] toArray(){
@@ -230,5 +359,5 @@ public boolean contains(Object o){ }
return false;
}
-
+*/
}
diff --git a/src/jvm/clojure/lang/APersistentSet.java b/src/jvm/clojure/lang/APersistentSet.java index 7cf94c31..7abf6608 100644 --- a/src/jvm/clojure/lang/APersistentSet.java +++ b/src/jvm/clojure/lang/APersistentSet.java @@ -46,18 +46,23 @@ public Object invoke(Object arg1) throws Exception{ } public boolean equals(Object obj){ - if(!(obj instanceof IPersistentSet)) + if(!(obj instanceof Set)) return false; - IPersistentSet m = (IPersistentSet) obj; + Set m = (Set) obj; - if(m.count() != count() || m.hashCode() != hashCode()) + if(m.size() != count() || m.hashCode() != hashCode()) return false; - for(ISeq s = seq(); s != null; s = s.rest()) + for(Object aM : m) { - if(!m.contains(s.first())) + if(!m.contains(aM)) return false; } +// for(ISeq s = seq(); s != null; s = s.rest()) +// { +// if(!m.contains(s.first())) +// return false; +// } return true; } @@ -65,11 +70,13 @@ public boolean equals(Object obj){ public int hashCode(){ if(_hash == -1) { - int hash = count(); + //int hash = count(); + int hash = 0; for(ISeq s = seq(); s != null; s = s.rest()) { Object e = s.first(); - hash = Util.hashCombine(hash, Util.hash(e)); +// hash = Util.hashCombine(hash, Util.hash(e)); + hash += Util.hash(e); } this._hash = hash; } diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java index 631273c9..42c9bd8f 100644 --- a/src/jvm/clojure/lang/APersistentVector.java +++ b/src/jvm/clojure/lang/APersistentVector.java @@ -14,7 +14,8 @@ package clojure.lang; import java.util.*; -public abstract class APersistentVector extends AFn implements IPersistentVector, Iterable, Collection, List, +public abstract class APersistentVector extends AFn implements IPersistentVector, Iterable, + List, RandomAccess, Comparable{ int _hash = -1; @@ -22,6 +23,9 @@ public APersistentVector(IPersistentMap meta){ super(meta); } +protected APersistentVector(){ +} + public String toString(){ return "<vector: - " + count() + " items>"; } @@ -39,17 +43,30 @@ public ISeq rseq(){ } static boolean doEquals(IPersistentVector v, Object obj){ - if(obj instanceof IPersistentVector) + if(obj instanceof List || obj instanceof IPersistentVector) { - IPersistentVector ma = (IPersistentVector) obj; - if(ma.count() != v.count() || ma.hashCode() != v.hashCode()) + Collection ma = (Collection) obj; + if(ma.size() != v.count() || ma.hashCode() != v.hashCode()) return false; - for(int i = 0; i < v.count(); i++) + for(Iterator i1 = ((List) v).iterator(), i2 = ma.iterator(); + i1.hasNext();) { - if(!Util.equal(v.nth(i), ma.nth(i))) + if(!Util.equal(i1.next(), i2.next())) return false; } + return true; } +// if(obj instanceof IPersistentVector) +// { +// IPersistentVector ma = (IPersistentVector) obj; +// if(ma.count() != v.count() || ma.hashCode() != v.hashCode()) +// return false; +// for(int i = 0; i < v.count(); i++) +// { +// if(!Util.equal(v.nth(i), ma.nth(i))) +// return false; +// } +// } else { if(!(obj instanceof Sequential)) @@ -75,11 +92,18 @@ public boolean equals(Object obj){ public int hashCode(){ if(_hash == -1) { - int hash = 0; - for(int i = 0; i < count(); i++) + int hash = 1; + Iterator i = iterator(); + while(i.hasNext()) { - hash = Util.hashCombine(hash, Util.hash(nth(i))); + Object obj = i.next(); + hash = 31 * hash + (obj == null ? 0 : obj.hashCode()); } +// int hash = 0; +// for(int i = 0; i < count(); i++) +// { +// hash = Util.hashCombine(hash, Util.hash(nth(i))); +// } this._hash = hash; } return _hash; @@ -116,7 +140,7 @@ public ListIterator listIterator(final int index){ int nexti = index; public boolean hasNext(){ - return nexti < count() - 1; + return nexti < count(); } public Object next(){ diff --git a/src/jvm/clojure/lang/MapEntry.java b/src/jvm/clojure/lang/MapEntry.java index 0b6d7271..7bc61080 100644 --- a/src/jvm/clojure/lang/MapEntry.java +++ b/src/jvm/clojure/lang/MapEntry.java @@ -37,8 +37,4 @@ public Object getValue(){ return val();
}
-public Object setValue(Object value){
- throw new UnsupportedOperationException();
-}
-
}
diff --git a/src/jvm/clojure/lang/PersistentHashMap.java b/src/jvm/clojure/lang/PersistentHashMap.java index db304a0f..9d9e8a7b 100644 --- a/src/jvm/clojure/lang/PersistentHashMap.java +++ b/src/jvm/clojure/lang/PersistentHashMap.java @@ -552,10 +552,6 @@ final static class LeafNode extends AMapEntry implements INode{ public Object getValue(){ return this.val; } - - public Object setValue(Object value){ - throw new UnsupportedOperationException(); - } } final static class HashCollisionNode implements INode{ diff --git a/src/jvm/clojure/lang/PersistentTreeMap.java b/src/jvm/clojure/lang/PersistentTreeMap.java index a89cab38..f1f960cf 100644 --- a/src/jvm/clojure/lang/PersistentTreeMap.java +++ b/src/jvm/clojure/lang/PersistentTreeMap.java @@ -484,10 +484,6 @@ static abstract class Node extends AMapEntry{ return val(); } - public Object setValue(Object value){ - throw new UnsupportedOperationException(); - } - Node left(){ return null; } diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 2a01ab36..0a891bf2 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -1044,6 +1044,8 @@ static public Object[] toArray(Object coll) throws Exception{ return (Object[]) coll; else if(coll instanceof Collection) return ((Collection) coll).toArray(); + else if(coll instanceof Map) + return ((Map) coll).entrySet().toArray(); else if(coll instanceof String) { char[] chars = ((String) coll).toCharArray(); |