aboutsummaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
authorAndy Clement <aclement@pivotal.io>2017-09-28 15:52:29 -0700
committerAndy Clement <aclement@pivotal.io>2017-09-28 15:52:29 -0700
commitb7e4aff1c15a0984d4ca772ffb82cdd9b0f6fa57 (patch)
tree7ddb1bc03335301416c9f66ed1a31fa69376ccbe /util
parent50422cb5dece5859f5f2bff3027bfa33d8bf4cde (diff)
downloadaspectj-b7e4aff1c15a0984d4ca772ffb82cdd9b0f6fa57.tar.gz
aspectj-b7e4aff1c15a0984d4ca772ffb82cdd9b0f6fa57.zip
Reusable SoftHashMap utility class
Diffstat (limited to 'util')
-rw-r--r--util/src/org/aspectj/util/SoftHashMap.java95
1 files changed, 95 insertions, 0 deletions
diff --git a/util/src/org/aspectj/util/SoftHashMap.java b/util/src/org/aspectj/util/SoftHashMap.java
new file mode 100644
index 000000000..f7971bddb
--- /dev/null
+++ b/util/src/org/aspectj/util/SoftHashMap.java
@@ -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();
+ }
+}