rlm@10
|
1 /**
|
rlm@10
|
2 * Copyright (c) Rich Hickey. All rights reserved.
|
rlm@10
|
3 * The use and distribution terms for this software are covered by the
|
rlm@10
|
4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
rlm@10
|
5 * which can be found in the file epl-v10.html at the root of this distribution.
|
rlm@10
|
6 * By using this software in any fashion, you are agreeing to be bound by
|
rlm@10
|
7 * the terms of this license.
|
rlm@10
|
8 * You must not remove this notice, or any other, from this software.
|
rlm@10
|
9 **/
|
rlm@10
|
10
|
rlm@10
|
11 package clojure.lang;
|
rlm@10
|
12
|
rlm@10
|
13 import java.io.Serializable;
|
rlm@10
|
14 import java.util.*;
|
rlm@10
|
15
|
rlm@10
|
16 public abstract class APersistentMap extends AFn implements IPersistentMap, Map, Iterable, Serializable, MapEquivalence {
|
rlm@10
|
17 int _hash = -1;
|
rlm@10
|
18
|
rlm@10
|
19 public String toString(){
|
rlm@10
|
20 return RT.printString(this);
|
rlm@10
|
21 }
|
rlm@10
|
22
|
rlm@10
|
23 public IPersistentCollection cons(Object o){
|
rlm@10
|
24 if(o instanceof Map.Entry)
|
rlm@10
|
25 {
|
rlm@10
|
26 Map.Entry e = (Map.Entry) o;
|
rlm@10
|
27
|
rlm@10
|
28 return assoc(e.getKey(), e.getValue());
|
rlm@10
|
29 }
|
rlm@10
|
30 else if(o instanceof IPersistentVector)
|
rlm@10
|
31 {
|
rlm@10
|
32 IPersistentVector v = (IPersistentVector) o;
|
rlm@10
|
33 if(v.count() != 2)
|
rlm@10
|
34 throw new IllegalArgumentException("Vector arg to map conj must be a pair");
|
rlm@10
|
35 return assoc(v.nth(0), v.nth(1));
|
rlm@10
|
36 }
|
rlm@10
|
37
|
rlm@10
|
38 IPersistentMap ret = this;
|
rlm@10
|
39 for(ISeq es = RT.seq(o); es != null; es = es.next())
|
rlm@10
|
40 {
|
rlm@10
|
41 Map.Entry e = (Map.Entry) es.first();
|
rlm@10
|
42 ret = ret.assoc(e.getKey(), e.getValue());
|
rlm@10
|
43 }
|
rlm@10
|
44 return ret;
|
rlm@10
|
45 }
|
rlm@10
|
46
|
rlm@10
|
47 public boolean equals(Object obj){
|
rlm@10
|
48 return mapEquals(this, obj);
|
rlm@10
|
49 }
|
rlm@10
|
50
|
rlm@10
|
51 static public boolean mapEquals(IPersistentMap m1, Object obj){
|
rlm@10
|
52 if(m1 == obj) return true;
|
rlm@10
|
53 if(!(obj instanceof Map))
|
rlm@10
|
54 return false;
|
rlm@10
|
55 Map m = (Map) obj;
|
rlm@10
|
56
|
rlm@10
|
57 if(m.size() != m1.count() || m.hashCode() != m1.hashCode())
|
rlm@10
|
58 return false;
|
rlm@10
|
59
|
rlm@10
|
60 for(ISeq s = m1.seq(); s != null; s = s.next())
|
rlm@10
|
61 {
|
rlm@10
|
62 Map.Entry e = (Map.Entry) s.first();
|
rlm@10
|
63 boolean found = m.containsKey(e.getKey());
|
rlm@10
|
64
|
rlm@10
|
65 if(!found || !Util.equals(e.getValue(), m.get(e.getKey())))
|
rlm@10
|
66 return false;
|
rlm@10
|
67 }
|
rlm@10
|
68
|
rlm@10
|
69 return true;
|
rlm@10
|
70 }
|
rlm@10
|
71
|
rlm@10
|
72 public boolean equiv(Object obj){
|
rlm@10
|
73 if(!(obj instanceof Map))
|
rlm@10
|
74 return false;
|
rlm@10
|
75 if(obj instanceof IPersistentMap && !(obj instanceof MapEquivalence))
|
rlm@10
|
76 return false;
|
rlm@10
|
77
|
rlm@10
|
78 Map m = (Map) obj;
|
rlm@10
|
79
|
rlm@10
|
80 if(m.size() != size())
|
rlm@10
|
81 return false;
|
rlm@10
|
82
|
rlm@10
|
83 for(ISeq s = seq(); s != null; s = s.next())
|
rlm@10
|
84 {
|
rlm@10
|
85 Map.Entry e = (Map.Entry) s.first();
|
rlm@10
|
86 boolean found = m.containsKey(e.getKey());
|
rlm@10
|
87
|
rlm@10
|
88 if(!found || !Util.equiv(e.getValue(), m.get(e.getKey())))
|
rlm@10
|
89 return false;
|
rlm@10
|
90 }
|
rlm@10
|
91
|
rlm@10
|
92 return true;
|
rlm@10
|
93 }
|
rlm@10
|
94 public int hashCode(){
|
rlm@10
|
95 if(_hash == -1)
|
rlm@10
|
96 {
|
rlm@10
|
97 this._hash = mapHash(this);
|
rlm@10
|
98 }
|
rlm@10
|
99 return _hash;
|
rlm@10
|
100 }
|
rlm@10
|
101
|
rlm@10
|
102 static public int mapHash(IPersistentMap m){
|
rlm@10
|
103 int hash = 0;
|
rlm@10
|
104 for(ISeq s = m.seq(); s != null; s = s.next())
|
rlm@10
|
105 {
|
rlm@10
|
106 Map.Entry e = (Map.Entry) s.first();
|
rlm@10
|
107 hash += (e.getKey() == null ? 0 : e.getKey().hashCode()) ^
|
rlm@10
|
108 (e.getValue() == null ? 0 : e.getValue().hashCode());
|
rlm@10
|
109 }
|
rlm@10
|
110 return hash;
|
rlm@10
|
111 }
|
rlm@10
|
112
|
rlm@10
|
113 static public class KeySeq extends ASeq{
|
rlm@10
|
114 ISeq seq;
|
rlm@10
|
115
|
rlm@10
|
116 static public KeySeq create(ISeq seq){
|
rlm@10
|
117 if(seq == null)
|
rlm@10
|
118 return null;
|
rlm@10
|
119 return new KeySeq(seq);
|
rlm@10
|
120 }
|
rlm@10
|
121
|
rlm@10
|
122 private KeySeq(ISeq seq){
|
rlm@10
|
123 this.seq = seq;
|
rlm@10
|
124 }
|
rlm@10
|
125
|
rlm@10
|
126 private KeySeq(IPersistentMap meta, ISeq seq){
|
rlm@10
|
127 super(meta);
|
rlm@10
|
128 this.seq = seq;
|
rlm@10
|
129 }
|
rlm@10
|
130
|
rlm@10
|
131 public Object first(){
|
rlm@10
|
132 return ((Map.Entry) seq.first()).getKey();
|
rlm@10
|
133 }
|
rlm@10
|
134
|
rlm@10
|
135 public ISeq next(){
|
rlm@10
|
136 return create(seq.next());
|
rlm@10
|
137 }
|
rlm@10
|
138
|
rlm@10
|
139 public KeySeq withMeta(IPersistentMap meta){
|
rlm@10
|
140 return new KeySeq(meta, seq);
|
rlm@10
|
141 }
|
rlm@10
|
142 }
|
rlm@10
|
143
|
rlm@10
|
144 static public class ValSeq extends ASeq{
|
rlm@10
|
145 ISeq seq;
|
rlm@10
|
146
|
rlm@10
|
147 static public ValSeq create(ISeq seq){
|
rlm@10
|
148 if(seq == null)
|
rlm@10
|
149 return null;
|
rlm@10
|
150 return new ValSeq(seq);
|
rlm@10
|
151 }
|
rlm@10
|
152
|
rlm@10
|
153 private ValSeq(ISeq seq){
|
rlm@10
|
154 this.seq = seq;
|
rlm@10
|
155 }
|
rlm@10
|
156
|
rlm@10
|
157 private ValSeq(IPersistentMap meta, ISeq seq){
|
rlm@10
|
158 super(meta);
|
rlm@10
|
159 this.seq = seq;
|
rlm@10
|
160 }
|
rlm@10
|
161
|
rlm@10
|
162 public Object first(){
|
rlm@10
|
163 return ((Map.Entry) seq.first()).getValue();
|
rlm@10
|
164 }
|
rlm@10
|
165
|
rlm@10
|
166 public ISeq next(){
|
rlm@10
|
167 return create(seq.next());
|
rlm@10
|
168 }
|
rlm@10
|
169
|
rlm@10
|
170 public ValSeq withMeta(IPersistentMap meta){
|
rlm@10
|
171 return new ValSeq(meta, seq);
|
rlm@10
|
172 }
|
rlm@10
|
173 }
|
rlm@10
|
174
|
rlm@10
|
175
|
rlm@10
|
176 public Object invoke(Object arg1) throws Exception{
|
rlm@10
|
177 return valAt(arg1);
|
rlm@10
|
178 }
|
rlm@10
|
179
|
rlm@10
|
180 public Object invoke(Object arg1, Object notFound) throws Exception{
|
rlm@10
|
181 return valAt(arg1, notFound);
|
rlm@10
|
182 }
|
rlm@10
|
183
|
rlm@10
|
184 // java.util.Map implementation
|
rlm@10
|
185
|
rlm@10
|
186 public void clear(){
|
rlm@10
|
187 throw new UnsupportedOperationException();
|
rlm@10
|
188 }
|
rlm@10
|
189
|
rlm@10
|
190 public boolean containsValue(Object value){
|
rlm@10
|
191 return values().contains(value);
|
rlm@10
|
192 }
|
rlm@10
|
193
|
rlm@10
|
194 public Set entrySet(){
|
rlm@10
|
195 return new AbstractSet(){
|
rlm@10
|
196
|
rlm@10
|
197 public Iterator iterator(){
|
rlm@10
|
198 return APersistentMap.this.iterator();
|
rlm@10
|
199 }
|
rlm@10
|
200
|
rlm@10
|
201 public int size(){
|
rlm@10
|
202 return count();
|
rlm@10
|
203 }
|
rlm@10
|
204
|
rlm@10
|
205 public int hashCode(){
|
rlm@10
|
206 return APersistentMap.this.hashCode();
|
rlm@10
|
207 }
|
rlm@10
|
208
|
rlm@10
|
209 public boolean contains(Object o){
|
rlm@10
|
210 if(o instanceof Entry)
|
rlm@10
|
211 {
|
rlm@10
|
212 Entry e = (Entry) o;
|
rlm@10
|
213 Entry found = entryAt(e.getKey());
|
rlm@10
|
214 if(found != null && Util.equals(found.getValue(), e.getValue()))
|
rlm@10
|
215 return true;
|
rlm@10
|
216 }
|
rlm@10
|
217 return false;
|
rlm@10
|
218 }
|
rlm@10
|
219 };
|
rlm@10
|
220 }
|
rlm@10
|
221
|
rlm@10
|
222 public Object get(Object key){
|
rlm@10
|
223 return valAt(key);
|
rlm@10
|
224 }
|
rlm@10
|
225
|
rlm@10
|
226 public boolean isEmpty(){
|
rlm@10
|
227 return count() == 0;
|
rlm@10
|
228 }
|
rlm@10
|
229
|
rlm@10
|
230 public Set keySet(){
|
rlm@10
|
231 return new AbstractSet(){
|
rlm@10
|
232
|
rlm@10
|
233 public Iterator iterator(){
|
rlm@10
|
234 final Iterator mi = APersistentMap.this.iterator();
|
rlm@10
|
235
|
rlm@10
|
236 return new Iterator(){
|
rlm@10
|
237
|
rlm@10
|
238
|
rlm@10
|
239 public boolean hasNext(){
|
rlm@10
|
240 return mi.hasNext();
|
rlm@10
|
241 }
|
rlm@10
|
242
|
rlm@10
|
243 public Object next(){
|
rlm@10
|
244 Entry e = (Entry) mi.next();
|
rlm@10
|
245 return e.getKey();
|
rlm@10
|
246 }
|
rlm@10
|
247
|
rlm@10
|
248 public void remove(){
|
rlm@10
|
249 throw new UnsupportedOperationException();
|
rlm@10
|
250 }
|
rlm@10
|
251 };
|
rlm@10
|
252 }
|
rlm@10
|
253
|
rlm@10
|
254 public int size(){
|
rlm@10
|
255 return count();
|
rlm@10
|
256 }
|
rlm@10
|
257
|
rlm@10
|
258 public boolean contains(Object o){
|
rlm@10
|
259 return APersistentMap.this.containsKey(o);
|
rlm@10
|
260 }
|
rlm@10
|
261 };
|
rlm@10
|
262 }
|
rlm@10
|
263
|
rlm@10
|
264 public Object put(Object key, Object value){
|
rlm@10
|
265 throw new UnsupportedOperationException();
|
rlm@10
|
266 }
|
rlm@10
|
267
|
rlm@10
|
268 public void putAll(Map t){
|
rlm@10
|
269 throw new UnsupportedOperationException();
|
rlm@10
|
270 }
|
rlm@10
|
271
|
rlm@10
|
272 public Object remove(Object key){
|
rlm@10
|
273 throw new UnsupportedOperationException();
|
rlm@10
|
274 }
|
rlm@10
|
275
|
rlm@10
|
276 public int size(){
|
rlm@10
|
277 return count();
|
rlm@10
|
278 }
|
rlm@10
|
279
|
rlm@10
|
280 public Collection values(){
|
rlm@10
|
281 return new AbstractCollection(){
|
rlm@10
|
282
|
rlm@10
|
283 public Iterator iterator(){
|
rlm@10
|
284 final Iterator mi = APersistentMap.this.iterator();
|
rlm@10
|
285
|
rlm@10
|
286 return new Iterator(){
|
rlm@10
|
287
|
rlm@10
|
288
|
rlm@10
|
289 public boolean hasNext(){
|
rlm@10
|
290 return mi.hasNext();
|
rlm@10
|
291 }
|
rlm@10
|
292
|
rlm@10
|
293 public Object next(){
|
rlm@10
|
294 Entry e = (Entry) mi.next();
|
rlm@10
|
295 return e.getValue();
|
rlm@10
|
296 }
|
rlm@10
|
297
|
rlm@10
|
298 public void remove(){
|
rlm@10
|
299 throw new UnsupportedOperationException();
|
rlm@10
|
300 }
|
rlm@10
|
301 };
|
rlm@10
|
302 }
|
rlm@10
|
303
|
rlm@10
|
304 public int size(){
|
rlm@10
|
305 return count();
|
rlm@10
|
306 }
|
rlm@10
|
307 };
|
rlm@10
|
308 }
|
rlm@10
|
309
|
rlm@10
|
310 /*
|
rlm@10
|
311 // java.util.Collection implementation
|
rlm@10
|
312
|
rlm@10
|
313 public Object[] toArray(){
|
rlm@10
|
314 return RT.seqToArray(seq());
|
rlm@10
|
315 }
|
rlm@10
|
316
|
rlm@10
|
317 public boolean add(Object o){
|
rlm@10
|
318 throw new UnsupportedOperationException();
|
rlm@10
|
319 }
|
rlm@10
|
320
|
rlm@10
|
321 public boolean remove(Object o){
|
rlm@10
|
322 throw new UnsupportedOperationException();
|
rlm@10
|
323 }
|
rlm@10
|
324
|
rlm@10
|
325 public boolean addAll(Collection c){
|
rlm@10
|
326 throw new UnsupportedOperationException();
|
rlm@10
|
327 }
|
rlm@10
|
328
|
rlm@10
|
329 public void clear(){
|
rlm@10
|
330 throw new UnsupportedOperationException();
|
rlm@10
|
331 }
|
rlm@10
|
332
|
rlm@10
|
333 public boolean retainAll(Collection c){
|
rlm@10
|
334 throw new UnsupportedOperationException();
|
rlm@10
|
335 }
|
rlm@10
|
336
|
rlm@10
|
337 public boolean removeAll(Collection c){
|
rlm@10
|
338 throw new UnsupportedOperationException();
|
rlm@10
|
339 }
|
rlm@10
|
340
|
rlm@10
|
341 public boolean containsAll(Collection c){
|
rlm@10
|
342 for(Object o : c)
|
rlm@10
|
343 {
|
rlm@10
|
344 if(!contains(o))
|
rlm@10
|
345 return false;
|
rlm@10
|
346 }
|
rlm@10
|
347 return true;
|
rlm@10
|
348 }
|
rlm@10
|
349
|
rlm@10
|
350 public Object[] toArray(Object[] a){
|
rlm@10
|
351 if(a.length >= count())
|
rlm@10
|
352 {
|
rlm@10
|
353 ISeq s = seq();
|
rlm@10
|
354 for(int i = 0; s != null; ++i, s = s.rest())
|
rlm@10
|
355 {
|
rlm@10
|
356 a[i] = s.first();
|
rlm@10
|
357 }
|
rlm@10
|
358 if(a.length > count())
|
rlm@10
|
359 a[count()] = null;
|
rlm@10
|
360 return a;
|
rlm@10
|
361 }
|
rlm@10
|
362 else
|
rlm@10
|
363 return toArray();
|
rlm@10
|
364 }
|
rlm@10
|
365
|
rlm@10
|
366 public int size(){
|
rlm@10
|
367 return count();
|
rlm@10
|
368 }
|
rlm@10
|
369
|
rlm@10
|
370 public boolean isEmpty(){
|
rlm@10
|
371 return count() == 0;
|
rlm@10
|
372 }
|
rlm@10
|
373
|
rlm@10
|
374 public boolean contains(Object o){
|
rlm@10
|
375 if(o instanceof Map.Entry)
|
rlm@10
|
376 {
|
rlm@10
|
377 Map.Entry e = (Map.Entry) o;
|
rlm@10
|
378 Map.Entry v = entryAt(e.getKey());
|
rlm@10
|
379 return (v != null && Util.equal(v.getValue(), e.getValue()));
|
rlm@10
|
380 }
|
rlm@10
|
381 return false;
|
rlm@10
|
382 }
|
rlm@10
|
383 */
|
rlm@10
|
384 }
|