View Javadoc

1   package cz.cuni.amis.utils;
2   
3   import java.util.*;
4   import java.lang.ref.*;
5   
6   /**
7    * The code has been obtained from site: http://www.java2s.com/Code/Java/Collections-Data-Structure/SoftHashMap.htm
8    * (1.3.2008)<p><p>
9    * Thank you java2s.com!
10   * 
11   * @author Jimmy
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               /* Soft key has been cleared by GC */
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 }