// Copyright (c) 2017 Pierantonio Cangianiello (original name: SelfExpiringHashMap)
// thread-safe.
sclass ExpiringHashMap<K, V> implements Map<K, V> {
final Map<K, V> internalMap;
final Map<K, ExpiringKey<K>> expiringKeys;
final DelayQueue<ExpiringKey> delayQueue = new DelayQueue<ExpiringKey>();
long maxLifeTimeMillis;
bool renewOnGet, renewOnOverwrite = true;
*() {
this(Long.MAX_VALUE);
}
*(long defaultMaxLifeTimeMillis) {
internalMap = new ConcurrentHashMap<K, V>();
expiringKeys = new WeakHashMap<K, ExpiringKey<K>>();
this.maxLifeTimeMillis = defaultMaxLifeTimeMillis;
}
public int size() {
cleanup();
return internalMap.size();
}
public boolean isEmpty() {
cleanup();
return internalMap.isEmpty();
}
public boolean containsKey(Object key) {
cleanup();
return internalMap.containsKey((K) key);
}
public boolean containsValue(Object value) {
cleanup();
return internalMap.containsValue((V) value);
}
public V get(Object key) {
cleanup();
if (renewOnGet) renewKey((K) key);
return internalMap.get((K) key);
}
public V put(K key, V value) {
return this.put(key, value, maxLifeTimeMillis);
}
public V put(K key, V value, long lifeTimeMillis) {
cleanup();
ExpiringKey delayedKey = new ExpiringKey(key, lifeTimeMillis);
ExpiringKey oldKey = expiringKeys.put((K) key, delayedKey);
if(oldKey != null) {
if (!renewOnOverwrite) {
delayedKey.startTime = oldKey.startTime;
delayedKey.maxLifeTimeMillis = oldKey.maxLifeTimeMillis;
}
expireKey(oldKey);
expiringKeys.put((K) key, delayedKey);
}
delayQueue.offer(delayedKey);
return internalMap.put(key, value);
}
public V remove(Object key) {
V removedValue = internalMap.remove((K) key);
expireKey(expiringKeys.remove((K) key));
return removedValue;
}
public void putAll(Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException();
}
public boolean renewKey(K key) {
ExpiringKey<K> delayedKey = expiringKeys.get((K) key);
if (delayedKey != null) {
delayedKey.renew();
return true;
}
return false;
}
private void expireKey(ExpiringKey<K> delayedKey) {
if (delayedKey != null) {
delayedKey.expire();
cleanup();
}
}
public void clear() {
delayQueue.clear();
expiringKeys.clear();
internalMap.clear();
}
public Set<K> keySet() {
cleanup();
ret internalMap.keySet(); // TODO: sync
}
public Collection<V> values() {
throw new UnsupportedOperationException();
}
public Set<Entry<K, V>> entrySet() {
throw new UnsupportedOperationException();
}
private void cleanup() {
ExpiringKey<K> delayedKey = delayQueue.poll();
while (delayedKey != null) {
internalMap.remove(delayedKey.getKey());
expiringKeys.remove(delayedKey.getKey());
delayedKey = delayQueue.poll();
}
}
class ExpiringKey<K> implements Delayed {
private long startTime = System.currentTimeMillis();
private long maxLifeTimeMillis;
private final K key;
public ExpiringKey(K key, long maxLifeTimeMillis) {
this.maxLifeTimeMillis = maxLifeTimeMillis;
this.key = key;
}
public K getKey() {
return key;
}
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ExpiringKey<K> other = (ExpiringKey<K>) obj;
if (this.key != other.key && (this.key == null || !this.key.equals(other.key))) {
return false;
}
return true;
}
public int hashCode() {
int hash = 7;
hash = 31 * hash + (this.key != null ? this.key.hashCode() : 0);
return hash;
}
public long getDelay(TimeUnit unit) {
return unit.convert(getDelayMillis(), TimeUnit.MILLISECONDS);
}
private long getDelayMillis() {
return (startTime + maxLifeTimeMillis) - System.currentTimeMillis();
}
public void renew() {
startTime = System.currentTimeMillis();
}
public void expire() {
startTime = System.currentTimeMillis() - maxLifeTimeMillis - 1;
}
public int compareTo(Delayed that) {
return Long.compare(this.getDelayMillis(), ((ExpiringKey) that).getDelayMillis());
}
}
ExpiringHashMap<K, V> dontRenewOnOverwrite() {
renewOnOverwrite = false;
this;
}
}download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
1 comment(s) hidden. show
| Snippet ID: | #1011872 |
| Snippet name: | ExpiringHashMap - use ExpiringMap2 instead |
| Eternal ID of this version: | #1011872/12 |
| Text MD5: | b474ca9479d962e486b49f813d521719 |
| Author: | stefan |
| Category: | javax |
| Type: | JavaX fragment (include) |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2018-07-14 12:14:12 |
| Source code size: | 5235 bytes / 182 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 1477 / 2075 |
| Version history: | 11 change(s) |
| Referenced in: | [show references] |