mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-12 18:55:38 +02:00
New folder containing the LRU Caching classes.
This commit is contained in:
parent
1fe68a8330
commit
305ae53cf5
6 changed files with 1156 additions and 0 deletions
|
@ -0,0 +1,42 @@
|
||||||
|
package org.eclipse.cdt.internal.core.util;
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Common Public License v0.5
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/cpl-v05.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Rational Software - Initial API and implementation
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>ICacheEnumeration</code> is used to iterate over both the keys
|
||||||
|
* and values in an LRUCache. The <code>getValue()</code> method returns the
|
||||||
|
* value of the last key to be retrieved using <code>nextElement()</code>.
|
||||||
|
* The <code>nextElement()</code> method must be called before the
|
||||||
|
* <code>getValue()</code> method.
|
||||||
|
*
|
||||||
|
* <p>The iteration can be made efficient by making use of the fact that values in
|
||||||
|
* the cache (instances of <code>LRUCacheEntry</code>), know their key. For this reason,
|
||||||
|
* Hashtable lookups don't have to be made at each step of the iteration.
|
||||||
|
*
|
||||||
|
* <p>Modifications to the cache must not be performed while using the
|
||||||
|
* enumeration. Doing so will lead to an illegal state.
|
||||||
|
*
|
||||||
|
* @see LRUCache
|
||||||
|
*
|
||||||
|
* This interface is similar to the JDT ICacheEnumeration interface.
|
||||||
|
*/
|
||||||
|
public interface ICacheEnumeration extends Enumeration {
|
||||||
|
/**
|
||||||
|
* Returns the value of the previously accessed key in the enumeration.
|
||||||
|
* Must be called after a call to nextElement().
|
||||||
|
*
|
||||||
|
* @return Value of current cache entry
|
||||||
|
*/
|
||||||
|
public Object getValue();
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package org.eclipse.cdt.internal.core.util;
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Common Public License v0.5
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/cpl-v05.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Rational Software - Initial API and implementation
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types implementing this interface can occupy a variable amount of space
|
||||||
|
* in an LRUCache. Cached items that do not implement this interface are
|
||||||
|
* considered to occupy one unit of space.
|
||||||
|
*
|
||||||
|
* @see LRUCache
|
||||||
|
*
|
||||||
|
* This interface is similar to the JDT ILRUCacheable interface.
|
||||||
|
*/
|
||||||
|
public interface ILRUCacheable {
|
||||||
|
/**
|
||||||
|
* Returns the space the receiver consumes in an LRU Cache. The default space
|
||||||
|
* value is 1.
|
||||||
|
*
|
||||||
|
* @return int Amount of cache space taken by the receiver
|
||||||
|
*/
|
||||||
|
public int getCacheFootprint();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,503 @@
|
||||||
|
package org.eclipse.cdt.internal.core.util;
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Common Public License v0.5
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/cpl-v05.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Rational Software - Initial API and implementation
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>LRUCache</code> is a hashtable that stores a finite number of elements.
|
||||||
|
* When an attempt is made to add values to a full cache, the least recently used values
|
||||||
|
* in the cache are discarded to make room for the new values as necessary.
|
||||||
|
*
|
||||||
|
* <p>The data structure is based on the LRU virtual memory paging scheme.
|
||||||
|
*
|
||||||
|
* <p>Objects can take up a variable amount of cache space by implementing
|
||||||
|
* the <code>ILRUCacheable</code> interface.
|
||||||
|
*
|
||||||
|
* <p>This implementation is NOT thread-safe. Synchronization wrappers would
|
||||||
|
* have to be added to ensure atomic insertions and deletions from the cache.
|
||||||
|
*
|
||||||
|
* @see ILRUCacheable
|
||||||
|
*
|
||||||
|
* This class is similar to the JDT LRUCache class.
|
||||||
|
*/
|
||||||
|
public class LRUCache implements Cloneable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This type is used internally by the LRUCache to represent entries
|
||||||
|
* stored in the cache.
|
||||||
|
* It is static because it does not require a pointer to the cache
|
||||||
|
* which contains it.
|
||||||
|
*
|
||||||
|
* @see LRUCache
|
||||||
|
*/
|
||||||
|
protected static class LRUCacheEntry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash table key
|
||||||
|
*/
|
||||||
|
public Object _fKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash table value (an LRUCacheEntry object)
|
||||||
|
*/
|
||||||
|
public Object _fValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time value for queue sorting
|
||||||
|
*/
|
||||||
|
public int _fTimestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache footprint of this entry
|
||||||
|
*/
|
||||||
|
public int _fSpace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous entry in queue
|
||||||
|
*/
|
||||||
|
public LRUCacheEntry _fPrevious;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Next entry in queue
|
||||||
|
*/
|
||||||
|
public LRUCacheEntry _fNext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the receiver with the provided values
|
||||||
|
* for key, value, and space.
|
||||||
|
*/
|
||||||
|
public LRUCacheEntry (Object key, Object value, int space) {
|
||||||
|
_fKey = key;
|
||||||
|
_fValue = value;
|
||||||
|
_fSpace = space;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a String that represents the value of this object.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
|
||||||
|
return "LRUCacheEntry [" + _fKey + "-->" + _fValue + "]"; //$NON-NLS-3$ //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount of cache space used so far
|
||||||
|
*/
|
||||||
|
protected int fCurrentSpace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum space allowed in cache
|
||||||
|
*/
|
||||||
|
protected int fSpaceLimit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counter for handing out sequential timestamps
|
||||||
|
*/
|
||||||
|
protected int fTimestampCounter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash table for fast random access to cache entries
|
||||||
|
*/
|
||||||
|
protected Hashtable fEntryTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start of queue (most recently used entry)
|
||||||
|
*/
|
||||||
|
protected LRUCacheEntry fEntryQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End of queue (least recently used entry)
|
||||||
|
*/
|
||||||
|
protected LRUCacheEntry fEntryQueueTail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default amount of space in the cache
|
||||||
|
*/
|
||||||
|
protected static final int DEFAULT_SPACELIMIT = 100;
|
||||||
|
/**
|
||||||
|
* Creates a new cache. Size of cache is defined by
|
||||||
|
* <code>DEFAULT_SPACELIMIT</code>.
|
||||||
|
*/
|
||||||
|
public LRUCache() {
|
||||||
|
|
||||||
|
this(DEFAULT_SPACELIMIT);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Creates a new cache.
|
||||||
|
* @param size Size of Cache
|
||||||
|
*/
|
||||||
|
public LRUCache(int size) {
|
||||||
|
|
||||||
|
fTimestampCounter = fCurrentSpace = 0;
|
||||||
|
fEntryQueue = fEntryQueueTail = null;
|
||||||
|
fEntryTable = new Hashtable(size);
|
||||||
|
fSpaceLimit = size;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a new cache containing the same contents.
|
||||||
|
*
|
||||||
|
* @return New copy of object.
|
||||||
|
*/
|
||||||
|
public Object clone() {
|
||||||
|
|
||||||
|
LRUCache newCache = newInstance(fSpaceLimit);
|
||||||
|
LRUCacheEntry qEntry;
|
||||||
|
|
||||||
|
/* Preserve order of entries by copying from oldest to newest */
|
||||||
|
qEntry = this.fEntryQueueTail;
|
||||||
|
while (qEntry != null) {
|
||||||
|
newCache.privateAdd (qEntry._fKey, qEntry._fValue, qEntry._fSpace);
|
||||||
|
qEntry = qEntry._fPrevious;
|
||||||
|
}
|
||||||
|
return newCache;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Flushes all entries from the cache.
|
||||||
|
*/
|
||||||
|
public void flush() {
|
||||||
|
|
||||||
|
fCurrentSpace = 0;
|
||||||
|
LRUCacheEntry entry = fEntryQueueTail; // Remember last entry
|
||||||
|
fEntryTable = new Hashtable(); // Clear it out
|
||||||
|
fEntryQueue = fEntryQueueTail = null;
|
||||||
|
while (entry != null) { // send deletion notifications in LRU order
|
||||||
|
privateNotifyDeletionFromCache(entry);
|
||||||
|
entry = entry._fPrevious;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Flushes the given entry from the cache. Does nothing if entry does not
|
||||||
|
* exist in cache.
|
||||||
|
*
|
||||||
|
* @param key Key of object to flush
|
||||||
|
*/
|
||||||
|
public void flush (Object key) {
|
||||||
|
|
||||||
|
LRUCacheEntry entry;
|
||||||
|
|
||||||
|
entry = (LRUCacheEntry) fEntryTable.get(key);
|
||||||
|
|
||||||
|
/* If entry does not exist, return */
|
||||||
|
if (entry == null) return;
|
||||||
|
|
||||||
|
this.privateRemoveEntry (entry, false);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Answers the value in the cache at the given key.
|
||||||
|
* If the value is not in the cache, returns null
|
||||||
|
*
|
||||||
|
* @param key Hash table key of object to retrieve
|
||||||
|
* @return Retreived object, or null if object does not exist
|
||||||
|
*/
|
||||||
|
public Object get(Object key) {
|
||||||
|
|
||||||
|
LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
|
||||||
|
if (entry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateTimestamp (entry);
|
||||||
|
return entry._fValue;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the amount of space that is current used in the cache.
|
||||||
|
*/
|
||||||
|
public int getCurrentSpace() {
|
||||||
|
return fCurrentSpace;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the maximum amount of space available in the cache.
|
||||||
|
*/
|
||||||
|
public int getSpaceLimit() {
|
||||||
|
return fSpaceLimit;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns an Enumeration of the keys currently in the cache.
|
||||||
|
*/
|
||||||
|
public Enumeration keys() {
|
||||||
|
|
||||||
|
return fEntryTable.keys();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns an enumeration that iterates over all the keys and values
|
||||||
|
* currently in the cache.
|
||||||
|
*/
|
||||||
|
public ICacheEnumeration keysAndValues() {
|
||||||
|
return new ICacheEnumeration() {
|
||||||
|
|
||||||
|
Enumeration fValues = fEntryTable.elements();
|
||||||
|
LRUCacheEntry fEntry;
|
||||||
|
|
||||||
|
public boolean hasMoreElements() {
|
||||||
|
return fValues.hasMoreElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object nextElement() {
|
||||||
|
fEntry = (LRUCacheEntry) fValues.nextElement();
|
||||||
|
return fEntry._fKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
if (fEntry == null) {
|
||||||
|
throw new java.util.NoSuchElementException();
|
||||||
|
}
|
||||||
|
return fEntry._fValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Ensures there is the specified amount of free space in the receiver,
|
||||||
|
* by removing old entries if necessary. Returns true if the requested space was
|
||||||
|
* made available, false otherwise.
|
||||||
|
*
|
||||||
|
* @param space Amount of space to free up
|
||||||
|
*/
|
||||||
|
protected boolean makeSpace (int space) {
|
||||||
|
|
||||||
|
int limit;
|
||||||
|
|
||||||
|
limit = this.getSpaceLimit();
|
||||||
|
|
||||||
|
/* if space is already available */
|
||||||
|
if (fCurrentSpace + space <= limit) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if entry is too big for cache */
|
||||||
|
if (space > limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free up space by removing oldest entries */
|
||||||
|
while (fCurrentSpace + space > limit && fEntryQueueTail != null) {
|
||||||
|
this.privateRemoveEntry (fEntryQueueTail, false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a new LRUCache instance
|
||||||
|
*/
|
||||||
|
protected LRUCache newInstance(int size) {
|
||||||
|
return new LRUCache(size);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds an entry for the given key/value/space.
|
||||||
|
*/
|
||||||
|
protected void privateAdd (Object key, Object value, int space) {
|
||||||
|
|
||||||
|
LRUCacheEntry entry;
|
||||||
|
|
||||||
|
entry = new LRUCacheEntry(key, value, space);
|
||||||
|
this.privateAddEntry (entry, false);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds the given entry from the receiver.
|
||||||
|
* @param shuffle Indicates whether we are just shuffling the queue
|
||||||
|
* (i.e., the entry table is left alone).
|
||||||
|
*/
|
||||||
|
protected void privateAddEntry (LRUCacheEntry entry, boolean shuffle) {
|
||||||
|
|
||||||
|
if (!shuffle) {
|
||||||
|
fEntryTable.put (entry._fKey, entry);
|
||||||
|
fCurrentSpace += entry._fSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry._fTimestamp = fTimestampCounter++;
|
||||||
|
entry._fNext = this.fEntryQueue;
|
||||||
|
entry._fPrevious = null;
|
||||||
|
|
||||||
|
if (fEntryQueue == null) {
|
||||||
|
/* this is the first and last entry */
|
||||||
|
fEntryQueueTail = entry;
|
||||||
|
} else {
|
||||||
|
fEntryQueue._fPrevious = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
fEntryQueue = entry;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* An entry has been removed from the cache, for example because it has
|
||||||
|
* fallen off the bottom of the LRU queue.
|
||||||
|
* Subclasses could over-ride this to implement a persistent cache below the LRU cache.
|
||||||
|
*/
|
||||||
|
protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) {
|
||||||
|
// Default is NOP.
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Removes the entry from the entry queue.
|
||||||
|
* @param shuffle indicates whether we are just shuffling the queue
|
||||||
|
* (i.e., the entry table is left alone).
|
||||||
|
*/
|
||||||
|
protected void privateRemoveEntry (LRUCacheEntry entry, boolean shuffle) {
|
||||||
|
|
||||||
|
LRUCacheEntry previous, next;
|
||||||
|
|
||||||
|
previous = entry._fPrevious;
|
||||||
|
next = entry._fNext;
|
||||||
|
|
||||||
|
if (!shuffle) {
|
||||||
|
fEntryTable.remove(entry._fKey);
|
||||||
|
fCurrentSpace -= entry._fSpace;
|
||||||
|
privateNotifyDeletionFromCache(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if this was the first entry */
|
||||||
|
if (previous == null) {
|
||||||
|
fEntryQueue = next;
|
||||||
|
} else {
|
||||||
|
previous._fNext = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if this was the last entry */
|
||||||
|
if (next == null) {
|
||||||
|
fEntryQueueTail = previous;
|
||||||
|
} else {
|
||||||
|
next._fPrevious = previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the value in the cache at the given key. Returns the value.
|
||||||
|
*
|
||||||
|
* @param key Key of object to add.
|
||||||
|
* @param value Value of object to add.
|
||||||
|
* @return added value.
|
||||||
|
*/
|
||||||
|
public Object put(Object key, Object value) {
|
||||||
|
|
||||||
|
int newSpace, oldSpace, newTotal;
|
||||||
|
LRUCacheEntry entry;
|
||||||
|
|
||||||
|
/* Check whether there's an entry in the cache */
|
||||||
|
newSpace = spaceFor (key, value);
|
||||||
|
entry = (LRUCacheEntry) fEntryTable.get (key);
|
||||||
|
|
||||||
|
if (entry != null) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the entry in the cache if it would not overflow
|
||||||
|
* the cache. Otherwise flush the entry and re-add it so as
|
||||||
|
* to keep cache within budget
|
||||||
|
*/
|
||||||
|
oldSpace = entry._fSpace;
|
||||||
|
newTotal = getCurrentSpace() - oldSpace + newSpace;
|
||||||
|
if (newTotal <= getSpaceLimit()) {
|
||||||
|
updateTimestamp (entry);
|
||||||
|
entry._fValue = value;
|
||||||
|
entry._fSpace = newSpace;
|
||||||
|
this.fCurrentSpace = newTotal;
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
privateRemoveEntry (entry, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (makeSpace(newSpace)) {
|
||||||
|
privateAdd (key, value, newSpace);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Removes and returns the value in the cache for the given key.
|
||||||
|
* If the key is not in the cache, returns null.
|
||||||
|
*
|
||||||
|
* @param key Key of object to remove from cache.
|
||||||
|
* @return Value removed from cache.
|
||||||
|
*/
|
||||||
|
public Object removeKey (Object key) {
|
||||||
|
|
||||||
|
LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
|
||||||
|
if (entry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object value = entry._fValue;
|
||||||
|
this.privateRemoveEntry (entry, false);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the maximum amount of space that the cache can store
|
||||||
|
*
|
||||||
|
* @param limit Number of units of cache space
|
||||||
|
*/
|
||||||
|
public void setSpaceLimit(int limit) {
|
||||||
|
if (limit < fSpaceLimit) {
|
||||||
|
makeSpace(fSpaceLimit - limit);
|
||||||
|
}
|
||||||
|
fSpaceLimit = limit;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the space taken by the given key and value.
|
||||||
|
*/
|
||||||
|
protected int spaceFor (Object key, Object value) {
|
||||||
|
|
||||||
|
if (value instanceof ILRUCacheable) {
|
||||||
|
return ((ILRUCacheable) value).getCacheFootprint();
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a String that represents the value of this object. This method
|
||||||
|
* is for debugging purposes only.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return
|
||||||
|
"LRUCache " + (fCurrentSpace * 100.0 / fSpaceLimit) + "% full\n" + //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
this.toStringContents();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a String that represents the contents of this object. This method
|
||||||
|
* is for debugging purposes only.
|
||||||
|
*/
|
||||||
|
protected String toStringContents() {
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
int length = fEntryTable.size();
|
||||||
|
Object[] unsortedKeys = new Object[length];
|
||||||
|
String[] unsortedToStrings = new String[length];
|
||||||
|
Enumeration e = this.keys();
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
Object key = e.nextElement();
|
||||||
|
unsortedKeys[i] = key;
|
||||||
|
unsortedToStrings[i] =
|
||||||
|
(key instanceof org.eclipse.cdt.internal.core.model.CElement) ?
|
||||||
|
((org.eclipse.cdt.internal.core.model.CElement)key).getElementName() :
|
||||||
|
key.toString();
|
||||||
|
}
|
||||||
|
ToStringSorter sorter = new ToStringSorter();
|
||||||
|
sorter.sort(unsortedKeys, unsortedToStrings);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
String toString = sorter.sortedStrings[i];
|
||||||
|
Object value = this.get(sorter.sortedObjects[i]);
|
||||||
|
result.append(toString);
|
||||||
|
result.append(" -> "); //$NON-NLS-1$
|
||||||
|
result.append(value);
|
||||||
|
result.append("\n"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Updates the timestamp for the given entry, ensuring that the queue is
|
||||||
|
* kept in correct order. The entry must exist
|
||||||
|
*/
|
||||||
|
protected void updateTimestamp (LRUCacheEntry entry) {
|
||||||
|
|
||||||
|
entry._fTimestamp = fTimestampCounter++;
|
||||||
|
if (fEntryQueue != entry) {
|
||||||
|
this.privateRemoveEntry (entry, true);
|
||||||
|
this.privateAddEntry (entry, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package org.eclipse.cdt.internal.core.util;
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Common Public License v0.5
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/cpl-v05.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Rational Software - Initial API and implementation
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>LRUCacheEnumerator</code> returns its elements in
|
||||||
|
* the order they are found in the <code>LRUCache</code>, with the
|
||||||
|
* most recent elements first.
|
||||||
|
*
|
||||||
|
* Once the enumerator is created, elements which are later added
|
||||||
|
* to the cache are not returned by the enumerator. However,
|
||||||
|
* elements returned from the enumerator could have been closed
|
||||||
|
* by the cache.
|
||||||
|
*
|
||||||
|
* This class is similar to the JDT LRUCacheEnumerator class.
|
||||||
|
*/
|
||||||
|
public class LRUCacheEnumerator implements Enumeration {
|
||||||
|
/**
|
||||||
|
* Current element;
|
||||||
|
*/
|
||||||
|
protected LRUEnumeratorElement fElementQueue;
|
||||||
|
|
||||||
|
public static class LRUEnumeratorElement {
|
||||||
|
/**
|
||||||
|
* Value returned by <code>nextElement()</code>;
|
||||||
|
*/
|
||||||
|
public Object fValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Next element
|
||||||
|
*/
|
||||||
|
public LRUEnumeratorElement fNext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public LRUEnumeratorElement(Object value) {
|
||||||
|
fValue = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Creates a CacheEnumerator on the list of <code>LRUEnumeratorElements</code>.
|
||||||
|
*/
|
||||||
|
public LRUCacheEnumerator(LRUEnumeratorElement firstElement) {
|
||||||
|
fElementQueue = firstElement;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns true if more elements exist.
|
||||||
|
*/
|
||||||
|
public boolean hasMoreElements() {
|
||||||
|
return fElementQueue != null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the next element.
|
||||||
|
*/
|
||||||
|
public Object nextElement() {
|
||||||
|
Object temp = fElementQueue.fValue;
|
||||||
|
fElementQueue = fElementQueue.fNext;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,429 @@
|
||||||
|
package org.eclipse.cdt.internal.core.util;
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Common Public License v0.5
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/cpl-v05.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Rational Software - Initial API and implementation
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.core.util.LRUCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>OverflowingLRUCache</code> is an LRUCache which attempts
|
||||||
|
* to maintain a size equal or less than its <code>fSpaceLimit</code>
|
||||||
|
* by removing the least recently used elements.
|
||||||
|
*
|
||||||
|
* <p>The cache will remove elements which successfully close and all
|
||||||
|
* elements which are explicitly removed.
|
||||||
|
*
|
||||||
|
* <p>If the cache cannot remove enough old elements to add new elements
|
||||||
|
* it will grow beyond <code>fSpaceLimit</code>. Later, it will attempt to
|
||||||
|
* shink back to the maximum space limit.
|
||||||
|
*
|
||||||
|
* The method <code>close</code> should attempt to close the element. If
|
||||||
|
* the element is successfully closed it will return true and the element will
|
||||||
|
* be removed from the cache. Otherwise the element will remain in the cache.
|
||||||
|
*
|
||||||
|
* <p>The cache implicitly attempts shrinks on calls to <code>put</code>and
|
||||||
|
* <code>setSpaceLimit</code>. Explicitly calling the <code>shrink</code> method
|
||||||
|
* will also cause the cache to attempt to shrink.
|
||||||
|
*
|
||||||
|
* <p>The cache calculates the used space of all elements which implement
|
||||||
|
* <code>ILRUCacheable</code>. All other elements are assumed to be of size one.
|
||||||
|
*
|
||||||
|
* <p>Use the <code>#peek(Object)</code> and <code>#disableTimestamps()</code> method to
|
||||||
|
* circumvent the timestamp feature of the cache. This feature is intended to be used
|
||||||
|
* only when the <code>#close(LRUCacheEntry)</code> method causes changes to the cache.
|
||||||
|
* For example, if a parent closes its children when </code>#close(LRUCacheEntry)</code> is called,
|
||||||
|
* it should be careful not to change the LRU linked list. It can be sure it is not causing
|
||||||
|
* problems by calling <code>#peek(Object)</code> instead of <code>#get(Object)</code> method.
|
||||||
|
*
|
||||||
|
* @see LRUCache
|
||||||
|
*
|
||||||
|
* This class is similar to the JDT OverflowingLRUCache class.
|
||||||
|
*/
|
||||||
|
public abstract class OverflowingLRUCache extends LRUCache {
|
||||||
|
/**
|
||||||
|
* Indicates if the cache has been over filled and by how much.
|
||||||
|
*/
|
||||||
|
protected int fOverflow = 0;
|
||||||
|
/**
|
||||||
|
* Indicates whether or not timestamps should be updated
|
||||||
|
*/
|
||||||
|
protected boolean fTimestampsOn = true;
|
||||||
|
/**
|
||||||
|
* Indicates how much space should be reclaimed when the cache overflows.
|
||||||
|
* Inital load factor of one third.
|
||||||
|
*/
|
||||||
|
protected double fLoadFactor = 0.333;
|
||||||
|
/**
|
||||||
|
* Creates a OverflowingLRUCache.
|
||||||
|
* @param size Size limit of cache.
|
||||||
|
*/
|
||||||
|
public OverflowingLRUCache(int size) {
|
||||||
|
this(size, 0);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Creates a OverflowingLRUCache.
|
||||||
|
* @param size Size limit of cache.
|
||||||
|
* @param overflow Size of the overflow.
|
||||||
|
*/
|
||||||
|
public OverflowingLRUCache(int size, int overflow) {
|
||||||
|
super(size);
|
||||||
|
fOverflow = overflow;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a new cache containing the same contents.
|
||||||
|
*
|
||||||
|
* @return New copy of this object.
|
||||||
|
*/
|
||||||
|
public Object clone() {
|
||||||
|
|
||||||
|
OverflowingLRUCache newCache = (OverflowingLRUCache)newInstance(fSpaceLimit, fOverflow);
|
||||||
|
LRUCacheEntry qEntry;
|
||||||
|
|
||||||
|
/* Preserve order of entries by copying from oldest to newest */
|
||||||
|
qEntry = this.fEntryQueueTail;
|
||||||
|
while (qEntry != null) {
|
||||||
|
newCache.privateAdd (qEntry._fKey, qEntry._fValue, qEntry._fSpace);
|
||||||
|
qEntry = qEntry._fPrevious;
|
||||||
|
}
|
||||||
|
return newCache;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns true if the element is successfully closed and
|
||||||
|
* removed from the cache, otherwise false.
|
||||||
|
*
|
||||||
|
* <p>NOTE: this triggers an external remove from the cache
|
||||||
|
* by closing the obejct.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected abstract boolean close(LRUCacheEntry entry);
|
||||||
|
/**
|
||||||
|
* Returns an enumerator of the values in the cache with the most
|
||||||
|
* recently used first.
|
||||||
|
*/
|
||||||
|
public Enumeration elements() {
|
||||||
|
if (fEntryQueue == null)
|
||||||
|
return new LRUCacheEnumerator(null);
|
||||||
|
LRUCacheEnumerator.LRUEnumeratorElement head =
|
||||||
|
new LRUCacheEnumerator.LRUEnumeratorElement(fEntryQueue._fValue);
|
||||||
|
LRUCacheEntry currentEntry = fEntryQueue._fNext;
|
||||||
|
LRUCacheEnumerator.LRUEnumeratorElement currentElement = head;
|
||||||
|
while(currentEntry != null) {
|
||||||
|
currentElement.fNext = new LRUCacheEnumerator.LRUEnumeratorElement(currentEntry._fValue);
|
||||||
|
currentElement = currentElement.fNext;
|
||||||
|
|
||||||
|
currentEntry = currentEntry._fNext;
|
||||||
|
}
|
||||||
|
return new LRUCacheEnumerator(head);
|
||||||
|
}
|
||||||
|
public double fillingRatio() {
|
||||||
|
return (fCurrentSpace + fOverflow) * 100.0 / fSpaceLimit;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* For internal testing only.
|
||||||
|
* This method exposed only for testing purposes!
|
||||||
|
*
|
||||||
|
* @return Hashtable of entries
|
||||||
|
*/
|
||||||
|
public java.util.Hashtable getEntryTable() {
|
||||||
|
return fEntryTable;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the load factor for the cache. The load factor determines how
|
||||||
|
* much space is reclaimed when the cache exceeds its space limit.
|
||||||
|
* @return double
|
||||||
|
*/
|
||||||
|
public double getLoadFactor() {
|
||||||
|
return fLoadFactor;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return The space by which the cache has overflown.
|
||||||
|
*/
|
||||||
|
public int getOverflow() {
|
||||||
|
return fOverflow;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Ensures there is the specified amount of free space in the receiver,
|
||||||
|
* by removing old entries if necessary. Returns true if the requested space was
|
||||||
|
* made available, false otherwise. May not be able to free enough space
|
||||||
|
* since some elements cannot be removed until they are saved.
|
||||||
|
*
|
||||||
|
* @param space Amount of space to free up
|
||||||
|
*/
|
||||||
|
protected boolean makeSpace(int space) {
|
||||||
|
|
||||||
|
int limit = fSpaceLimit;
|
||||||
|
if (fOverflow == 0) {
|
||||||
|
/* if space is already available */
|
||||||
|
if (fCurrentSpace + space <= limit) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free up space by removing oldest entries */
|
||||||
|
int spaceNeeded = (int)((1 - fLoadFactor) * fSpaceLimit);
|
||||||
|
spaceNeeded = (spaceNeeded > space) ? spaceNeeded : space;
|
||||||
|
LRUCacheEntry entry = fEntryQueueTail;
|
||||||
|
|
||||||
|
while (fCurrentSpace + spaceNeeded > limit && entry != null) {
|
||||||
|
this.privateRemoveEntry(entry, false, false);
|
||||||
|
entry = entry._fPrevious;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check again, since we may have aquired enough space */
|
||||||
|
if (fCurrentSpace + space <= limit) {
|
||||||
|
fOverflow = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update fOverflow */
|
||||||
|
fOverflow = fCurrentSpace + space - limit;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a new instance of the reciever.
|
||||||
|
*/
|
||||||
|
protected abstract LRUCache newInstance(int size, int overflow);
|
||||||
|
/**
|
||||||
|
* Answers the value in the cache at the given key.
|
||||||
|
* If the value is not in the cache, returns null
|
||||||
|
*
|
||||||
|
* This function does not modify timestamps.
|
||||||
|
*/
|
||||||
|
public Object peek(Object key) {
|
||||||
|
|
||||||
|
LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
|
||||||
|
if (entry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return entry._fValue;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* For testing purposes only
|
||||||
|
*/
|
||||||
|
public void printStats() {
|
||||||
|
int forwardListLength = 0;
|
||||||
|
LRUCacheEntry entry = fEntryQueue;
|
||||||
|
while(entry != null) {
|
||||||
|
forwardListLength++;
|
||||||
|
entry = entry._fNext;
|
||||||
|
}
|
||||||
|
System.out.println("Forward length: " + forwardListLength); //$NON-NLS-1$
|
||||||
|
|
||||||
|
int backwardListLength = 0;
|
||||||
|
entry = fEntryQueueTail;
|
||||||
|
while(entry != null) {
|
||||||
|
backwardListLength++;
|
||||||
|
entry = entry._fPrevious;
|
||||||
|
}
|
||||||
|
System.out.println("Backward length: " + backwardListLength); //$NON-NLS-1$
|
||||||
|
|
||||||
|
Enumeration keys = fEntryTable.keys();
|
||||||
|
class Temp {
|
||||||
|
public Class fClass;
|
||||||
|
public int fCount;
|
||||||
|
public Temp(Class aClass) {
|
||||||
|
fClass = aClass;
|
||||||
|
fCount = 1;
|
||||||
|
}
|
||||||
|
public String toString() {
|
||||||
|
return "Class: " + fClass + " has " + fCount + " entries."; //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
java.util.HashMap h = new java.util.HashMap();
|
||||||
|
while(keys.hasMoreElements()) {
|
||||||
|
entry = (LRUCacheEntry)fEntryTable.get(keys.nextElement());
|
||||||
|
Class key = entry._fValue.getClass();
|
||||||
|
Temp t = (Temp)h.get(key);
|
||||||
|
if (t == null) {
|
||||||
|
h.put(key, new Temp(key));
|
||||||
|
} else {
|
||||||
|
t.fCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator iter = h.keySet().iterator(); iter.hasNext();){
|
||||||
|
System.out.println(h.get(iter.next()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Removes the entry from the entry queue.
|
||||||
|
* Calls <code>privateRemoveEntry</code> with the external functionality enabled.
|
||||||
|
*
|
||||||
|
* @param shuffle indicates whether we are just shuffling the queue
|
||||||
|
* (i.e., the entry table is left alone).
|
||||||
|
*/
|
||||||
|
protected void privateRemoveEntry (LRUCacheEntry entry, boolean shuffle) {
|
||||||
|
privateRemoveEntry(entry, shuffle, true);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Removes the entry from the entry queue. If <i>external</i> is true, the entry is removed
|
||||||
|
* without checking if it can be removed. It is assumed that the client has already closed
|
||||||
|
* the element it is trying to remove (or will close it promptly).
|
||||||
|
*
|
||||||
|
* If <i>external</i> is false, and the entry could not be closed, it is not removed and the
|
||||||
|
* pointers are not changed.
|
||||||
|
*
|
||||||
|
* @param shuffle indicates whether we are just shuffling the queue
|
||||||
|
* (i.e., the entry table is left alone).
|
||||||
|
*/
|
||||||
|
protected void privateRemoveEntry(LRUCacheEntry entry, boolean shuffle, boolean external) {
|
||||||
|
|
||||||
|
if (!shuffle) {
|
||||||
|
if (external) {
|
||||||
|
fEntryTable.remove(entry._fKey);
|
||||||
|
fCurrentSpace -= entry._fSpace;
|
||||||
|
privateNotifyDeletionFromCache(entry);
|
||||||
|
} else {
|
||||||
|
if (!close(entry)) return;
|
||||||
|
// buffer close will recursively call #privateRemoveEntry with external==true
|
||||||
|
// thus entry will already be removed if reaching this point.
|
||||||
|
if (fEntryTable.get(entry._fKey) == null){
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// basic removal
|
||||||
|
fEntryTable.remove(entry._fKey);
|
||||||
|
fCurrentSpace -= entry._fSpace;
|
||||||
|
privateNotifyDeletionFromCache(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LRUCacheEntry previous = entry._fPrevious;
|
||||||
|
LRUCacheEntry next = entry._fNext;
|
||||||
|
|
||||||
|
/* if this was the first entry */
|
||||||
|
if (previous == null) {
|
||||||
|
fEntryQueue = next;
|
||||||
|
} else {
|
||||||
|
previous._fNext = next;
|
||||||
|
}
|
||||||
|
/* if this was the last entry */
|
||||||
|
if (next == null) {
|
||||||
|
fEntryQueueTail = previous;
|
||||||
|
} else {
|
||||||
|
next._fPrevious = previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the value in the cache at the given key. Returns the value.
|
||||||
|
*
|
||||||
|
* @param key Key of object to add.
|
||||||
|
* @param value Value of object to add.
|
||||||
|
* @return added value.
|
||||||
|
*/
|
||||||
|
public Object put(Object key, Object value) {
|
||||||
|
/* attempt to rid ourselves of the overflow, if there is any */
|
||||||
|
if (fOverflow > 0)
|
||||||
|
shrink();
|
||||||
|
|
||||||
|
/* Check whether there's an entry in the cache */
|
||||||
|
int newSpace = spaceFor (key, value);
|
||||||
|
LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get (key);
|
||||||
|
|
||||||
|
if (entry != null) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the entry in the cache if it would not overflow
|
||||||
|
* the cache. Otherwise flush the entry and re-add it so as
|
||||||
|
* to keep cache within budget
|
||||||
|
*/
|
||||||
|
int oldSpace = entry._fSpace;
|
||||||
|
int newTotal = fCurrentSpace - oldSpace + newSpace;
|
||||||
|
if (newTotal <= fSpaceLimit) {
|
||||||
|
updateTimestamp (entry);
|
||||||
|
entry._fValue = value;
|
||||||
|
entry._fSpace = newSpace;
|
||||||
|
fCurrentSpace = newTotal;
|
||||||
|
fOverflow = 0;
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
privateRemoveEntry (entry, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt to make new space
|
||||||
|
makeSpace(newSpace);
|
||||||
|
|
||||||
|
// add without worring about space, it will
|
||||||
|
// be handled later in a makeSpace call
|
||||||
|
privateAdd (key, value, newSpace);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Removes and returns the value in the cache for the given key.
|
||||||
|
* If the key is not in the cache, returns null.
|
||||||
|
*
|
||||||
|
* @param key Key of object to remove from cache.
|
||||||
|
* @return Value removed from cache.
|
||||||
|
*/
|
||||||
|
public Object remove(Object key) {
|
||||||
|
return removeKey(key);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the load factor for the cache. The load factor determines how
|
||||||
|
* much space is reclaimed when the cache exceeds its space limit.
|
||||||
|
* @param newLoadFactor double
|
||||||
|
* @throws IllegalArgumentException when the new load factor is not in (0.0, 1.0]
|
||||||
|
*/
|
||||||
|
public void setLoadFactor(double newLoadFactor) throws IllegalArgumentException {
|
||||||
|
if(newLoadFactor <= 1.0 && newLoadFactor > 0.0)
|
||||||
|
fLoadFactor = newLoadFactor;
|
||||||
|
else
|
||||||
|
throw new IllegalArgumentException("cache.invalidLoadFactor"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the maximum amount of space that the cache can store
|
||||||
|
*
|
||||||
|
* @param limit Number of units of cache space
|
||||||
|
*/
|
||||||
|
public void setSpaceLimit(int limit) {
|
||||||
|
if (limit < fSpaceLimit) {
|
||||||
|
makeSpace(fSpaceLimit - limit);
|
||||||
|
}
|
||||||
|
fSpaceLimit = limit;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Attempts to shrink the cache if it has overflown.
|
||||||
|
* Returns true if the cache shrinks to less than or equal to <code>fSpaceLimit</code>.
|
||||||
|
*/
|
||||||
|
public boolean shrink() {
|
||||||
|
if (fOverflow > 0)
|
||||||
|
return makeSpace(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a String that represents the value of this object. This method
|
||||||
|
* is for debugging purposes only.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return
|
||||||
|
"OverflowingLRUCache " + this.fillingRatio() + "% full\n" + //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
this.toStringContents();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Updates the timestamp for the given entry, ensuring that the queue is
|
||||||
|
* kept in correct order. The entry must exist.
|
||||||
|
*
|
||||||
|
* <p>This method will do nothing if timestamps have been disabled.
|
||||||
|
*/
|
||||||
|
protected void updateTimestamp(LRUCacheEntry entry) {
|
||||||
|
if (fTimestampsOn) {
|
||||||
|
entry._fTimestamp = fTimestampCounter++;
|
||||||
|
if (fEntryQueue != entry) {
|
||||||
|
this.privateRemoveEntry(entry, true);
|
||||||
|
this.privateAddEntry(entry, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package org.eclipse.cdt.internal.core.util;
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Common Public License v0.5
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/cpl-v05.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Rational Software - Initial API and implementation
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SortOperation takes a collection of objects and returns
|
||||||
|
* a sorted collection of these objects. The sorting of these
|
||||||
|
* objects is based on their toString(). They are sorted in
|
||||||
|
* alphabetical order.
|
||||||
|
*
|
||||||
|
* This class is similar to the JDT toStringSorter class.
|
||||||
|
*/
|
||||||
|
public class ToStringSorter {
|
||||||
|
Object[] sortedObjects;
|
||||||
|
String[] sortedStrings;
|
||||||
|
/**
|
||||||
|
* Returns true if stringTwo is 'greater than' stringOne
|
||||||
|
* This is the 'ordering' method of the sort operation.
|
||||||
|
*/
|
||||||
|
public boolean compare(String stringOne, String stringTwo) {
|
||||||
|
return stringOne.compareTo(stringTwo) < 0;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sort the objects in sorted collection and return that collection.
|
||||||
|
*/
|
||||||
|
private void quickSort(int left, int right) {
|
||||||
|
int originalLeft = left;
|
||||||
|
int originalRight = right;
|
||||||
|
int midIndex = (left + right) / 2;
|
||||||
|
String midToString = this.sortedStrings[midIndex];
|
||||||
|
|
||||||
|
do {
|
||||||
|
while (compare(this.sortedStrings[left], midToString))
|
||||||
|
left++;
|
||||||
|
while (compare(midToString, this.sortedStrings[right]))
|
||||||
|
right--;
|
||||||
|
if (left <= right) {
|
||||||
|
Object tmp = this.sortedObjects[left];
|
||||||
|
this.sortedObjects[left] = this.sortedObjects[right];
|
||||||
|
this.sortedObjects[right] = tmp;
|
||||||
|
String tmpToString = this.sortedStrings[left];
|
||||||
|
this.sortedStrings[left] = this.sortedStrings[right];
|
||||||
|
this.sortedStrings[right] = tmpToString;
|
||||||
|
left++;
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
} while (left <= right);
|
||||||
|
|
||||||
|
if (originalLeft < right)
|
||||||
|
quickSort(originalLeft, right);
|
||||||
|
if (left < originalRight)
|
||||||
|
quickSort(left, originalRight);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return a new sorted collection from this unsorted collection.
|
||||||
|
* Sort using quick sort.
|
||||||
|
*/
|
||||||
|
public void sort(Object[] unSortedObjects, String[] unsortedStrings) {
|
||||||
|
int size = unSortedObjects.length;
|
||||||
|
this.sortedObjects = new Object[size];
|
||||||
|
this.sortedStrings = new String[size];
|
||||||
|
|
||||||
|
//copy the array so can return a new sorted collection
|
||||||
|
System.arraycopy(unSortedObjects, 0, this.sortedObjects, 0, size);
|
||||||
|
System.arraycopy(unsortedStrings, 0, this.sortedStrings, 0, size);
|
||||||
|
if (size > 1)
|
||||||
|
quickSort(0, size - 1);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue