Mercurial > lasercutter
view src/clojure/lang/PersistentStructMap.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 /**2 * Copyright (c) Rich Hickey. All rights reserved.3 * The use and distribution terms for this software are covered by the4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)5 * which can be found in the file epl-v10.html at the root of this distribution.6 * By using this software in any fashion, you are agreeing to be bound by7 * the terms of this license.8 * You must not remove this notice, or any other, from this software.9 **/11 /* rich Dec 16, 2007 */13 package clojure.lang;15 import java.util.Iterator;16 import java.util.Map;17 import java.io.Serializable;19 public class PersistentStructMap extends APersistentMap implements IObj{21 public static class Def implements Serializable{22 final ISeq keys;23 final IPersistentMap keyslots;25 Def(ISeq keys, IPersistentMap keyslots){26 this.keys = keys;27 this.keyslots = keyslots;28 }29 }31 final Def def;32 final Object[] vals;33 final IPersistentMap ext;34 final IPersistentMap _meta;37 static public Def createSlotMap(ISeq keys){38 if(keys == null)39 throw new IllegalArgumentException("Must supply keys");40 int c = RT.count(keys);41 Object[] v = new Object[2*c];42 int i = 0;43 for(ISeq s = keys; s != null; s = s.next(), i++)44 {45 v[2*i] = s.first();46 v[2*i+1] = i;47 }48 return new Def(keys, RT.map(v));49 }51 static public PersistentStructMap create(Def def, ISeq keyvals){52 Object[] vals = new Object[def.keyslots.count()];53 IPersistentMap ext = PersistentHashMap.EMPTY;54 for(; keyvals != null; keyvals = keyvals.next().next())55 {56 if(keyvals.next() == null)57 throw new IllegalArgumentException(String.format("No value supplied for key: %s", keyvals.first()));58 Object k = keyvals.first();59 Object v = RT.second(keyvals);60 Map.Entry e = def.keyslots.entryAt(k);61 if(e != null)62 vals[(Integer) e.getValue()] = v;63 else64 ext = ext.assoc(k, v);65 }66 return new PersistentStructMap(null, def, vals, ext);67 }69 static public PersistentStructMap construct(Def def, ISeq valseq){70 Object[] vals = new Object[def.keyslots.count()];71 IPersistentMap ext = PersistentHashMap.EMPTY;72 for(int i = 0; i < vals.length && valseq != null; valseq = valseq.next(), i++)73 {74 vals[i] = valseq.first();75 }76 if(valseq != null)77 throw new IllegalArgumentException("Too many arguments to struct constructor");78 return new PersistentStructMap(null, def, vals, ext);79 }81 static public IFn getAccessor(final Def def, Object key){82 Map.Entry e = def.keyslots.entryAt(key);83 if(e != null)84 {85 final int i = (Integer) e.getValue();86 return new AFn(){87 public Object invoke(Object arg1) throws Exception{88 PersistentStructMap m = (PersistentStructMap) arg1;89 if(m.def != def)90 throw new Exception("Accessor/struct mismatch");91 return m.vals[i];92 }93 };94 }95 throw new IllegalArgumentException("Not a key of struct");96 }98 protected PersistentStructMap(IPersistentMap meta, Def def, Object[] vals, IPersistentMap ext){99 this._meta = meta;100 this.ext = ext;101 this.def = def;102 this.vals = vals;103 }105 /**106 * Returns a new instance of PersistentStructMap using the given parameters.107 * This function is used instead of the PersistentStructMap constructor by108 * all methods that return a new PersistentStructMap. This is done so as to109 * allow subclasses to return instances of their class from all110 * PersistentStructMap methods.111 */112 protected PersistentStructMap makeNew(IPersistentMap meta, Def def, Object[] vals, IPersistentMap ext){113 return new PersistentStructMap(meta, def, vals, ext);114 }116 public IObj withMeta(IPersistentMap meta){117 if(meta == _meta)118 return this;119 return makeNew(meta, def, vals, ext);120 }122 public IPersistentMap meta(){123 return _meta;124 }126 public boolean containsKey(Object key){127 return def.keyslots.containsKey(key) || ext.containsKey(key);128 }130 public IMapEntry entryAt(Object key){131 Map.Entry e = def.keyslots.entryAt(key);132 if(e != null)133 {134 return new MapEntry(e.getKey(), vals[(Integer) e.getValue()]);135 }136 return ext.entryAt(key);137 }139 public IPersistentMap assoc(Object key, Object val){140 Map.Entry e = def.keyslots.entryAt(key);141 if(e != null)142 {143 int i = (Integer) e.getValue();144 Object[] newVals = vals.clone();145 newVals[i] = val;146 return makeNew(_meta, def, newVals, ext);147 }148 return makeNew(_meta, def, vals, ext.assoc(key, val));149 }151 public Object valAt(Object key){152 Integer i = (Integer) def.keyslots.valAt(key);153 if(i != null)154 {155 return vals[i];156 }157 return ext.valAt(key);158 }160 public Object valAt(Object key, Object notFound){161 Integer i = (Integer) def.keyslots.valAt(key);162 if(i != null)163 {164 return vals[i];165 }166 return ext.valAt(key, notFound);167 }169 public IPersistentMap assocEx(Object key, Object val) throws Exception{170 if(containsKey(key))171 throw new Exception("Key already present");172 return assoc(key, val);173 }175 public IPersistentMap without(Object key) throws Exception{176 Map.Entry e = def.keyslots.entryAt(key);177 if(e != null)178 throw new Exception("Can't remove struct key");179 IPersistentMap newExt = ext.without(key);180 if(newExt == ext)181 return this;182 return makeNew(_meta, def, vals, newExt);183 }185 public Iterator iterator(){186 return new SeqIterator(seq());187 }190 public int count(){191 return vals.length + RT.count(ext);192 }194 public ISeq seq(){195 return new Seq(null, def.keys, vals, 0, ext);196 }198 public IPersistentCollection empty(){199 return construct(def, null);200 }202 static class Seq extends ASeq{203 final int i;204 final ISeq keys;205 final Object[] vals;206 final IPersistentMap ext;209 public Seq(IPersistentMap meta, ISeq keys, Object[] vals, int i, IPersistentMap ext){210 super(meta);211 this.i = i;212 this.keys = keys;213 this.vals = vals;214 this.ext = ext;215 }217 public Obj withMeta(IPersistentMap meta){218 if(meta != _meta)219 return new Seq(meta, keys, vals, i, ext);220 return this;221 }223 public Object first(){224 return new MapEntry(keys.first(), vals[i]);225 }227 public ISeq next(){228 if(i + 1 < vals.length)229 return new Seq(_meta, keys.next(), vals, i + 1, ext);230 return ext.seq();231 }232 }233 }