Browse Source

Reusable SoftHashMap utility class

tags/V1_9_0_RC3
Andy Clement 6 years ago
parent
commit
b7e4aff1c1
1 changed files with 95 additions and 0 deletions
  1. 95
    0
      util/src/org/aspectj/util/SoftHashMap.java

+ 95
- 0
util/src/org/aspectj/util/SoftHashMap.java View File

@@ -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();
}
}

Loading…
Cancel
Save