# HG changeset patch # User dl # Date 1237948943 25200 # Node ID e63d916028137c81facf1481be490f36b22afc55 # Parent f35f516befc3bad06bbb345cce3d628fcc8b10df 6800572: Removing elements from views of NavigableMap implementations does not always work correctly. Summary: Replace use of new TreeSet with new KeySet Reviewed-by: martin diff -r f35f516befc3 -r e63d91602813 jdk/src/share/classes/java/util/TreeMap.java --- a/jdk/src/share/classes/java/util/TreeMap.java Tue Mar 24 14:10:38 2009 +0000 +++ b/jdk/src/share/classes/java/util/TreeMap.java Tue Mar 24 19:42:23 2009 -0700 @@ -1068,14 +1068,14 @@ } public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { - return new TreeSet(m.subMap(fromElement, fromInclusive, - toElement, toInclusive)); + return new KeySet(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); } public NavigableSet headSet(E toElement, boolean inclusive) { - return new TreeSet(m.headMap(toElement, inclusive)); + return new KeySet(m.headMap(toElement, inclusive)); } public NavigableSet tailSet(E fromElement, boolean inclusive) { - return new TreeSet(m.tailMap(fromElement, inclusive)); + return new KeySet(m.tailMap(fromElement, inclusive)); } public SortedSet subSet(E fromElement, E toElement) { return subSet(fromElement, true, toElement, false); @@ -1087,7 +1087,7 @@ return tailSet(fromElement, true); } public NavigableSet descendingSet() { - return new TreeSet(m.descendingMap()); + return new KeySet(m.descendingMap()); } } diff -r f35f516befc3 -r e63d91602813 jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Tue Mar 24 14:10:38 2009 +0000 +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Tue Mar 24 19:42:23 2009 -0700 @@ -2394,15 +2394,14 @@ boolean fromInclusive, E toElement, boolean toInclusive) { - return new ConcurrentSkipListSet - (m.subMap(fromElement, fromInclusive, - toElement, toInclusive)); + return new KeySet(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); } public NavigableSet headSet(E toElement, boolean inclusive) { - return new ConcurrentSkipListSet(m.headMap(toElement, inclusive)); + return new KeySet(m.headMap(toElement, inclusive)); } public NavigableSet tailSet(E fromElement, boolean inclusive) { - return new ConcurrentSkipListSet(m.tailMap(fromElement, inclusive)); + return new KeySet(m.tailMap(fromElement, inclusive)); } public NavigableSet subSet(E fromElement, E toElement) { return subSet(fromElement, true, toElement, false); @@ -2414,7 +2413,7 @@ return tailSet(fromElement, true); } public NavigableSet descendingSet() { - return new ConcurrentSkipListSet(m.descendingMap()); + return new KeySet(m.descendingMap()); } } diff -r f35f516befc3 -r e63d91602813 jdk/test/java/util/Collection/MOAT.java --- a/jdk/test/java/util/Collection/MOAT.java Tue Mar 24 14:10:38 2009 +0000 +++ b/jdk/test/java/util/Collection/MOAT.java Tue Mar 24 19:42:23 2009 -0700 @@ -555,6 +555,7 @@ NavigableMap nm = (NavigableMap) m; + testNavigableMapRemovers(nm); testNavigableMap(nm); testNavigableMap(nm.headMap(6, false)); testNavigableMap(nm.headMap(5, true)); @@ -742,6 +743,97 @@ equal(it.next(), expected); } + static void equalMaps(Map m1, Map m2) { + equal(m1, m2); + equal(m2, m1); + equal(m1.size(), m2.size()); + equal(m1.isEmpty(), m2.isEmpty()); + equal(m1.toString(), m2.toString()); + check(Arrays.equals(m1.entrySet().toArray(), m2.entrySet().toArray())); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + static void testNavigableMapRemovers(NavigableMap m) + { + final Map emptyMap = new HashMap(); + + final Map singletonMap = new HashMap(); + singletonMap.put(1, 2); + + abstract class NavigableMapView { + abstract NavigableMap view(NavigableMap m); + } + + NavigableMapView[] views = { + new NavigableMapView() { NavigableMap view(NavigableMap m) { + return m; }}, + new NavigableMapView() { NavigableMap view(NavigableMap m) { + return m.headMap(99, true); }}, + new NavigableMapView() { NavigableMap view(NavigableMap m) { + return m.tailMap(-99, false); }}, + new NavigableMapView() { NavigableMap view(NavigableMap m) { + return m.subMap(-99, true, 99, false); }}, + }; + + abstract class Remover { + abstract void remove(NavigableMap m, Object k, Object v); + } + + Remover[] removers = { + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.remove(k), v); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.descendingMap().remove(k), v); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.descendingMap().headMap(-86, false).remove(k), v); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.descendingMap().tailMap(86, true).remove(k), v); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.headMap(86, true).remove(k), v); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.tailMap(-86, true).remove(k), v); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + equal(m.subMap(-86, false, 86, true).remove(k), v); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.keySet().remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.navigableKeySet().remove(k)); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.navigableKeySet().headSet(86, true).remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.navigableKeySet().tailSet(-86, false).remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.navigableKeySet().subSet(-86, true, 86, false) + .remove(k)); }}, + + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.descendingKeySet().headSet(-86, false).remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.descendingKeySet().tailSet(86, true).remove(k)); }}, + new Remover() { void remove(NavigableMap m, Object k, Object v) { + check(m.descendingKeySet().subSet(86, true, -86, false) + .remove(k)); }}, + }; + + for (NavigableMapView view : views) { + for (Remover remover : removers) { + try { + m.clear(); + equalMaps(m, emptyMap); + equal(m.put(1, 2), null); + equalMaps(m, singletonMap); + NavigableMap v = view.view(m); + remover.remove(v, 1, 2); + equalMaps(m, emptyMap); + } catch (Throwable t) { unexpected(t); } + } + } + } + private static void testNavigableMap(NavigableMap m) { clear(m);