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 the
4 * 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 by
7 * 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 else
64 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 by
108 * all methods that return a new PersistentStructMap. This is done so as to
109 * allow subclasses to return instances of their class from all
110 * 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 }