1 package cz.cuni.amis.utils;
2
3 import java.util.*;
4 import java.lang.ref.*;
5
6
7
8
9
10
11
12
13 public class SoftHashMap extends AbstractMap implements Map {
14
15 private Set entrySet = null;
16 private Map hash;
17 private ReferenceQueue queue = new ReferenceQueue();
18
19 static private class SoftKey extends SoftReference {
20 private int hash;
21
22 private SoftKey(Object k) {
23 super(k);
24 hash = k.hashCode();
25 }
26 private static SoftKey create(Object k) {
27 if (k == null) {
28 return null;
29 } else {
30 return new SoftKey(k);
31 }
32 }
33 private SoftKey(Object k, ReferenceQueue q) {
34 super(k, q);
35 hash = k.hashCode();
36 }
37 private static SoftKey create(Object k, ReferenceQueue q) {
38 if (k == null) {
39 return null;
40 } else {
41 return new SoftKey(k, q);
42 }
43 }
44 public boolean equals(Object o) {
45 if (this == o) {
46 return true;
47 } else if (!(o instanceof SoftKey)) {
48 return false;
49 }
50 Object t = this.get();
51 Object u = ((SoftKey)o).get();
52 if ((t == null) || (u == null)) {
53 return false;
54 } else if (t == u) {
55 return true;
56 } else {
57 return t.equals(u);
58 }
59 }
60 public int hashCode() {
61 return hash;
62 }
63 }
64
65 private void processQueue() {
66 SoftKey sk;
67 while ((sk = (SoftKey)queue.poll()) != null) {
68 hash.remove(sk);
69 }
70 }
71
72 public SoftHashMap() {
73 hash = new HashMap();
74 }
75
76 public SoftHashMap(Map t) {
77 this(Math.max(2*t.size(), 11), 0.75f);
78 putAll(t);
79 }
80
81 public SoftHashMap(int initialCapacity) {
82 hash = new HashMap(initialCapacity);
83 }
84
85 public SoftHashMap(int initialCapacity, float loadFactor) {
86 hash = new HashMap(initialCapacity, loadFactor);
87 }
88
89 public int size() {
90 return entrySet().size();
91 }
92
93 public boolean isEmpty() {
94 return entrySet().isEmpty();
95 }
96
97 public boolean containsKey(Object key) {
98 return hash.containsKey(SoftKey.create(key));
99 }
100
101 public Object get(Object key) {
102 return hash.get(SoftKey.create(key));
103 }
104
105 public Object put(Object key, Object value) {
106 processQueue();
107 return hash.put(SoftKey.create(key, queue), value);
108 }
109
110 public Object remove(Object key) {
111 processQueue();
112 return hash.remove(SoftKey.create(key));
113 }
114
115 public void clear() {
116 processQueue();
117 hash.clear();
118 }
119
120 private static class Entry implements Map.Entry {
121 private Map.Entry ent;
122 private Object key;
123
124 Entry(Map.Entry ent, Object key) {
125 this.ent = ent;
126 this.key = key;
127 }
128
129 public Object getKey() {
130 return key;
131 }
132
133 public Object getValue() {
134 return ent.getValue();
135 }
136
137 public Object setValue(Object value) {
138 return ent.setValue(value);
139 }
140
141 public boolean equals(Object o) {
142 if (!(o instanceof Map.Entry)) {
143 return false;
144 } else {
145 Map.Entry e = (Map.Entry)o;
146 Object value = getValue();
147 return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
148 (value==null ? e.getValue()==null : value.equals(e.getValue()));
149 }
150 }
151
152 public int hashCode() {
153 Object value = getValue();
154 return (((key == null) ? 0 : key.hashCode())
155 ^ ((value == null) ? 0 : value.hashCode()));
156 }
157
158 }
159
160 public Set entrySet() {
161 if (entrySet == null) {
162 entrySet = new EntrySet();
163 }
164 return entrySet;
165 }
166
167 private class EntrySet extends AbstractSet {
168 Set set = hash.entrySet();
169
170 public Iterator iterator() {
171
172 return new Iterator() {
173 Iterator iter = set.iterator();
174 Entry next = null;
175
176 public boolean hasNext() {
177 while (iter.hasNext()) {
178 Map.Entry ent = (Map.Entry)iter.next();
179 SoftKey sk = (SoftKey)ent.getKey();
180 Object k = null;
181 if ((sk != null) && ((k = sk.get()) == null)) {
182
183 continue;
184 }
185 next = new Entry(ent, k);
186 return true;
187 }
188 return false;
189 }
190
191 public Object next() {
192 if ((next == null) && !hasNext()) {
193 throw new NoSuchElementException();
194 }
195 Entry element = next;
196 next = null;
197 return element;
198 }
199
200 public void remove() {
201 iter.remove();
202 }
203 };
204 }
205
206 public boolean isEmpty() {
207 return !(iterator().hasNext());
208 }
209
210 public int size() {
211 int size = 0;
212 for (Iterator i = iterator(); i.hasNext(); i.next(), size++);
213 return size;
214 }
215
216 public boolean remove(Object o) {
217 processQueue();
218 if (!(o instanceof Map.Entry)) {
219 return false;
220 }
221 Map.Entry e = (Map.Entry)o;
222 Object ev = e.getValue();
223 SoftKey sk = SoftKey.create(e.getKey());
224 Object hv = hash.get(sk);
225 if ((hv == null)
226 ? ((ev == null) && hash.containsKey(sk)) : hv.equals(ev)) {
227 hash.remove(sk);
228 return true;
229 }
230 return false;
231 }
232
233 public int hashCode() {
234 int h = 0;
235 for (Iterator i = set.iterator(); i.hasNext();) {
236 Map.Entry ent = (Map.Entry)i.next();
237 SoftKey sk = (SoftKey)ent.getKey();
238 Object v;
239 if (sk == null) {
240 continue;
241 }
242 h += (sk.hashCode()
243 ^ (((v = ent.getValue()) == null) ? 0 : v.hashCode()));
244 }
245 return h;
246 }
247 }
248 }