|
|
@@ -0,0 +1,95 @@ |
|
|
|
/* ******************************************************************* |
|
|
|
* Copyright (c) 2017 Contributors |
|
|
|
* All rights reserved. |
|
|
|
* This program and the accompanying materials are made available |
|
|
|
* under the terms of the Eclipse Public License v1.0 |
|
|
|
* which accompanies this distribution and is available at |
|
|
|
* http://www.eclipse.org/legal/epl-v10.html |
|
|
|
* ******************************************************************/package org.aspectj.util; |
|
|
|
|
|
|
|
import java.lang.ref.*; |
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
public class SoftHashMap<K,V> extends AbstractMap<K,V> { |
|
|
|
private Map<K, SpecialValue> map; |
|
|
|
private ReferenceQueue<? super V> rq = new ReferenceQueue<>(); |
|
|
|
|
|
|
|
public SoftHashMap() { |
|
|
|
this.map = new HashMap<K,SpecialValue>(); |
|
|
|
} |
|
|
|
|
|
|
|
class SpecialValue extends SoftReference<V> { |
|
|
|
private final K key; |
|
|
|
|
|
|
|
SpecialValue(K k, V v) { |
|
|
|
super(v, rq); |
|
|
|
this.key = k; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
private void processQueue() { |
|
|
|
SpecialValue sv = null; |
|
|
|
while ((sv = (SpecialValue)rq.poll()) != null) { |
|
|
|
map.remove(sv.key); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public V get(Object key) { |
|
|
|
SpecialValue ref = map.get(key); |
|
|
|
if (ref == null) { |
|
|
|
map.remove(key); |
|
|
|
return null; |
|
|
|
} |
|
|
|
V value = ref.get(); |
|
|
|
if (value == null) { |
|
|
|
map.remove(ref.key); |
|
|
|
return null; |
|
|
|
} |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public V put(K k, V v) { |
|
|
|
processQueue(); |
|
|
|
SpecialValue sv = new SpecialValue(k, v); |
|
|
|
SpecialValue result = map.put(k, sv); |
|
|
|
return (result == null ? null : result.get()); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public java.util.Set<Map.Entry<K,V>> entrySet() { |
|
|
|
if (map.isEmpty()) { return Collections.<K,V>emptyMap().entrySet(); } |
|
|
|
Map<K,V> currentContents = new HashMap<K,V>(); |
|
|
|
for (Map.Entry<K,SpecialValue> entry: map.entrySet()) { |
|
|
|
V currentValueForEntry = entry.getValue().get(); |
|
|
|
if (currentValueForEntry != null) { |
|
|
|
currentContents.put(entry.getKey(), currentValueForEntry); |
|
|
|
} |
|
|
|
} |
|
|
|
return currentContents.entrySet(); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void clear() { |
|
|
|
processQueue(); |
|
|
|
map.clear(); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public int size() { |
|
|
|
processQueue(); |
|
|
|
return map.size(); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public V remove(Object k) { |
|
|
|
processQueue(); |
|
|
|
SpecialValue ref = map.remove(k); |
|
|
|
if (ref == null) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
return ref.get(); |
|
|
|
} |
|
|
|
} |