Change order of LRUMap to LRU to MRU

git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@131424 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Stephen Colebourne 2003-12-11 00:46:12 +00:00
parent 7feafdc4de
commit 2ec031411c
3 changed files with 62 additions and 153 deletions

View File

@ -1,5 +1,5 @@
/* /*
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/map/LRUMap.java,v 1.2 2003/12/07 23:59:13 scolebourne Exp $ * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/map/LRUMap.java,v 1.3 2003/12/11 00:46:12 scolebourne Exp $
* ==================================================================== * ====================================================================
* *
* The Apache Software License, Version 1.1 * The Apache Software License, Version 1.1
@ -74,18 +74,14 @@ import java.util.Map;
* <p> * <p>
* The map implements <code>OrderedMap</code> and entries may be queried using * The map implements <code>OrderedMap</code> and entries may be queried using
* the bidirectional <code>OrderedMapIterator</code>. The order returned is * the bidirectional <code>OrderedMapIterator</code>. The order returned is
* most recently used to least recently used. Iterators from map views can * least recently used to most recently used. Iterators from map views can
* also be cast to <code>OrderedIterator</code> if required. * also be cast to <code>OrderedIterator</code> if required.
* <p> * <p>
* All the available iterators can be reset back to the start by casting to * All the available iterators can be reset back to the start by casting to
* <code>ResettableIterator</code> and calling <code>reset()</code>. * <code>ResettableIterator</code> and calling <code>reset()</code>.
* <p>
* NOTE: The order of the map has changed from the previous version located
* in the main collections package. The map is now ordered most recently used
* to least recently used.
* *
* @since Commons Collections 3.0 * @since Commons Collections 3.0
* @version $Revision: 1.2 $ $Date: 2003/12/07 23:59:13 $ * @version $Revision: 1.3 $ $Date: 2003/12/11 00:46:12 $
* *
* @author James Strachan * @author James Strachan
* @author Morgan Delagrange * @author Morgan Delagrange
@ -164,30 +160,30 @@ public class LRUMap extends AbstractLinkedMap implements Serializable, Cloneable
if (entry == null) { if (entry == null) {
return null; return null;
} }
moveFirst(entry); moveToMRU(entry);
return entry.getValue(); return entry.getValue();
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* Updates an existing key-value mapping. * Moves an entry to the MRU position at the end of the list.
* This implementation moves the updated entry to the top of the list. * This implementation moves the updated entry to the end of the list.
* *
* @param entry the entry to update * @param entry the entry to update
* @param newValue the new value to store * @param newValue the new value to store
* @return value the previous value * @return value the previous value
*/ */
protected void moveFirst(LinkEntry entry) { protected void moveToMRU(LinkEntry entry) {
if (entry.before != header) { if (entry.after != header) {
modCount++; modCount++;
// remove // remove
entry.after.before = entry.before;
entry.before.after = entry.after; entry.before.after = entry.after;
entry.after.before = entry.before;
// add first // add first
entry.before = header; entry.after = header;
entry.after = header.after; entry.before = header.before;
header.after.before = entry; header.before.after = entry;
header.after = entry; header.before = entry;
} }
} }
@ -200,7 +196,7 @@ public class LRUMap extends AbstractLinkedMap implements Serializable, Cloneable
* @return value the previous value * @return value the previous value
*/ */
protected void updateEntry(HashEntry entry, Object newValue) { protected void updateEntry(HashEntry entry, Object newValue) {
moveFirst((LinkEntry) entry); // handles modCount moveToMRU((LinkEntry) entry); // handles modCount
entry.setValue(newValue); entry.setValue(newValue);
} }
@ -217,41 +213,39 @@ public class LRUMap extends AbstractLinkedMap implements Serializable, Cloneable
*/ */
protected void addMapping(int hashIndex, int hashCode, Object key, Object value) { protected void addMapping(int hashIndex, int hashCode, Object key, Object value) {
if (size >= maxSize && removeLRU(header.before)) { if (size >= maxSize && removeLRU(header.before)) {
LinkEntry entry = header.before; reuseMapping(header.after, hashIndex, hashCode, key, value);
// remove from current location
int removeIndex = hashIndex(entry.hashCode, data.length);
HashEntry loop = data[removeIndex];
HashEntry previous = null;
while (loop != entry) {
previous = loop;
loop = loop.next;
}
modCount++;
removeEntry(entry, removeIndex, previous);
reuseEntry(entry, hashIndex, hashCode, key, value);
addEntry(entry, hashIndex);
} else { } else {
super.addMapping(hashIndex, hashCode, key, value); super.addMapping(hashIndex, hashCode, key, value);
} }
} }
/** /**
* Adds a new entry into this map using access order. * Reuses an entry by removing it and moving it to a new place in the map.
* <p>
* This implementation adds the entry to the data storage table and
* to the start of the linked list.
* *
* @param entry the entry to add * @param entry the entry to reuse
* @param hashIndex the index into the data array to store at * @param hashIndex the index into the data array to store at
* @param hashCode the hash code of the key to add
* @param key the key to add
* @param value the value to add
* @return the value previously mapped to this key, null if none
*/ */
protected void addEntry(HashEntry entry, int hashIndex) { protected void reuseMapping(LinkEntry entry, int hashIndex, int hashCode, Object key, Object value) {
LinkEntry link = (LinkEntry) entry; // find the entry before the entry specified in the hash table
link.before = header; // remember that the parameters (except the first) refer to the new entry,
link.after = header.after; // not the old one
header.after.before = link; int removeIndex = hashIndex(entry.hashCode, data.length);
header.after = link; HashEntry loop = data[removeIndex];
data[hashIndex] = entry; HashEntry previous = null;
while (loop != entry) {
previous = loop;
loop = loop.next;
}
// reuse the entry
modCount++;
removeEntry(entry, removeIndex, previous);
reuseEntry(entry, hashIndex, hashCode, key, value);
addEntry(entry, hashIndex);
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/map/TestLRUMap.java,v 1.2 2003/12/07 23:59:12 scolebourne Exp $ * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/map/TestLRUMap.java,v 1.3 2003/12/11 00:46:12 scolebourne Exp $
* ==================================================================== * ====================================================================
* *
* The Apache Software License, Version 1.1 * The Apache Software License, Version 1.1
@ -58,11 +58,9 @@
package org.apache.commons.collections.map; package org.apache.commons.collections.map;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException;
import junit.framework.Test; import junit.framework.Test;
import junit.textui.TestRunner; import junit.textui.TestRunner;
@ -74,7 +72,7 @@ import org.apache.commons.collections.ResettableIterator;
/** /**
* JUnit tests. * JUnit tests.
* *
* @version $Revision: 1.2 $ $Date: 2003/12/07 23:59:12 $ * @version $Revision: 1.3 $ $Date: 2003/12/11 00:46:12 $
* *
* @author Stephen Colebourne * @author Stephen Colebourne
*/ */
@ -126,44 +124,44 @@ public class TestLRUMap extends AbstractTestOrderedMap {
assertEquals(true, map.isFull()); assertEquals(true, map.isFull());
assertEquals(2, map.maxSize()); assertEquals(2, map.maxSize());
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[0], it.next()); assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[1], it.next());
assertSame(values[0], it.next()); assertSame(values[0], it.next());
assertSame(values[1], it.next());
map.put(keys[2], values[2]); map.put(keys[2], values[2]);
assertEquals(2, map.size()); assertEquals(2, map.size());
assertEquals(true, map.isFull()); assertEquals(true, map.isFull());
assertEquals(2, map.maxSize()); assertEquals(2, map.maxSize());
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[2], it.next());
assertSame(keys[1], it.next()); assertSame(keys[1], it.next());
assertSame(keys[2], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[2], it.next());
assertSame(values[1], it.next()); assertSame(values[1], it.next());
assertSame(values[2], it.next());
map.put(keys[2], values[0]); map.put(keys[2], values[0]);
assertEquals(2, map.size()); assertEquals(2, map.size());
assertEquals(true, map.isFull()); assertEquals(true, map.isFull());
assertEquals(2, map.maxSize()); assertEquals(2, map.maxSize());
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[2], it.next());
assertSame(keys[1], it.next()); assertSame(keys[1], it.next());
assertSame(keys[2], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[0], it.next());
assertSame(values[1], it.next()); assertSame(values[1], it.next());
assertSame(values[0], it.next());
map.put(keys[1], values[3]); map.put(keys[1], values[3]);
assertEquals(2, map.size()); assertEquals(2, map.size());
assertEquals(true, map.isFull()); assertEquals(true, map.isFull());
assertEquals(2, map.maxSize()); assertEquals(2, map.maxSize());
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[2], it.next()); assertSame(keys[2], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[3], it.next());
assertSame(values[0], it.next()); assertSame(values[0], it.next());
assertSame(values[3], it.next());
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
@ -190,8 +188,8 @@ public class TestLRUMap extends AbstractTestOrderedMap {
Iterator it = null; Iterator it = null;
resetEmpty(); resetEmpty();
map.put(keys[1], values[1]);
map.put(keys[0], values[0]); map.put(keys[0], values[0]);
map.put(keys[1], values[1]);
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[0], it.next()); assertSame(keys[0], it.next());
assertSame(keys[1], it.next()); assertSame(keys[1], it.next());
@ -199,142 +197,59 @@ public class TestLRUMap extends AbstractTestOrderedMap {
assertSame(values[0], it.next()); assertSame(values[0], it.next());
assertSame(values[1], it.next()); assertSame(values[1], it.next());
// change to order // no change to order
map.put(keys[1], values[1]); map.put(keys[1], values[1]);
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[0], it.next()); assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[1], it.next());
assertSame(values[0], it.next()); assertSame(values[0], it.next());
assertSame(values[1], it.next());
// no change to order // no change to order
map.put(keys[1], values[2]); map.put(keys[1], values[2]);
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[0], it.next()); assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[2], it.next());
assertSame(values[0], it.next()); assertSame(values[0], it.next());
assertSame(values[2], it.next());
// change to order // change to order
map.put(keys[0], values[3]); map.put(keys[0], values[3]);
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[0], it.next());
assertSame(keys[1], it.next()); assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[3], it.next());
assertSame(values[2], it.next()); assertSame(values[2], it.next());
assertSame(values[3], it.next());
// change to order // change to order
map.get(keys[1]); map.get(keys[1]);
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[0], it.next()); assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[2], it.next());
assertSame(values[3], it.next()); assertSame(values[3], it.next());
assertSame(values[2], it.next());
// change to order // change to order
map.get(keys[0]); map.get(keys[0]);
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[0], it.next());
assertSame(keys[1], it.next()); assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[3], it.next());
assertSame(values[2], it.next()); assertSame(values[2], it.next());
assertSame(values[3], it.next());
// no change to order // no change to order
map.get(keys[0]); map.get(keys[0]);
it = map.keySet().iterator(); it = map.keySet().iterator();
assertSame(keys[0], it.next());
assertSame(keys[1], it.next()); assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
it = map.values().iterator(); it = map.values().iterator();
assertSame(values[3], it.next());
assertSame(values[2], it.next()); assertSame(values[2], it.next());
} assertSame(values[3], it.next());
//-----------------------------------------------------------------------
public void testFirstKey() { // override
resetEmpty();
OrderedMap ordered = (OrderedMap) map;
try {
ordered.firstKey();
fail();
} catch (NoSuchElementException ex) {}
resetFull();
ordered = (OrderedMap) map;
Object confirmedFirst = confirmed.keySet().iterator().next();
ordered.get(confirmedFirst);
assertEquals(confirmedFirst, ordered.firstKey());
}
public void testLastKey() { // override
resetEmpty();
OrderedMap ordered = (OrderedMap) map;
try {
ordered.lastKey();
fail();
} catch (NoSuchElementException ex) {}
resetFull();
ordered = (OrderedMap) map;
Object confirmedFirst = confirmed.keySet().iterator().next();
// access order, thus first in is now in last place
assertEquals(confirmedFirst, ordered.lastKey());
}
//-----------------------------------------------------------------------
public void testNextKey() { // override
resetEmpty();
OrderedMap ordered = (OrderedMap) map;
assertEquals(null, ordered.nextKey(getOtherKeys()[0]));
if (isAllowNullKey() == false) {
try {
assertEquals(null, ordered.nextKey(null)); // this is allowed too
} catch (NullPointerException ex) {}
} else {
assertEquals(null, ordered.nextKey(null));
}
resetFull();
ordered = (OrderedMap) map;
List list = new ArrayList(confirmed.keySet());
Collections.reverse(list); // first into map is eldest
Iterator it = list.iterator();
Object confirmedLast = it.next();
while (it.hasNext()) {
Object confirmedObject = it.next();
assertEquals(confirmedObject, ordered.nextKey(confirmedLast));
confirmedLast = confirmedObject;
}
assertEquals(null, ordered.nextKey(confirmedLast));
}
public void testPreviousKey() { // override
resetEmpty();
OrderedMap ordered = (OrderedMap) map;
assertEquals(null, ordered.previousKey(getOtherKeys()[0]));
if (isAllowNullKey() == false) {
try {
assertEquals(null, ordered.previousKey(null)); // this is allowed too
} catch (NullPointerException ex) {}
} else {
assertEquals(null, ordered.previousKey(null));
}
resetFull();
ordered = (OrderedMap) map;
List list = new ArrayList(confirmed.keySet());
Iterator it = list.iterator();
Object confirmedLast = it.next();
while (it.hasNext()) {
Object confirmedObject = it.next();
assertEquals(confirmedObject, ordered.previousKey(confirmedLast));
confirmedLast = confirmedObject;
}
assertEquals(null, ordered.previousKey(confirmedLast));
} }
// public void testCreate() throws Exception { // public void testCreate() throws Exception {