Mercurial > lasercutter
comparison src/clojure/lang/TransactionalHashMap.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
9:35cf337adfcf | 10:ef7dbbd6452c |
---|---|
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 **/ | |
10 | |
11 /* rich Jul 31, 2008 */ | |
12 | |
13 package clojure.lang; | |
14 | |
15 import java.util.concurrent.ConcurrentMap; | |
16 import java.util.*; | |
17 | |
18 public class TransactionalHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>{ | |
19 final Ref[] bins; | |
20 | |
21 IPersistentMap mapAt(int bin){ | |
22 return (IPersistentMap) bins[bin].deref(); | |
23 } | |
24 | |
25 final int binFor(Object k){ | |
26 //spread hashes, a la Cliff Click | |
27 int h = k.hashCode(); | |
28 h ^= (h >>> 20) ^ (h >>> 12); | |
29 h ^= (h >>> 7) ^ (h >>> 4); | |
30 return h % bins.length; | |
31 // return k.hashCode() % bins.length; | |
32 } | |
33 | |
34 Entry entryAt(Object k){ | |
35 return mapAt(binFor(k)).entryAt(k); | |
36 } | |
37 | |
38 public TransactionalHashMap() throws Exception{ | |
39 this(421); | |
40 } | |
41 | |
42 public TransactionalHashMap(int nBins) throws Exception{ | |
43 bins = new Ref[nBins]; | |
44 for(int i = 0; i < nBins; i++) | |
45 bins[i] = new Ref(PersistentHashMap.EMPTY); | |
46 } | |
47 | |
48 public TransactionalHashMap(Map<? extends K, ? extends V> m) throws Exception{ | |
49 this(m.size()); | |
50 putAll(m); | |
51 } | |
52 | |
53 public int size(){ | |
54 int n = 0; | |
55 for(int i = 0; i < bins.length; i++) | |
56 { | |
57 n += mapAt(i).count(); | |
58 } | |
59 return n; | |
60 } | |
61 | |
62 public boolean isEmpty(){ | |
63 return size() == 0; | |
64 } | |
65 | |
66 public boolean containsKey(Object k){ | |
67 return entryAt(k) != null; | |
68 } | |
69 | |
70 public V get(Object k){ | |
71 Entry e = entryAt(k); | |
72 if(e != null) | |
73 return (V) e.getValue(); | |
74 return null; | |
75 } | |
76 | |
77 public V put(K k, V v){ | |
78 Ref r = bins[binFor(k)]; | |
79 IPersistentMap map = (IPersistentMap) r.deref(); | |
80 Object ret = map.valAt(k); | |
81 r.set(map.assoc(k, v)); | |
82 return (V) ret; | |
83 } | |
84 | |
85 public V remove(Object k){ | |
86 Ref r = bins[binFor(k)]; | |
87 IPersistentMap map = (IPersistentMap) r.deref(); | |
88 Object ret = map.valAt(k); | |
89 //checked exceptions are a bad idea, especially in an interface | |
90 try | |
91 { | |
92 r.set(map.without(k)); | |
93 } | |
94 catch(Exception e) | |
95 { | |
96 throw new RuntimeException(e); | |
97 } | |
98 return (V) ret; | |
99 } | |
100 | |
101 public void putAll(Map<? extends K, ? extends V> map){ | |
102 for(Iterator i = map.entrySet().iterator(); i.hasNext();) | |
103 { | |
104 Entry<K, V> e = (Entry) i.next(); | |
105 put(e.getKey(), e.getValue()); | |
106 } | |
107 } | |
108 | |
109 public void clear(){ | |
110 for(int i = 0; i < bins.length; i++) | |
111 { | |
112 Ref r = bins[i]; | |
113 IPersistentMap map = (IPersistentMap) r.deref(); | |
114 if(map.count() > 0) | |
115 { | |
116 r.set(PersistentHashMap.EMPTY); | |
117 } | |
118 } | |
119 } | |
120 | |
121 public Set<Entry<K, V>> entrySet(){ | |
122 final ArrayList<Map.Entry<K, V>> entries = new ArrayList(bins.length); | |
123 for(int i = 0; i < bins.length; i++) | |
124 { | |
125 IPersistentMap map = mapAt(i); | |
126 if(map.count() > 0) | |
127 entries.addAll((Collection) RT.seq(map)); | |
128 } | |
129 return new AbstractSet<Entry<K, V>>(){ | |
130 public Iterator iterator(){ | |
131 return Collections.unmodifiableList(entries).iterator(); | |
132 } | |
133 | |
134 public int size(){ | |
135 return entries.size(); | |
136 } | |
137 }; | |
138 } | |
139 | |
140 public V putIfAbsent(K k, V v){ | |
141 Ref r = bins[binFor(k)]; | |
142 IPersistentMap map = (IPersistentMap) r.deref(); | |
143 Entry e = map.entryAt(k); | |
144 if(e == null) | |
145 { | |
146 r.set(map.assoc(k, v)); | |
147 return null; | |
148 } | |
149 else | |
150 return (V) e.getValue(); | |
151 } | |
152 | |
153 public boolean remove(Object k, Object v){ | |
154 Ref r = bins[binFor(k)]; | |
155 IPersistentMap map = (IPersistentMap) r.deref(); | |
156 Entry e = map.entryAt(k); | |
157 if(e != null && e.getValue().equals(v)) | |
158 { | |
159 //checked exceptions are a bad idea, especially in an interface | |
160 try | |
161 { | |
162 r.set(map.without(k)); | |
163 } | |
164 catch(Exception ex) | |
165 { | |
166 throw new RuntimeException(ex); | |
167 } | |
168 return true; | |
169 } | |
170 return false; | |
171 } | |
172 | |
173 public boolean replace(K k, V oldv, V newv){ | |
174 Ref r = bins[binFor(k)]; | |
175 IPersistentMap map = (IPersistentMap) r.deref(); | |
176 Entry e = map.entryAt(k); | |
177 if(e != null && e.getValue().equals(oldv)) | |
178 { | |
179 r.set(map.assoc(k, newv)); | |
180 return true; | |
181 } | |
182 return false; | |
183 } | |
184 | |
185 public V replace(K k, V v){ | |
186 Ref r = bins[binFor(k)]; | |
187 IPersistentMap map = (IPersistentMap) r.deref(); | |
188 Entry e = map.entryAt(k); | |
189 if(e != null) | |
190 { | |
191 r.set(map.assoc(k, v)); | |
192 return (V) e.getValue(); | |
193 } | |
194 return null; | |
195 } | |
196 | |
197 } |