]> source.dussan.org Git - aspectj.git/commitdiff
Reusable SoftHashMap utility class
authorAndy Clement <aclement@pivotal.io>
Thu, 28 Sep 2017 22:52:29 +0000 (15:52 -0700)
committerAndy Clement <aclement@pivotal.io>
Thu, 28 Sep 2017 22:52:29 +0000 (15:52 -0700)
util/src/org/aspectj/util/SoftHashMap.java [new file with mode: 0644]

diff --git a/util/src/org/aspectj/util/SoftHashMap.java b/util/src/org/aspectj/util/SoftHashMap.java
new file mode 100644 (file)
index 0000000..f7971bd
--- /dev/null
@@ -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();
+       }
+}