view 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
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 Jul 31, 2008 */
13 package clojure.lang;
15 import java.util.concurrent.ConcurrentMap;
16 import java.util.*;
18 public class TransactionalHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>{
19 final Ref[] bins;
21 IPersistentMap mapAt(int bin){
22 return (IPersistentMap) bins[bin].deref();
23 }
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 }
34 Entry entryAt(Object k){
35 return mapAt(binFor(k)).entryAt(k);
36 }
38 public TransactionalHashMap() throws Exception{
39 this(421);
40 }
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 }
48 public TransactionalHashMap(Map<? extends K, ? extends V> m) throws Exception{
49 this(m.size());
50 putAll(m);
51 }
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 }
62 public boolean isEmpty(){
63 return size() == 0;
64 }
66 public boolean containsKey(Object k){
67 return entryAt(k) != null;
68 }
70 public V get(Object k){
71 Entry e = entryAt(k);
72 if(e != null)
73 return (V) e.getValue();
74 return null;
75 }
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 }
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 }
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 }
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 }
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 }
134 public int size(){
135 return entries.size();
136 }
137 };
138 }
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 }
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 }
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 }
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 }
197 }