/*******************************************************************************
* Copyright © 2005, 2013 IBM Corporation and others.
* 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.ide.core.internal.model;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
/**
* @author winghong
*/
public class SoftLRUCache {
private static final boolean DEBUG = false;
private static class OrderedSoftReference extends SoftReference {
OrderedSoftReference previous;
OrderedSoftReference next;
Object key;
// Used for sentinel values
OrderedSoftReference() {
super(null);
}
OrderedSoftReference(Object key, Object referent, ReferenceQueue q, OrderedSoftReference previous, OrderedSoftReference next) {
super(referent, q);
this.key = key;
this.previous = previous;
this.next = next;
this.previous.next = this;
this.next.previous = this;
}
OrderedSoftReference remove() {
if(DEBUG) System.out.println("Remove: " + key); //$NON-NLS-1$
previous.next = next;
next.previous = previous;
return this;
}
}
private OrderedSoftReference first;
private OrderedSoftReference last;
private Map softReferences;
private ReferenceQueue referenceQueue;
private int maxSize;
public SoftLRUCache(int maxSize) {
this.maxSize = maxSize;
this.softReferences = new HashMap();
this.referenceQueue = new ReferenceQueue();
this.first = new OrderedSoftReference();
this.last = new OrderedSoftReference();
this.first.next = last;
this.last.previous = first;
}
public void put(Object key, Object value) {
if(DEBUG) System.out.println("Put: " + key); //$NON-NLS-1$
removeClearedReferences();
softReferences.put(key, new OrderedSoftReference(key, value, referenceQueue, first, first.next));
if(softReferences.size() > maxSize) {
if(DEBUG) System.out.println("Removing oldest key"); //$NON-NLS-1$
softReferences.remove(last.previous.remove().key);
}
}
public Object get(Object key) {
removeClearedReferences();
OrderedSoftReference ref = (OrderedSoftReference) softReferences.get(key);
if(ref == null) {
return null;
}
Object result = ref.get();
if(result != null) {
ref.remove();
ref.next = first.next;
ref.previous = first;
first.next.previous = ref;
first.next = ref;
}
if(DEBUG && result == null) System.out.println("Key " + key + " has been cleared"); //$NON-NLS-1$ //$NON-NLS-2$
return result;
}
private void removeClearedReferences() {
OrderedSoftReference ref;
while((ref = (OrderedSoftReference) referenceQueue.poll()) != null) {
if(DEBUG) System.out.println("Removing cleared soft reference"); //$NON-NLS-1$
softReferences.remove(ref.remove().key);
}
}
public static void main(String[] args) {
StrongLRUCache cache = new StrongLRUCache(5);
for(int i = 0; i < 100; i++) {
Integer key = new Integer((int) Math.floor(Math.random() * 100));
if(Math.round(Math.random()) == 0) {
int sizeInKilobytes = (int) Math.floor(Math.random() * 100);
int[] value = new int[sizeInKilobytes * 1024];
cache.put(key, value);
}
else {
if(cache.get(key) != null) {
System.out.println("Get: " + key); //$NON-NLS-1$
}
else {
System.out.println("Key Not found: " + key); //$NON-NLS-1$
}
}
}
}
}