summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2008-10-06 13:26:31 +0000
committerRich Hickey <richhickey@gmail.com>2008-10-06 13:26:31 +0000
commit7de158ba6ee7cbf73e9f91fce4d038dd73b40789 (patch)
treeddee07fa136e5e91fd2538bfe3f08d8bfa201c5d /src
parent2763e3f0dea103890bb6f8fe407186f257a29e35 (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.clj8
-rw-r--r--src/jvm/clojure/lang/AMapEntry.java50
-rw-r--r--src/jvm/clojure/lang/APersistentMap.java151
-rw-r--r--src/jvm/clojure/lang/APersistentSet.java21
-rw-r--r--src/jvm/clojure/lang/APersistentVector.java44
-rw-r--r--src/jvm/clojure/lang/MapEntry.java4
-rw-r--r--src/jvm/clojure/lang/PersistentHashMap.java4
-rw-r--r--src/jvm/clojure/lang/PersistentTreeMap.java4
-rw-r--r--src/jvm/clojure/lang/RT.java2
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();