68
|
1 /*
|
|
2 Copyright (c) 2008 Franklin Schmidt <fschmidt@gmail.com>
|
|
3
|
|
4 Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5 of this software and associated documentation files (the "Software"), to deal
|
|
6 in the Software without restriction, including without limitation the rights
|
|
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8 copies of the Software, and to permit persons to whom the Software is
|
|
9 furnished to do so, subject to the following conditions:
|
|
10
|
|
11 The above copyright notice and this permission notice shall be included in
|
|
12 all copies or substantial portions of the Software.
|
|
13
|
|
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20 THE SOFTWARE.
|
|
21 */
|
|
22
|
|
23 package fschmidt.db.util;
|
|
24
|
|
25 import java.lang.ref.ReferenceQueue;
|
|
26 import java.util.Map;
|
|
27 import java.util.AbstractMap;
|
|
28 import java.util.HashMap;
|
|
29 import java.util.Set;
|
|
30 import java.util.AbstractSet;
|
|
31 import java.util.Iterator;
|
|
32
|
|
33
|
|
34 public abstract class CacheMap<K,V> extends AbstractMap<K,V> {
|
|
35
|
|
36 protected static interface MyReference<K,V> {
|
|
37 public K key();
|
|
38 public V get();
|
|
39 public void clear();
|
|
40 }
|
|
41
|
|
42 protected abstract MyReference<K,V> newReference(K key,V value,ReferenceQueue<V> q);
|
|
43
|
|
44 private final Map<K,MyReference<K,V>> cache = new HashMap<K,MyReference<K,V>>();
|
|
45 private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
|
|
46
|
|
47 private void sweep() {
|
|
48 while(true) {
|
|
49 @SuppressWarnings("unchecked")
|
|
50 MyReference<K,V> ref = (MyReference<K,V>)queue.poll();
|
|
51 if( ref == null )
|
|
52 return;
|
|
53 MyReference<K,V> mappedRef = cache.remove(ref.key());
|
|
54 if( mappedRef != ref && mappedRef != null )
|
|
55 cache.put( mappedRef.key(), mappedRef ); // put it back
|
|
56 }
|
|
57 }
|
|
58
|
|
59 public int size() {
|
|
60 return cache.size();
|
|
61 }
|
|
62
|
|
63 public boolean isEmpty() {
|
|
64 return cache.isEmpty();
|
|
65 }
|
|
66
|
|
67 public boolean containsKey(Object key) {
|
|
68 return cache.containsKey(key);
|
|
69 }
|
|
70
|
|
71 public V get(Object key) {
|
|
72 MyReference<K,V> ref = cache.get(key);
|
|
73 return ref==null ? null : ref.get();
|
|
74 }
|
|
75
|
|
76 public V put(K key,V value) {
|
|
77 sweep();
|
|
78 MyReference<K,V> ref = cache.put( key, newReference(key,value,queue) );
|
|
79 return ref==null ? null : ref.get();
|
|
80 }
|
|
81
|
|
82 public V remove(Object key) {
|
|
83 sweep();
|
|
84 MyReference<K,V> ref = cache.remove(key);
|
|
85 return ref==null ? null : ref.get();
|
|
86 }
|
|
87
|
|
88 public void clear() {
|
|
89 sweep();
|
|
90 cache.clear();
|
|
91 }
|
|
92
|
|
93 /*
|
|
94 public Object clone() {
|
|
95 GCCacheMap map = new GCCacheMap();
|
|
96 map.cache = (HashMap)cache.clone();
|
|
97 return map;
|
|
98 }
|
|
99 */
|
|
100 public Set<K> keySet() {
|
|
101 return cache.keySet();
|
|
102 }
|
|
103
|
|
104 public Set<Map.Entry<K,V>> entrySet() {
|
|
105 return new MySet();
|
|
106 }
|
|
107
|
|
108
|
|
109 private class MySet extends AbstractSet<Map.Entry<K,V>> {
|
|
110
|
|
111 public int size() {
|
|
112 return CacheMap.this.size();
|
|
113 }
|
|
114
|
|
115 public Iterator<Map.Entry<K,V>> iterator() {
|
|
116 return new MyIterator(cache.entrySet().iterator());
|
|
117 }
|
|
118
|
|
119 }
|
|
120
|
|
121 private class MyIterator implements Iterator<Map.Entry<K,V>> {
|
|
122 Iterator<Map.Entry<K,MyReference<K,V>>> iter;
|
|
123
|
|
124 MyIterator(Iterator<Map.Entry<K,MyReference<K,V>>> iter) {
|
|
125 this.iter = iter;
|
|
126 }
|
|
127
|
|
128 public boolean hasNext() {
|
|
129 return iter.hasNext();
|
|
130 }
|
|
131
|
|
132 public void remove() {
|
|
133 iter.remove();
|
|
134 }
|
|
135
|
|
136 public Map.Entry<K,V> next() {
|
|
137 return new MyEntry( iter.next() );
|
|
138 }
|
|
139 }
|
|
140
|
|
141 private class MyEntry implements Map.Entry<K,V> {
|
|
142 Map.Entry<K,MyReference<K,V>> entry;
|
|
143
|
|
144 MyEntry(Map.Entry<K,MyReference<K,V>> entry) {
|
|
145 this.entry = entry;
|
|
146 }
|
|
147
|
|
148 public K getKey() {
|
|
149 return entry.getKey();
|
|
150 }
|
|
151
|
|
152 public V getValue() {
|
|
153 MyReference<K,V> ref = entry.getValue();
|
|
154 return ref.get();
|
|
155 }
|
|
156
|
|
157 public V setValue(V value) {
|
|
158 MyReference<K,V> ref = entry.setValue( newReference(getKey(),value,queue) );
|
|
159 return ref.get();
|
|
160 }
|
|
161
|
|
162 public boolean equals(Object o) {
|
|
163 if( o==null || !(o instanceof CacheMap.MyEntry) )
|
|
164 return false;
|
|
165 MyEntry m = (MyEntry)o;
|
|
166 return entry.equals(m.entry);
|
|
167 }
|
|
168
|
|
169 public int hashCode() {
|
|
170 K key = getKey();
|
|
171 V value = getValue();
|
|
172 return (key==null ? 0 : key.hashCode()) ^
|
|
173 (value==null ? 0 : value.hashCode());
|
|
174 }
|
|
175 }
|
|
176
|
|
177 }
|