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
@ -74,18 +74,14 @@ import java.util.Map;
* <p>
* The map implements <code>OrderedMap</code> and entries may be queried using
* 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.
* <p>
* All the available iterators can be reset back to the start by casting to
* <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
* @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 Morgan Delagrange
@ -164,30 +160,30 @@ public class LRUMap extends AbstractLinkedMap implements Serializable, Cloneable
if (entry == null) {
return null;
}
moveFirst(entry);
moveToMRU(entry);
return entry.getValue();
}
//-----------------------------------------------------------------------
/**
* Updates an existing key-value mapping.
* This implementation moves the updated entry to the top of the list.
* Moves an entry to the MRU position at the end of the list.
* This implementation moves the updated entry to the end of the list.
*
* @param entry the entry to update
* @param newValue the new value to store
* @return value the previous value
*/
protected void moveFirst(LinkEntry entry) {
if (entry.before != header) {
protected void moveToMRU(LinkEntry entry) {
if (entry.after != header) {
modCount++;
// remove
entry.after.before = entry.before;
entry.before.after = entry.after;
entry.after.before = entry.before;
// add first
entry.before = header;
entry.after = header.after;
header.after.before = entry;
header.after = entry;
entry.after = header;
entry.before = header.before;
header.before.after = entry;
header.before = entry;
}
}
@ -200,7 +196,7 @@ public class LRUMap extends AbstractLinkedMap implements Serializable, Cloneable
* @return value the previous value
*/
protected void updateEntry(HashEntry entry, Object newValue) {
moveFirst((LinkEntry) entry); // handles modCount
moveToMRU((LinkEntry) entry); // handles modCount
entry.setValue(newValue);
}
@ -217,8 +213,26 @@ public class LRUMap extends AbstractLinkedMap implements Serializable, Cloneable
*/
protected void addMapping(int hashIndex, int hashCode, Object key, Object value) {
if (size >= maxSize && removeLRU(header.before)) {
LinkEntry entry = header.before;
// remove from current location
reuseMapping(header.after, hashIndex, hashCode, key, value);
} else {
super.addMapping(hashIndex, hashCode, key, value);
}
}
/**
* Reuses an entry by removing it and moving it to a new place in the map.
*
* @param entry the entry to reuse
* @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 reuseMapping(LinkEntry entry, int hashIndex, int hashCode, Object key, Object value) {
// find the entry before the entry specified in the hash table
// remember that the parameters (except the first) refer to the new entry,
// not the old one
int removeIndex = hashIndex(entry.hashCode, data.length);
HashEntry loop = data[removeIndex];
HashEntry previous = null;
@ -226,32 +240,12 @@ public class LRUMap extends AbstractLinkedMap implements Serializable, Cloneable
previous = loop;
loop = loop.next;
}
// reuse the entry
modCount++;
removeEntry(entry, removeIndex, previous);
reuseEntry(entry, hashIndex, hashCode, key, value);
addEntry(entry, hashIndex);
} else {
super.addMapping(hashIndex, hashCode, key, value);
}
}
/**
* Adds a new entry into this map using access order.
* <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 hashIndex the index into the data array to store at
*/
protected void addEntry(HashEntry entry, int hashIndex) {
LinkEntry link = (LinkEntry) entry;
link.before = header;
link.after = header.after;
header.after.before = link;
header.after = link;
data[hashIndex] = entry;
}
/**

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
@ -58,11 +58,9 @@
package org.apache.commons.collections.map;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import junit.framework.Test;
import junit.textui.TestRunner;
@ -74,7 +72,7 @@ import org.apache.commons.collections.ResettableIterator;
/**
* 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
*/
@ -126,44 +124,44 @@ public class TestLRUMap extends AbstractTestOrderedMap {
assertEquals(true, map.isFull());
assertEquals(2, map.maxSize());
it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator();
assertSame(values[1], it.next());
assertSame(values[0], it.next());
assertSame(values[1], it.next());
map.put(keys[2], values[2]);
assertEquals(2, map.size());
assertEquals(true, map.isFull());
assertEquals(2, map.maxSize());
it = map.keySet().iterator();
assertSame(keys[2], it.next());
assertSame(keys[1], it.next());
assertSame(keys[2], it.next());
it = map.values().iterator();
assertSame(values[2], it.next());
assertSame(values[1], it.next());
assertSame(values[2], it.next());
map.put(keys[2], values[0]);
assertEquals(2, map.size());
assertEquals(true, map.isFull());
assertEquals(2, map.maxSize());
it = map.keySet().iterator();
assertSame(keys[2], it.next());
assertSame(keys[1], it.next());
assertSame(keys[2], it.next());
it = map.values().iterator();
assertSame(values[0], it.next());
assertSame(values[1], it.next());
assertSame(values[0], it.next());
map.put(keys[1], values[3]);
assertEquals(2, map.size());
assertEquals(true, map.isFull());
assertEquals(2, map.maxSize());
it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[2], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator();
assertSame(values[3], it.next());
assertSame(values[0], it.next());
assertSame(values[3], it.next());
}
//-----------------------------------------------------------------------
@ -190,8 +188,8 @@ public class TestLRUMap extends AbstractTestOrderedMap {
Iterator it = null;
resetEmpty();
map.put(keys[1], values[1]);
map.put(keys[0], values[0]);
map.put(keys[1], values[1]);
it = map.keySet().iterator();
assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
@ -199,142 +197,59 @@ public class TestLRUMap extends AbstractTestOrderedMap {
assertSame(values[0], it.next());
assertSame(values[1], it.next());
// change to order
// no change to order
map.put(keys[1], values[1]);
it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator();
assertSame(values[1], it.next());
assertSame(values[0], it.next());
assertSame(values[1], it.next());
// no change to order
map.put(keys[1], values[2]);
it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator();
assertSame(values[2], it.next());
assertSame(values[0], it.next());
assertSame(values[2], it.next());
// change to order
map.put(keys[0], values[3]);
it = map.keySet().iterator();
assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
it = map.values().iterator();
assertSame(values[3], it.next());
assertSame(values[2], it.next());
assertSame(values[3], it.next());
// change to order
map.get(keys[1]);
it = map.keySet().iterator();
assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
it = map.values().iterator();
assertSame(values[2], it.next());
assertSame(values[3], it.next());
assertSame(values[2], it.next());
// change to order
map.get(keys[0]);
it = map.keySet().iterator();
assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
it = map.values().iterator();
assertSame(values[3], it.next());
assertSame(values[2], it.next());
assertSame(values[3], it.next());
// no change to order
map.get(keys[0]);
it = map.keySet().iterator();
assertSame(keys[0], it.next());
assertSame(keys[1], it.next());
assertSame(keys[0], it.next());
it = map.values().iterator();
assertSame(values[3], it.next());
assertSame(values[2], 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));
assertSame(values[3], it.next());
}
// public void testCreate() throws Exception {