diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/ICacheEnumeration.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/ICacheEnumeration.java
new file mode 100644
index 00000000000..8135a13acf7
--- /dev/null
+++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/ICacheEnumeration.java
@@ -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 ICacheEnumeration
is used to iterate over both the keys
+ * and values in an LRUCache. The getValue()
method returns the
+ * value of the last key to be retrieved using nextElement()
.
+ * The nextElement()
method must be called before the
+ * getValue()
method.
+ *
+ *
The iteration can be made efficient by making use of the fact that values in
+ * the cache (instances of LRUCacheEntry
), know their key. For this reason,
+ * Hashtable lookups don't have to be made at each step of the iteration.
+ *
+ *
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();
+}
diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/ILRUCacheable.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/ILRUCacheable.java
new file mode 100644
index 00000000000..1293c6476c1
--- /dev/null
+++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/ILRUCacheable.java
@@ -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();
+
+}
diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/LRUCache.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/LRUCache.java
new file mode 100644
index 00000000000..9ab85bb9d90
--- /dev/null
+++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/LRUCache.java
@@ -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 LRUCache
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.
+ *
+ *
The data structure is based on the LRU virtual memory paging scheme. + * + *
Objects can take up a variable amount of cache space by implementing
+ * the ILRUCacheable
interface.
+ *
+ *
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
+ * DEFAULT_SPACELIMIT
.
+ */
+ 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;
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/LRUCacheEnumerator.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/LRUCacheEnumerator.java
new file mode 100644
index 00000000000..7be087d3fb0
--- /dev/null
+++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/LRUCacheEnumerator.java
@@ -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 LRUCacheEnumerator
returns its elements in
+ * the order they are found in the LRUCache
, 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 nextElement()
;
+ */
+ public Object fValue;
+
+ /**
+ * Next element
+ */
+ public LRUEnumeratorElement fNext;
+
+ /**
+ * Constructor
+ */
+ public LRUEnumeratorElement(Object value) {
+ fValue = value;
+ }
+ }
+ /**
+ * Creates a CacheEnumerator on the list of LRUEnumeratorElements
.
+ */
+ 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;
+ }
+}
+
diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/OverflowingLRUCache.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/OverflowingLRUCache.java
new file mode 100644
index 00000000000..c479f797d83
--- /dev/null
+++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/OverflowingLRUCache.java
@@ -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 OverflowingLRUCache
is an LRUCache which attempts
+ * to maintain a size equal or less than its fSpaceLimit
+ * by removing the least recently used elements.
+ *
+ *
The cache will remove elements which successfully close and all + * elements which are explicitly removed. + * + *
If the cache cannot remove enough old elements to add new elements
+ * it will grow beyond fSpaceLimit
. Later, it will attempt to
+ * shink back to the maximum space limit.
+ *
+ * The method close
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.
+ *
+ *
The cache implicitly attempts shrinks on calls to put
and
+ * setSpaceLimit
. Explicitly calling the shrink
method
+ * will also cause the cache to attempt to shrink.
+ *
+ *
The cache calculates the used space of all elements which implement
+ * ILRUCacheable
. All other elements are assumed to be of size one.
+ *
+ *
Use the #peek(Object)
and #disableTimestamps()
method to
+ * circumvent the timestamp feature of the cache. This feature is intended to be used
+ * only when the #close(LRUCacheEntry)
method causes changes to the cache.
+ * For example, if a parent closes its children when #close(LRUCacheEntry) is called,
+ * it should be careful not to change the LRU linked list. It can be sure it is not causing
+ * problems by calling #peek(Object)
instead of #get(Object)
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.
+ *
+ *
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 privateRemoveEntry
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 external 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 external 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 fSpaceLimit
.
+ */
+ 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.
+ *
+ *
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); + } + } + } +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/ToStringSorter.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/ToStringSorter.java new file mode 100644 index 00000000000..8ec2504ba53 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/util/ToStringSorter.java @@ -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); + } +}