summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2008-03-04 02:43:23 +0000
committerRich Hickey <richhickey@gmail.com>2008-03-04 02:43:23 +0000
commit1a399df8f3f3bcb9d3a92a584fa9714832ab550f (patch)
tree7b80af17ec585c87937899f7b4a90f5d9ca37544
parent50eed41cee8a274ac37a5052ae1f3cd232750176 (diff)
sets - read/print/compile/metadata, hash-set, sorted-set, disj
-rw-r--r--src/boot.clj29
-rw-r--r--src/jvm/clojure/lang/Compiler.java55
-rw-r--r--src/jvm/clojure/lang/LispReader.java14
-rw-r--r--src/jvm/clojure/lang/PersistentHashSet.java7
-rw-r--r--src/jvm/clojure/lang/PersistentTreeSet.java72
-rw-r--r--src/jvm/clojure/lang/RT.java17
6 files changed, 191 insertions, 3 deletions
diff --git a/src/boot.clj b/src/boot.clj
index ee337356..fe444297 100644
--- a/src/boot.clj
+++ b/src/boot.clj
@@ -164,6 +164,13 @@ hash-map
(. clojure.lang.PersistentHashMap (create keyvals))))
(defn
+ #^{:doc "Returns a new hash set with supplied keys."}
+hash-set
+ ([] {})
+ ([& keys]
+ (. clojure.lang.PersistentHashSet (create keys))))
+
+(defn
#^{:doc "keyval => key val
Returns a new sorted map with supplied mappings."}
sorted-map
@@ -171,6 +178,13 @@ sorted-map
(. clojure.lang.PersistentTreeMap (create keyvals))))
(defn
+ #^{:doc "Returns a new sorted set with supplied keys."}
+sorted-set
+ ([] {})
+ ([& keys]
+ (. clojure.lang.PersistentTreeSet (create keys))))
+
+(defn
#^{:doc "keyval => key val
Returns a new sorted map with supplied mappings, using the
supplied comparator."}
@@ -223,8 +237,6 @@ true? [x] (identical? x true))
not [x] (if x false true))
-
-
(defn
#^{:tag Boolean
:doc "Equality. Returns true if obj1 equals obj2, false if
@@ -675,6 +687,19 @@ dissoc
ret))))
(defn
+ #^{:doc "disj[oin]. Returns a new set of the same
+ (hashed/sorted) type, that does not contain key(s)."}
+disj
+ ([set] set)
+ ([#^clojure.lang.IPersistentSet set key]
+ (. set (disjoin key)))
+ ([set key & ks]
+ (let [ret (disj set key)]
+ (if ks
+ (recur ret (first ks) (rest ks))
+ ret))))
+
+(defn
#^{:doc "Returns the map entry for key, or nil if key not present."}
find [map key]
(. clojure.lang.RT (find map key)))
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index 03114f65..c7ebc814 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -2059,6 +2059,7 @@ static String munge(String name){
static class EmptyExpr implements Expr{
final Object coll;
final static Type HASHMAP_TYPE = Type.getType(PersistentHashMap.class);
+ final static Type HASHSET_TYPE = Type.getType(PersistentHashSet.class);
final static Type VECTOR_TYPE = Type.getType(PersistentVector.class);
final static Type LIST_TYPE = Type.getType(PersistentList.class);
@@ -2080,6 +2081,8 @@ static class EmptyExpr implements Expr{
gen.getStatic(VECTOR_TYPE, "EMPTY", VECTOR_TYPE);
else if(coll instanceof IPersistentMap)
gen.getStatic(HASHMAP_TYPE, "EMPTY", HASHMAP_TYPE);
+ else if(coll instanceof IPersistentSet)
+ gen.getStatic(HASHSET_TYPE, "EMPTY", HASHSET_TYPE);
else
throw new UnsupportedOperationException("Unknown Collection type");
}
@@ -2096,6 +2099,8 @@ static class EmptyExpr implements Expr{
return IPersistentVector.class;
else if(coll instanceof IPersistentMap)
return IPersistentMap.class;
+ else if(coll instanceof IPersistentSet)
+ return IPersistentSet.class;
else
throw new UnsupportedOperationException("Unknown Collection type");
}
@@ -2183,6 +2188,54 @@ static class MapExpr implements Expr{
}
}
+static class SetExpr implements Expr{
+ final IPersistentVector keys;
+ final static Method setMethod = Method.getMethod("clojure.lang.IPersistentSet set(Object[])");
+
+
+ public SetExpr(IPersistentVector keys){
+ this.keys = keys;
+ }
+
+ public Object eval() throws Exception{
+ Object[] ret = new Object[keys.count()];
+ for(int i = 0; i < keys.count(); i++)
+ ret[i] = ((Expr) keys.nth(i)).eval();
+ return RT.set(ret);
+ }
+
+ public void emit(C context, FnExpr fn, GeneratorAdapter gen){
+ MethodExpr.emitArgsAsArray(keys, fn, gen);
+ gen.invokeStatic(RT_TYPE, setMethod);
+ if(context == C.STATEMENT)
+ gen.pop();
+ }
+
+ public boolean hasJavaClass() throws Exception{
+ return true;
+ }
+
+ public Class getJavaClass() throws Exception{
+ return IPersistentSet.class;
+ }
+
+
+ static public Expr parse(C context, IPersistentSet form) throws Exception{
+ IPersistentVector keys = PersistentVector.EMPTY;
+ for(ISeq s = RT.seq(form); s != null; s = s.rest())
+ {
+ Object e = s.first();
+ keys = (IPersistentVector) keys.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, e));
+ }
+ Expr ret = new SetExpr(keys);
+ if(form instanceof IObj && ((IObj) form).meta() != null)
+ return new MetaExpr(ret, (MapExpr) MapExpr
+ .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta()));
+ else
+ return ret;
+ }
+}
+
static class VectorExpr implements Expr{
final IPersistentVector args;
final static Method vectorMethod = Method.getMethod("clojure.lang.IPersistentVector vector(Object[])");
@@ -3131,6 +3184,8 @@ private static Expr analyze(C context, Object form, String name) throws Exceptio
return VectorExpr.parse(context, (IPersistentVector) form);
else if(form instanceof IPersistentMap)
return MapExpr.parse(context, (IPersistentMap) form);
+ else if(form instanceof IPersistentSet)
+ return SetExpr.parse(context, (IPersistentSet) form);
// else
//throw new UnsupportedOperationException();
diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java
index cba2e149..2a4b647b 100644
--- a/src/jvm/clojure/lang/LispReader.java
+++ b/src/jvm/clojure/lang/LispReader.java
@@ -29,6 +29,7 @@ static Symbol CONCAT = Symbol.create("clojure", "concat");
static Symbol LIST = Symbol.create("clojure", "list");
static Symbol APPLY = Symbol.create("clojure", "apply");
static Symbol HASHMAP = Symbol.create("clojure", "hash-map");
+static Symbol HASHSET = Symbol.create("clojure", "hash-set");
static Symbol VECTOR = Symbol.create("clojure", "vector");
static Symbol WITH_META = Symbol.create("clojure", "with-meta");
static Symbol META = Symbol.create("clojure", "meta");
@@ -78,6 +79,7 @@ static
dispatchMacros['\''] = new WrappingReader(Compiler.THE_VAR);
dispatchMacros['"'] = new RegexReader();
dispatchMacros['('] = new FnReader();
+ dispatchMacros['{'] = new SetReader();
}
static boolean isWhitespace(int ch){
@@ -538,6 +540,10 @@ static class SyntaxQuoteReader extends AFn{
{
ret = RT.list(APPLY, VECTOR, RT.cons(CONCAT, sqExpandList(((IPersistentVector) form).seq())));
}
+ else if(form instanceof IPersistentSet)
+ {
+ ret = RT.list(APPLY, HASHSET, RT.cons(CONCAT, sqExpandList(((IPersistentSet) form).seq())));
+ }
else if(form instanceof ISeq)
{
ISeq seq = RT.seq(form);
@@ -688,6 +694,14 @@ static class MapReader extends AFn{
}
+static class SetReader extends AFn{
+ public Object invoke(Object reader, Object leftbracket) throws Exception{
+ PushbackReader r = (PushbackReader) reader;
+ return PersistentHashSet.create(readDelimitedList('}', r, true));
+ }
+
+}
+
static class UnmatchedDelimiterReader extends AFn{
public Object invoke(Object reader, Object rightdelim) throws Exception{
throw new Exception("Unmatched delimiter: " + rightdelim);
diff --git a/src/jvm/clojure/lang/PersistentHashSet.java b/src/jvm/clojure/lang/PersistentHashSet.java
index c28ff2cb..60794b97 100644
--- a/src/jvm/clojure/lang/PersistentHashSet.java
+++ b/src/jvm/clojure/lang/PersistentHashSet.java
@@ -57,9 +57,14 @@ public IPersistentSet disjoin(Object key) throws Exception{
return this;
}
-public IPersistentCollection cons(Object o){
+public IPersistentSet cons(Object o){
if(contains(o))
return this;
return new PersistentHashSet(meta(),impl.assoc(o,o));
}
+
+public PersistentHashSet withMeta(IPersistentMap meta){
+ return new PersistentHashSet(meta, impl);
+}
+
}
diff --git a/src/jvm/clojure/lang/PersistentTreeSet.java b/src/jvm/clojure/lang/PersistentTreeSet.java
new file mode 100644
index 00000000..ae96940d
--- /dev/null
+++ b/src/jvm/clojure/lang/PersistentTreeSet.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) Rich Hickey. All rights reserved.
+ * The use and distribution terms for this software are covered by the
+ * Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
+ * which can be found in the file CPL.TXT at the root of this distribution.
+ * By using this software in any fashion, you are agreeing to be bound by
+ * the terms of this license.
+ * You must not remove this notice, or any other, from this software.
+ **/
+
+/* rich Mar 3, 2008 */
+
+package clojure.lang;
+
+import java.util.List;
+import java.util.Iterator;
+
+public class PersistentTreeSet extends APersistentSet implements Reversible{
+static public final PersistentTreeSet EMPTY = new PersistentTreeSet(null, PersistentTreeMap.EMPTY);
+
+public static PersistentTreeSet create(Object... init){
+ PersistentTreeSet ret = EMPTY;
+ for(int i = 0; i < init.length; i++)
+ {
+ ret = (PersistentTreeSet) ret.cons(init[i]);
+ }
+ return ret;
+}
+
+public static PersistentTreeSet create(List init){
+ PersistentTreeSet ret = EMPTY;
+ for(Iterator i = init.iterator(); i.hasNext();)
+ {
+ Object key = i.next();
+ ret = (PersistentTreeSet) ret.cons(key);
+ }
+ return ret;
+}
+
+static public PersistentTreeSet create(ISeq items){
+ PersistentTreeSet ret = EMPTY;
+ for(; items != null; items = items.rest())
+ {
+ ret = (PersistentTreeSet) ret.cons(items.first());
+ }
+ return ret;
+}
+
+PersistentTreeSet(IPersistentMap meta, IPersistentMap impl){
+ super(meta, impl);
+}
+
+public IPersistentSet disjoin(Object key) throws Exception{
+ if(contains(key))
+ return new PersistentTreeSet(meta(),impl.without(key));
+ return this;
+}
+
+public IPersistentSet cons(Object o){
+ if(contains(o))
+ return this;
+ return new PersistentTreeSet(meta(),impl.assoc(o,o));
+}
+
+public ISeq rseq() throws Exception{
+ return APersistentMap.KeySeq.create(((Reversible) impl).rseq());
+}
+
+public PersistentTreeSet withMeta(IPersistentMap meta){
+ return new PersistentTreeSet(meta, impl);
+}
+}
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java
index c61d8b8a..47acdc77 100644
--- a/src/jvm/clojure/lang/RT.java
+++ b/src/jvm/clojure/lang/RT.java
@@ -471,6 +471,8 @@ static public Object contains(Object coll, Object key){
return F;
else if(coll instanceof Associative)
return ((Associative) coll).containsKey(key) ? T : F;
+ else if(coll instanceof IPersistentSet)
+ return ((IPersistentSet) coll).contains(key) ? T : F;
else if(coll instanceof Map)
{
Map m = (Map) coll;
@@ -670,6 +672,10 @@ static public IPersistentMap map(Object... init){
return PersistentHashMap.create(init);
}
+static public IPersistentSet set(Object... init){
+ return PersistentHashSet.create(init);
+}
+
static public IPersistentVector vector(Object... init){
return PersistentVector.create(init);
}
@@ -922,6 +928,17 @@ static public void print(Object x, Writer w) throws Exception{
}
w.write(']');
}
+ else if(x instanceof IPersistentSet)
+ {
+ w.write("#{");
+ for(ISeq s = seq(x); s != null; s = s.rest())
+ {
+ print(s.first(), w);
+ if(s.rest() != null)
+ w.write(" ");
+ }
+ w.write('}');
+ }
// else if(x instanceof Map.Entry)
// {
// Map.Entry e = (Map.Entry) x;