summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2009-01-15 15:50:30 +0000
committerRich Hickey <richhickey@gmail.com>2009-01-15 15:50:30 +0000
commit8f0a24409ce9e905222b03377175533e1cab3be6 (patch)
treebf96e3b9845171ee8234ed76ee78441d5df80fd0 /src
parent9fcd8aea5940019c7d5ee25ddaf4b43f6339a326 (diff)
hashCode/equals/= cleanup, maximize alignment with j.u.Collections
seqs/lists now implement List
Diffstat (limited to 'src')
-rw-r--r--src/clj/clojure/core.clj12
-rw-r--r--src/jvm/clojure/lang/APersistentMap.java23
-rw-r--r--src/jvm/clojure/lang/APersistentSet.java4
-rw-r--r--src/jvm/clojure/lang/APersistentVector.java57
-rw-r--r--src/jvm/clojure/lang/ASeq.java87
-rw-r--r--src/jvm/clojure/lang/Compiler.java6
-rw-r--r--src/jvm/clojure/lang/IPersistentCollection.java2
-rw-r--r--src/jvm/clojure/lang/PersistentHashMap.java6
-rw-r--r--src/jvm/clojure/lang/PersistentList.java67
-rw-r--r--src/jvm/clojure/lang/PersistentQueue.java18
-rw-r--r--src/jvm/clojure/lang/RT.java6
-rw-r--r--src/jvm/clojure/lang/Util.java10
12 files changed, 257 insertions, 41 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index e0ebaf65..d21c3f02 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -458,14 +458,14 @@
(defn =
"Equality. Returns true if x equals y, false if not. Same as
Java x.equals(y) except it also works for nil, and compares
- numbers in a type-independent manner. Clojure's immutable data
+ numbers and collections in a type-independent manner. Clojure's immutable data
structures define equals() (and thus =) as a value, not an identity,
comparison."
{:tag Boolean
- :inline (fn [x y] `(. clojure.lang.Util equal ~x ~y))
+ :inline (fn [x y] `(. clojure.lang.Util equiv ~x ~y))
:inline-arities #{2}}
([x] true)
- ([x y] (. clojure.lang.Util (equal x y)))
+ ([x y] (clojure.lang.Util/equiv x y))
([x y & more]
(if (= x y)
(if (rest more)
@@ -486,8 +486,8 @@
(defn compare
"Comparator. Returns 0 if x equals y, -1 if x is logically 'less
than' y, else 1. Same as Java x.compareTo(y) except it also works
- for nil, and compares numbers in a type-independent manner. x must
- implement Comparable"
+ for nil, and compares numbers and collections in a type-independent
+ manner. x must implement Comparable"
{:tag Integer
:inline (fn [x y] `(. clojure.lang.Util compare ~x ~y))}
[x y] (. clojure.lang.Util (compare x y)))
@@ -3237,7 +3237,7 @@
(defn distinct?
- "Returns true if no two of the arguments are equal"
+ "Returns true if no two of the arguments are ="
{:tag Boolean}
([x] true)
([x y] (not (= x y)))
diff --git a/src/jvm/clojure/lang/APersistentMap.java b/src/jvm/clojure/lang/APersistentMap.java
index c90538ae..4d8bc8f7 100644
--- a/src/jvm/clojure/lang/APersistentMap.java
+++ b/src/jvm/clojure/lang/APersistentMap.java
@@ -65,13 +65,32 @@ public boolean equals(Object obj){
Map.Entry e = (Map.Entry) s.first();
boolean found = m.containsKey(e.getKey());
- if(!found || !Util.equal(e.getValue(), m.get(e.getKey())))
+ if(!found || !Util.equals(e.getValue(), m.get(e.getKey())))
return false;
}
return true;
}
+public boolean equiv(Object obj){
+ if(!(obj instanceof Map))
+ return false;
+ Map m = (Map) obj;
+
+ if(m.size() != size())
+ return false;
+
+ for(ISeq s = seq(); s != null; s = s.rest())
+ {
+ Map.Entry e = (Map.Entry) s.first();
+ boolean found = m.containsKey(e.getKey());
+
+ if(!found || !Util.equiv(e.getValue(), m.get(e.getKey())))
+ return false;
+ }
+
+ return true;
+}
public int hashCode(){
if(_hash == -1)
{
@@ -190,7 +209,7 @@ public Set entrySet(){
{
Entry e = (Entry) o;
Entry found = entryAt(e.getKey());
- if(found != null && Util.equal(found.getValue(), e.getValue()))
+ if(found != null && Util.equals(found.getValue(), e.getValue()))
return true;
}
return false;
diff --git a/src/jvm/clojure/lang/APersistentSet.java b/src/jvm/clojure/lang/APersistentSet.java
index b48b377c..36063276 100644
--- a/src/jvm/clojure/lang/APersistentSet.java
+++ b/src/jvm/clojure/lang/APersistentSet.java
@@ -71,6 +71,10 @@ public boolean equals(Object obj){
return true;
}
+public boolean equiv(Object o){
+ return equals(o);
+}
+
public int hashCode(){
if(_hash == -1)
{
diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java
index 0ecf9263..fe891ef7 100644
--- a/src/jvm/clojure/lang/APersistentVector.java
+++ b/src/jvm/clojure/lang/APersistentVector.java
@@ -52,7 +52,7 @@ static boolean doEquals(IPersistentVector v, Object obj){
for(Iterator i1 = ((List) v).iterator(), i2 = ma.iterator();
i1.hasNext();)
{
- if(!Util.equal(i1.next(), i2.next()))
+ if(!Util.equals(i1.next(), i2.next()))
return false;
}
return true;
@@ -75,7 +75,50 @@ static boolean doEquals(IPersistentVector v, Object obj){
ISeq ms = ((IPersistentCollection) obj).seq();
for(int i = 0; i < v.count(); i++, ms = ms.rest())
{
- if(ms == null || !Util.equal(v.nth(i), ms.first()))
+ if(ms == null || !Util.equals(v.nth(i), ms.first()))
+ return false;
+ }
+ if(ms != null)
+ return false;
+ }
+
+ return true;
+
+}
+
+static boolean doEquiv(IPersistentVector v, Object obj){
+ if(obj instanceof List || obj instanceof IPersistentVector)
+ {
+ Collection ma = (Collection) obj;
+ if(ma.size() != v.count())
+ return false;
+ for(Iterator i1 = ((List) v).iterator(), i2 = ma.iterator();
+ i1.hasNext();)
+ {
+ if(!Util.equiv(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))
+ return false;
+ ISeq ms = ((IPersistentCollection) obj).seq();
+ for(int i = 0; i < v.count(); i++, ms = ms.rest())
+ {
+ if(ms == null || !Util.equiv(v.nth(i), ms.first()))
return false;
}
if(ms != null)
@@ -90,6 +133,10 @@ public boolean equals(Object obj){
return doEquals(this, obj);
}
+public boolean equiv(Object obj){
+ return doEquiv(this, obj);
+}
+
public int hashCode(){
if(_hash == -1)
{
@@ -120,14 +167,14 @@ public Object remove(int i){
public int indexOf(Object o){
for(int i = 0; i < count(); i++)
- if(Util.equal(nth(i), o))
+ if(Util.equiv(nth(i), o))
return i;
return -1;
}
public int lastIndexOf(Object o){
for(int i = count() - 1; i >= 0; i--)
- if(Util.equal(nth(i), o))
+ if(Util.equiv(nth(i), o))
return i;
return -1;
}
@@ -333,7 +380,7 @@ public boolean isEmpty(){
public boolean contains(Object o){
for(ISeq s = seq(); s != null; s = s.rest())
{
- if(Util.equal(s.first(), o))
+ if(Util.equiv(s.first(), o))
return true;
}
return false;
diff --git a/src/jvm/clojure/lang/ASeq.java b/src/jvm/clojure/lang/ASeq.java
index 9e298301..8bd830d1 100644
--- a/src/jvm/clojure/lang/ASeq.java
+++ b/src/jvm/clojure/lang/ASeq.java
@@ -10,11 +10,9 @@
package clojure.lang;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.*;
-public abstract class ASeq extends Obj implements ISeq, Collection, Streamable{
+public abstract class ASeq extends Obj implements ISeq, List, Streamable{
transient int _hash = -1;
public String toString(){
@@ -33,20 +31,32 @@ protected ASeq(IPersistentMap meta){
protected ASeq(){
}
-public boolean equals(Object obj){
+public boolean equiv(Object obj){
- if(!(obj instanceof Sequential))
+ if(!(obj instanceof Sequential || obj instanceof List))
return false;
- ISeq ms = ((IPersistentCollection) obj).seq();
+ ISeq ms = RT.seq(obj);
for(ISeq s = seq(); s != null; s = s.rest(), ms = ms.rest())
{
- if(ms == null || !Util.equal(s.first(), ms.first()))
+ if(ms == null || !Util.equiv(s.first(), ms.first()))
return false;
}
- if(ms != null)
+ return ms == null;
+
+}
+
+public boolean equals(Object obj){
+
+ if(!(obj instanceof Sequential || obj instanceof List))
return false;
+ ISeq ms = RT.seq(obj);
+ for(ISeq s = seq(); s != null; s = s.rest(), ms = ms.rest())
+ {
+ if(ms == null || !Util.equals(s.first(), ms.first()))
+ return false;
+ }
+ return ms == null;
- return true;
}
public int hashCode(){
@@ -166,7 +176,7 @@ public boolean isEmpty(){
public boolean contains(Object o){
for(ISeq s = seq(); s != null; s = s.rest())
{
- if(Util.equal(s.first(), o))
+ if(Util.equiv(s.first(), o))
return true;
}
return false;
@@ -177,6 +187,8 @@ public Iterator iterator(){
return new SeqIterator(this);
}
+
+
public IStream stream() throws Exception {
return new Stream(this);
}
@@ -198,4 +210,57 @@ public IStream stream() throws Exception {
return RT.eos();
}
}
+
+
+//////////// List stuff /////////////////
+private List reify(){
+ return new ArrayList(this);
+}
+
+public List subList(int fromIndex, int toIndex){
+ return reify().subList(fromIndex, toIndex);
+}
+
+public Object set(int index, Object element){
+ throw new UnsupportedOperationException();
+}
+
+public Object remove(int index){
+ throw new UnsupportedOperationException();
+}
+
+public int indexOf(Object o){
+ ISeq s = seq();
+ for(int i = 0; s != null; s = s.rest(), i++)
+ {
+ if(Util.equiv(s.first(), o))
+ return i;
+ }
+ return -1;
+}
+
+public int lastIndexOf(Object o){
+ return reify().lastIndexOf(o);
+}
+
+public ListIterator listIterator(){
+ return reify().listIterator();
+}
+
+public ListIterator listIterator(int index){
+ return reify().listIterator(index);
+}
+
+public Object get(int index){
+ return RT.nth(this, index);
+}
+
+public void add(int index, Object element){
+ throw new UnsupportedOperationException();
+}
+
+public boolean addAll(int index, Collection c){
+ throw new UnsupportedOperationException();
+}
+
}
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index 5fc6f6fc..cee50024 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -1808,7 +1808,7 @@ public static class TryExpr implements Expr{
{
Object f = fs.first();
Object op = (f instanceof ISeq) ? ((ISeq) f).first() : null;
- if(!Util.equal(op, CATCH) && !Util.equal(op, FINALLY))
+ if(!Util.equals(op, CATCH) && !Util.equals(op, FINALLY))
{
if(caught)
throw new Exception("Only catch or finally clause can follow catch in try expression");
@@ -1816,7 +1816,7 @@ public static class TryExpr implements Expr{
}
else
{
- if(Util.equal(op, CATCH))
+ if(Util.equals(op, CATCH))
{
Class c = HostExpr.maybeClass(RT.second(f), false);
if(c == null)
@@ -3627,7 +3627,7 @@ public static class BodyExpr implements Expr{
static class Parser implements IParser{
public Expr parse(C context, Object frms) throws Exception{
ISeq forms = (ISeq) frms;
- if(Util.equal(RT.first(forms), DO))
+ if(Util.equals(RT.first(forms), DO))
forms = RT.rest(forms);
PersistentVector exprs = PersistentVector.EMPTY;
for(; forms != null; forms = forms.rest())
diff --git a/src/jvm/clojure/lang/IPersistentCollection.java b/src/jvm/clojure/lang/IPersistentCollection.java
index 21e436f2..a79534ae 100644
--- a/src/jvm/clojure/lang/IPersistentCollection.java
+++ b/src/jvm/clojure/lang/IPersistentCollection.java
@@ -20,4 +20,6 @@ ISeq seq();
IPersistentCollection cons(Object o);
IPersistentCollection empty();
+
+boolean equiv(Object o);
}
diff --git a/src/jvm/clojure/lang/PersistentHashMap.java b/src/jvm/clojure/lang/PersistentHashMap.java
index 014dcefb..d696cd5a 100644
--- a/src/jvm/clojure/lang/PersistentHashMap.java
+++ b/src/jvm/clojure/lang/PersistentHashMap.java
@@ -536,7 +536,7 @@ final static class LeafNode extends AMapEntry implements INode{
public INode assoc(int shift, int hash, Object key, Object val, Box addedLeaf){
if(hash == this.hash)
{
- if(Util.equal(key, this.key))
+ if(Util.equals(key, this.key))
{
if(val == this.val)
return this;
@@ -552,13 +552,13 @@ final static class LeafNode extends AMapEntry implements INode{
}
public INode without(int hash, Object key){
- if(hash == this.hash && Util.equal(key, this.key))
+ if(hash == this.hash && Util.equals(key, this.key))
return null;
return this;
}
public LeafNode find(int hash, Object key){
- if(hash == this.hash && Util.equal(key, this.key))
+ if(hash == this.hash && Util.equals(key, this.key))
return this;
return null;
}
diff --git a/src/jvm/clojure/lang/PersistentList.java b/src/jvm/clojure/lang/PersistentList.java
index 13a77f7e..b3949007 100644
--- a/src/jvm/clojure/lang/PersistentList.java
+++ b/src/jvm/clojure/lang/PersistentList.java
@@ -12,7 +12,7 @@ package clojure.lang;
import java.util.*;
-public class PersistentList extends ASeq implements IPersistentList, IReduce{
+public class PersistentList extends ASeq implements IPersistentList, IReduce, List{
private final Object _first;
private final IPersistentList _rest;
@@ -112,18 +112,22 @@ public Object reduce(IFn f, Object start) throws Exception{
return ret;
}
-static class EmptyList extends Obj implements IPersistentList, Collection{
- @Override
+
+static class EmptyList extends Obj implements IPersistentList, List{
+
public int hashCode(){
return 1;
}
- @Override
public boolean equals(Object o) {
- return o instanceof Sequential && RT.count(o) == 0;
+ return (o instanceof Sequential || o instanceof List) && RT.count(o) == 0;
}
+ public boolean equiv(Object o){
+ return equals(o);
+ }
+
EmptyList(IPersistentMap meta){
super(meta);
}
@@ -225,6 +229,59 @@ static class EmptyList extends Obj implements IPersistentList, Collection{
objects[0] = null;
return objects;
}
+
+ //////////// List stuff /////////////////
+ private List reify(){
+ return new ArrayList(this);
+ }
+
+ public List subList(int fromIndex, int toIndex){
+ return reify().subList(fromIndex, toIndex);
+ }
+
+ public Object set(int index, Object element){
+ throw new UnsupportedOperationException();
+ }
+
+ public Object remove(int index){
+ throw new UnsupportedOperationException();
+ }
+
+ public int indexOf(Object o){
+ ISeq s = seq();
+ for(int i = 0; s != null; s = s.rest(), i++)
+ {
+ if(Util.equiv(s.first(), o))
+ return i;
+ }
+ return -1;
+ }
+
+ public int lastIndexOf(Object o){
+ return reify().lastIndexOf(o);
+ }
+
+ public ListIterator listIterator(){
+ return reify().listIterator();
+ }
+
+ public ListIterator listIterator(int index){
+ return reify().listIterator(index);
+ }
+
+ public Object get(int index){
+ return RT.nth(this, index);
+ }
+
+ public void add(int index, Object element){
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean addAll(int index, Collection c){
+ throw new UnsupportedOperationException();
+ }
+
+
}
}
diff --git a/src/jvm/clojure/lang/PersistentQueue.java b/src/jvm/clojure/lang/PersistentQueue.java
index 8fbeb281..0d2ec9a9 100644
--- a/src/jvm/clojure/lang/PersistentQueue.java
+++ b/src/jvm/clojure/lang/PersistentQueue.java
@@ -37,6 +37,20 @@ PersistentQueue(IPersistentMap meta, ISeq f, PersistentVector r){
this.r = r;
}
+public boolean equiv(Object obj){
+
+ if(!(obj instanceof Sequential))
+ return false;
+ ISeq ms = ((IPersistentCollection) obj).seq();
+ for(ISeq s = seq(); s != null; s = s.rest(), ms = ms.rest())
+ {
+ if(ms == null || !Util.equiv(s.first(), ms.first()))
+ return false;
+ }
+ return ms.rest() == null;
+
+}
+
public boolean equals(Object obj){
if(!(obj instanceof Sequential))
@@ -44,7 +58,7 @@ public boolean equals(Object obj){
ISeq ms = ((IPersistentCollection) obj).seq();
for(ISeq s = seq(); s != null; s = s.rest(), ms = ms.rest())
{
- if(ms == null || !Util.equal(s.first(), ms.first()))
+ if(ms == null || !Util.equals(s.first(), ms.first()))
return false;
}
return ms.rest() == null;
@@ -214,7 +228,7 @@ public boolean isEmpty(){
public boolean contains(Object o){
for(ISeq s = seq(); s != null; s = s.rest())
{
- if(Util.equal(s.first(), o))
+ if(Util.equiv(s.first(), o))
return true;
}
return false;
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java
index 4954028c..f5d97e83 100644
--- a/src/jvm/clojure/lang/RT.java
+++ b/src/jvm/clojure/lang/RT.java
@@ -705,7 +705,7 @@ static public Object nth(Object coll, int n){
return Character.valueOf(((String) coll).charAt(n));
else if(coll.getClass().isArray())
return Reflector.prepRet(Array.get(coll, n));
- else if(coll instanceof List)
+ else if(coll instanceof RandomAccess)
return ((List) coll).get(n);
else if(coll instanceof Matcher)
return ((Matcher) coll).group(n);
@@ -815,7 +815,7 @@ static public Object assocN(int n, Object val, Object coll){
}
static boolean hasTag(Object o, Object tag){
- return Util.equal(tag, RT.get(RT.meta(o), TAG_KEY));
+ return Util.equals(tag, RT.get(RT.meta(o), TAG_KEY));
}
/**
@@ -1410,7 +1410,7 @@ static public Object format(Object o, String s, Object... args) throws Exception
Writer w;
if(o == null)
w = new StringWriter();
- else if(Util.equal(o, T))
+ else if(Util.equals(o, T))
w = (Writer) OUT.get();
else
w = (Writer) o;
diff --git a/src/jvm/clojure/lang/Util.java b/src/jvm/clojure/lang/Util.java
index b671e005..0fd54475 100644
--- a/src/jvm/clojure/lang/Util.java
+++ b/src/jvm/clojure/lang/Util.java
@@ -15,18 +15,26 @@ package clojure.lang;
import java.math.BigInteger;
public class Util{
-static public boolean equal(Object k1, Object k2){
+static public boolean equiv(Object k1, Object k2){
if(k1 == k2)
return true;
if(k1 != null)
{
if(k1 instanceof Number)
return Numbers.equiv(k1, k2);
+ else if(k1 instanceof IPersistentCollection && k2 instanceof IPersistentCollection)
+ return ((IPersistentCollection)k1).equiv(k2);
return k1.equals(k2);
}
return false;
}
+static public boolean equals(Object k1, Object k2){
+ if(k1 == k2)
+ return true;
+ return k1 != null && k1.equals(k2);
+}
+
static public int compare(Object k1, Object k2){
if(k1 == k2)
return 0;