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