diff --git a/data/test/LRUMap.fullCollection.version3.obj b/data/test/LRUMap.fullCollection.version3.obj index 7c7b42381..d40bce461 100644 Binary files a/data/test/LRUMap.fullCollection.version3.obj and b/data/test/LRUMap.fullCollection.version3.obj differ diff --git a/src/java/org/apache/commons/collections/map/LRUMap.java b/src/java/org/apache/commons/collections/map/LRUMap.java index f9f4f3677..e9f214107 100644 --- a/src/java/org/apache/commons/collections/map/LRUMap.java +++ b/src/java/org/apache/commons/collections/map/LRUMap.java @@ -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; *

* The map implements OrderedMap and entries may be queried using * the bidirectional OrderedMapIterator. 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 OrderedIterator if required. *

* All the available iterators can be reset back to the start by casting to * ResettableIterator and calling reset(). - *

- * 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,41 +213,39 @@ 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 - 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); - + reuseMapping(header.after, hashIndex, hashCode, key, value); } else { super.addMapping(hashIndex, hashCode, key, value); } } /** - * Adds a new entry into this map using access order. - *

- * This implementation adds the entry to the data storage table and - * to the start of the linked list. + * Reuses an entry by removing it and moving it to a new place in the map. * - * @param entry the entry to add + * @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 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; + 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; + 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); } /** diff --git a/src/test/org/apache/commons/collections/map/TestLRUMap.java b/src/test/org/apache/commons/collections/map/TestLRUMap.java index 07cebd8b3..d197c9a95 100644 --- a/src/test/org/apache/commons/collections/map/TestLRUMap.java +++ b/src/test/org/apache/commons/collections/map/TestLRUMap.java @@ -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 {