summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2007-12-16 22:22:09 +0000
committerRich Hickey <richhickey@gmail.com>2007-12-16 22:22:09 +0000
commitc0d142ca0b05be6249872c05fe1bff2fd948bd81 (patch)
tree3d87aae5b29f7a7e016d0fbbc2f19232f0b4095b
parentce156fe5fe5eda63529588102015bc832bf92be3 (diff)
first cut PersistentStructMap
-rw-r--r--src/jvm/clojure/lang/IPersistentMap.java2
-rw-r--r--src/jvm/clojure/lang/MultiFn.java2
-rw-r--r--src/jvm/clojure/lang/PersistentStructMap.java184
-rw-r--r--src/jvm/clojure/lang/RT.java2
4 files changed, 187 insertions, 3 deletions
diff --git a/src/jvm/clojure/lang/IPersistentMap.java b/src/jvm/clojure/lang/IPersistentMap.java
index 555ca1a0..2f352240 100644
--- a/src/jvm/clojure/lang/IPersistentMap.java
+++ b/src/jvm/clojure/lang/IPersistentMap.java
@@ -18,6 +18,6 @@ IPersistentMap assoc(Object key, Object val);
IPersistentMap assocEx(Object key, Object val) throws Exception;
-IPersistentMap without(Object key);
+IPersistentMap without(Object key) throws Exception;
}
diff --git a/src/jvm/clojure/lang/MultiFn.java b/src/jvm/clojure/lang/MultiFn.java
index 53c0b8d5..a322d65b 100644
--- a/src/jvm/clojure/lang/MultiFn.java
+++ b/src/jvm/clojure/lang/MultiFn.java
@@ -28,7 +28,7 @@ public MultiFn assoc(Object dispatchVal, IFn method){
}
-public MultiFn dissoc(Object dispatchVal){
+public MultiFn dissoc(Object dispatchVal) throws Exception{
return new MultiFn(meta(), dispatchFn, defaultDispatchVal, methodTable.without(dispatchVal));
}
diff --git a/src/jvm/clojure/lang/PersistentStructMap.java b/src/jvm/clojure/lang/PersistentStructMap.java
new file mode 100644
index 00000000..2206e6b4
--- /dev/null
+++ b/src/jvm/clojure/lang/PersistentStructMap.java
@@ -0,0 +1,184 @@
+/**
+ * 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 Dec 16, 2007 */
+
+package clojure.lang;
+
+import java.util.Iterator;
+import java.util.Map;
+
+public class PersistentStructMap extends APersistentMap{
+
+final IPersistentMap keyslots;
+final Object[] vals;
+final IPersistentMap ext;
+
+static public IPersistentMap createSlotMap(ISeq keys){
+ if(keys == null)
+ throw new IllegalArgumentException("Must supply keys");
+ PersistentHashMap temp = PersistentHashMap.EMPTY;
+ for(ISeq s = keys; s != null; s = s.rest())
+ {
+ temp = (PersistentHashMap) temp.assoc(s.first(), null);
+ }
+ int i = 0;
+ PersistentHashMap ret = PersistentHashMap.EMPTY;
+ for(ISeq s = RT.keys(temp); s != null; s = s.rest(), i++)
+ ret = (PersistentHashMap) ret.assoc(s.first(), i);
+ return ret;
+}
+
+static public PersistentStructMap create(IPersistentMap keyslots, ISeq init){
+ Object[] vals = new Object[keyslots.count()];
+ IPersistentMap ext = PersistentHashMap.EMPTY;
+ for(; init != null; init = init.rest().rest())
+ {
+ if(init.rest() == null)
+ throw new IllegalArgumentException(String.format("No value supplied for key: %s", init.first()));
+ Object k = init.first();
+ Object v = RT.second(init);
+ Map.Entry e = keyslots.entryAt(k);
+ if(e != null)
+ vals[(Integer) e.getValue()] = v;
+ else
+ ext = ext.assoc(k, v);
+ }
+ return new PersistentStructMap(null, keyslots, vals, ext);
+}
+
+static public IFn getAccessor(final IPersistentMap keyslots, Object key){
+ Map.Entry e = keyslots.entryAt(key);
+ if(e != null)
+ {
+ final int i = (Integer) e.getValue();
+ return new AFn(){
+ public Object invoke(Object arg1) throws Exception{
+ PersistentStructMap m = (PersistentStructMap) arg1;
+ if(m.keyslots != keyslots)
+ throw new Exception("Accessor/struct mismatch");
+ return m.vals[i];
+ }
+ };
+ }
+ throw new IllegalArgumentException("Not a key of struct");
+}
+
+PersistentStructMap(IPersistentMap meta, IPersistentMap keys, Object[] vals, IPersistentMap ext){
+ super(meta);
+ this.ext = ext;
+ this.keyslots = keys;
+ this.vals = vals;
+}
+
+public boolean containsKey(Object key){
+ return keyslots.containsKey(key) || ext.containsKey(key);
+}
+
+public IMapEntry entryAt(Object key){
+ Map.Entry e = keyslots.entryAt(key);
+ if(e != null)
+ {
+ return new MapEntry(key, vals[(Integer) e.getValue()]);
+ }
+ return ext.entryAt(key);
+}
+
+public IPersistentMap assoc(Object key, Object val){
+ Map.Entry e = keyslots.entryAt(key);
+ if(e != null)
+ {
+ int i = (Integer) e.getValue();
+ Object[] newVals = vals.clone();
+ newVals[i] = val;
+ return new PersistentStructMap(_meta, keyslots, newVals, ext);
+ }
+ return new PersistentStructMap(_meta, keyslots, vals, ext.assoc(key, val));
+}
+
+public Object valAt(Object key){
+ Map.Entry e = keyslots.entryAt(key);
+ if(e != null)
+ {
+ return vals[(Integer) e.getValue()];
+ }
+ return ext.valAt(key);
+}
+
+public Object valAt(Object key, Object notFound){
+ Map.Entry e = keyslots.entryAt(key);
+ if(e != null)
+ {
+ return vals[(Integer) e.getValue()];
+ }
+ return ext.valAt(key, notFound);
+}
+
+public IPersistentMap assocEx(Object key, Object val) throws Exception{
+ if(containsKey(key))
+ throw new Exception("Key already present");
+ return assoc(key, val);
+}
+
+public IPersistentMap without(Object key) throws Exception{
+ Map.Entry e = keyslots.entryAt(key);
+ if(e != null)
+ throw new Exception("Can't remove struct key");
+ IPersistentMap newExt = ext.without(key);
+ if(newExt == ext)
+ return this;
+ return new PersistentStructMap(_meta, keyslots, vals, newExt);
+}
+
+public Iterator iterator(){
+ return new SeqIterator(seq());
+}
+
+
+public int count(){
+ return vals.length + RT.count(ext);
+}
+
+public ISeq seq(){
+ return new Seq(null, RT.keys(keyslots), vals, 0, ext);
+}
+
+static class Seq extends ASeq{
+ final int i;
+ final ISeq keys;
+ final Object[] vals;
+ final IPersistentMap ext;
+
+
+ public Seq(IPersistentMap meta, ISeq keys, Object[] vals, int i, IPersistentMap ext){
+ super(meta);
+ this.i = i;
+ this.keys = keys;
+ this.vals = vals;
+ this.ext = ext;
+ }
+
+ public Obj withMeta(IPersistentMap meta){
+ if(meta != _meta)
+ return new Seq(meta, keys, vals, i, ext);
+ return this;
+ }
+
+ public Object first(){
+ return new MapEntry(keys.first(), vals[i]);
+ }
+
+ public ISeq rest(){
+ if(i + 1 < vals.length)
+ return new Seq(_meta, keys.rest(), vals, i + 1, ext);
+ return ext.seq();
+ }
+}
+}
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java
index 1e5fb9a6..e657459d 100644
--- a/src/jvm/clojure/lang/RT.java
+++ b/src/jvm/clojure/lang/RT.java
@@ -359,7 +359,7 @@ static public ISeq findKey(Keyword key, ISeq keyvals) throws Exception{
return null;
}
-static public Object dissoc(Object coll, Object key){
+static public Object dissoc(Object coll, Object key) throws Exception{
if(coll == null)
return null;
return ((IPersistentMap) coll).without(key);