TreeMap.navigableKeySet().descendingIterator() sequence ?

Martin Buchholz martinrb at google.com
Sun Apr 20 00:56:09 UTC 2008


Alan, thanks for filing the bug.

Charlie, thanks for the review.  However, since you are not (yet?)
an OpenJDK committer, I will still need an official review from Doug
(or Alan?)

I noticed there was another test case, NavigableMap/LockStep.java,
that "almost" tested the faulty code.

I include a change to that test case as well, below
(as well as making the test case a little more maintainble).

diff --git a/test/java/util/NavigableMap/LockStep.java
b/test/java/util/NavigableMap/LockStep.java
--- a/test/java/util/NavigableMap/LockStep.java
+++ b/test/java/util/NavigableMap/LockStep.java
@@ -159,6 +159,7 @@ public class LockStep {
         Object[] a = new Object[1]; a[0] = Boolean.TRUE;
         equal(c.toArray(a), a);
         equal(a[0], null);
+        check(! c.iterator().hasNext());
     }

     static void testEmptySet(Set<?> c) {
@@ -262,6 +263,16 @@ public class LockStep {
         }
     }

+    static void equalIterators(final Iterator<?> it1,
+                               final Iterator<?> it2) {
+        while (it1.hasNext()) {
+            if (maybe(2))
+                check(it2.hasNext());
+            equal(it1.next(), it2.next());
+        }
+        check(! it2.hasNext());
+    }
+
     static void equalNavigableSetsLeaf(final NavigableSet s1,
                                        final NavigableSet s2) {
         equal2(s1,            s2);
@@ -273,6 +284,8 @@ public class LockStep {
             equal(s1.first(), s2.first());
             equal(s1.last(),  s2.last());
         }
+        equalIterators(s1.iterator(), s2.iterator());
+        equalIterators(s1.descendingIterator(), s2.descendingIterator());
         checkNavigableSet(s1);
         checkNavigableSet(s2);
     }
@@ -493,30 +506,23 @@ public class LockStep {

     static MapFrobber randomAdder(NavigableMap m) {
         final Integer k = unusedKey(m);
-        MapFrobber f;
-        switch (rnd.nextInt(4)) {
-        case 0: f = new MapFrobber() {void frob(NavigableMap m) {
-            equal(m.put(k, k+1), null);
-            equal(m.get(k), k+1);
-            if (maybe(4)) {
-                equal(m.put(k, k+1), k+1);
-                equal(m.get(k), k+1);}}};
-            break;
-        case 1: f = new MapFrobber() {void frob(NavigableMap m) {
-            m.descendingMap().put(k, k+1);
-            equal(m.get(k), k+1);}};
-            break;
-        case 2: f = new MapFrobber() {void frob(NavigableMap m) {
-            m.tailMap(k,true).headMap(k,true).put(k,k+1);}};
-            break;
-        case 3: f = new MapFrobber() {void frob(NavigableMap m) {
-            m.tailMap(k,true).headMap(k,true).descendingMap().put(k,k+1);}};
-            break;
-        default: throw new Error();
-        }
-        final MapFrobber ff = f;
+        final MapFrobber[] randomAdders = {
+            new MapFrobber() {void frob(NavigableMap m) {
+                equal(m.put(k, k+1), null);
+                equal(m.get(k), k+1);
+                if (maybe(4)) {
+                    equal(m.put(k, k+1), k+1);
+                    equal(m.get(k), k+1);}}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                m.descendingMap().put(k, k+1);
+                equal(m.get(k), k+1);}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                m.tailMap(k,true).headMap(k,true).put(k,k+1);}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                m.tailMap(k,true).headMap(k,true).descendingMap().put(k,k+1);}}
+        };
         return new MapFrobber() {void frob(NavigableMap m) {
-            ff.frob(m);
+            randomAdders[rnd.nextInt(randomAdders.length)].frob(m);
             if (maybe(2)) equal(m.get(k), k+1);
             if (maybe(4)) {
                 equal(m.put(k, k+1), k+1);
@@ -525,26 +531,19 @@ public class LockStep {

     static SetFrobber randomAdder(NavigableSet s) {
         final Integer e = unusedElt(s);
-        SetFrobber f;
-        switch (rnd.nextInt(4)) {
-        case 0: f = new SetFrobber() {void frob(NavigableSet s) {
-            check(s.add(e));}};
-            break;
-        case 1: f = new SetFrobber() {void frob(NavigableSet s) {
-            s.descendingSet().add(e);}};
-            break;
-        case 2: f = new SetFrobber() {void frob(NavigableSet s) {
-            s.tailSet(e,true).headSet(e,true).add(e);}};
-            break;
-        case 3: f = new SetFrobber() {void frob(NavigableSet s) {
-            s.descendingSet().tailSet(e,true).headSet(e,true).add(e);}};
-            break;
-        default: throw new Error();
-        }
-        final SetFrobber ff = f;
+        final SetFrobber[] randomAdders = {
+            new SetFrobber() {void frob(NavigableSet s) {
+                check(s.add(e));}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                s.descendingSet().add(e);}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                s.tailSet(e,true).headSet(e,true).add(e);}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                s.descendingSet().tailSet(e,true).headSet(e,true).add(e);}}
+        };
         return new SetFrobber() {void frob(NavigableSet s) {
             if (maybe(2)) check(! s.contains(e));
-            ff.frob(s);
+            randomAdders[rnd.nextInt(randomAdders.length)].frob(s);
             if (maybe(2)) check(! s.add(e));
             if (maybe(2)) check(s.contains(e));}};
     }
@@ -605,89 +604,112 @@ public class LockStep {

     static MapFrobber randomRemover(NavigableMap m) {
         final Integer k = usedKey(m);
-        switch (rnd.nextInt(7)) {
-        default: throw new Error();
-        case 0: return new MapFrobber() {void frob(NavigableMap m) {
-            Map.Entry e = m.firstEntry();
-            equal(m.pollFirstEntry(), e);
-            checkUnusedKey(m, e.getKey());}};
-        case 1: return new MapFrobber() {void frob(NavigableMap m) {
-            Map.Entry e = m.lastEntry();
-            equal(m.pollLastEntry(), e);
-            checkUnusedKey(m, e.getKey());}};
-        case 2: return new MapFrobber() {void frob(NavigableMap m) {
-            check(m.remove(k) != null);
-            checkUnusedKey(m, k);}};
-        case 3: return new MapFrobber() {void frob(NavigableMap m) {
-            m.subMap(k, true, k, true).clear();
-            checkUnusedKey(m, k);}};
-        case 4: return new MapFrobber() {void frob(NavigableMap m) {
-            m.descendingMap().subMap(k, true, k, true).clear();
-            checkUnusedKey(m, k);}};
-        case 5: return new MapFrobber() {void frob(NavigableMap m) {
-            final Iterator it = m.keySet().iterator();
-            while (it.hasNext())
-                if (it.next().equals(k)) {
-                    it.remove();
-                    if (maybe(2))
-                        THROWS(IllegalStateException.class,
-                               new Fun(){void f(){ it.remove(); }});
-                }
-            checkUnusedKey(m, k);}};
-        case 6: return new MapFrobber() {void frob(NavigableMap m) {
-            final Iterator<Map.Entry> it = m.entrySet().iterator();
-            while (it.hasNext())
-                if (it.next().getKey().equals(k)) {
-                    it.remove();
-                    if (maybe(2))
-                        THROWS(IllegalStateException.class, remover(it));
-                }
-            checkUnusedKey(m, k);}};
-        }
+        final MapFrobber[] randomRemovers = {
+            new MapFrobber() {void frob(NavigableMap m) {
+                Map.Entry e = m.firstEntry();
+                equal(m.pollFirstEntry(), e);
+                checkUnusedKey(m, e.getKey());}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                Map.Entry e = m.lastEntry();
+                equal(m.pollLastEntry(), e);
+                checkUnusedKey(m, e.getKey());}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                check(m.remove(k) != null);
+                checkUnusedKey(m, k);}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                m.subMap(k, true, k, true).clear();
+                checkUnusedKey(m, k);}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                m.descendingMap().subMap(k, true, k, true).clear();
+                checkUnusedKey(m, k);}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                final Iterator it = m.keySet().iterator();
+                while (it.hasNext())
+                    if (it.next().equals(k)) {
+                        it.remove();
+                        if (maybe(2))
+                            THROWS(IllegalStateException.class,
+                                   new Fun(){void f(){ it.remove(); }});
+                    }
+                checkUnusedKey(m, k);}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                final Iterator it = m.navigableKeySet().descendingIterator();
+                while (it.hasNext())
+                    if (it.next().equals(k)) {
+                        it.remove();
+                        if (maybe(2))
+                            THROWS(IllegalStateException.class,
+                                   new Fun(){void f(){ it.remove(); }});
+                    }
+                checkUnusedKey(m, k);}},
+            new MapFrobber() {void frob(NavigableMap m) {
+                final Iterator<Map.Entry> it = m.entrySet().iterator();
+                while (it.hasNext())
+                    if (it.next().getKey().equals(k)) {
+                        it.remove();
+                        if (maybe(2))
+                            THROWS(IllegalStateException.class, remover(it));
+                    }
+                checkUnusedKey(m, k);}},
+        };
+
+        return randomRemovers[rnd.nextInt(randomRemovers.length)];
     }

     static SetFrobber randomRemover(NavigableSet s) {
         final Integer e = usedElt(s);
-        switch (rnd.nextInt(7)) {
-        default: throw new Error();
-        case 0: return new SetFrobber() {void frob(NavigableSet s) {
-            Object e = s.first();
-            equal(s.pollFirst(), e);
-            checkUnusedElt(s, e);}};
-        case 1: return new SetFrobber() {void frob(NavigableSet s) {
-            Object e = s.last();
-            equal(s.pollLast(), e);
-            checkUnusedElt(s, e);}};
-        case 2: return new SetFrobber() {void frob(NavigableSet s) {
-            check(s.remove(e));
-            checkUnusedElt(s, e);}};
-        case 3: return new SetFrobber() {void frob(NavigableSet s) {
-            s.subSet(e, true, e, true).clear();
-            checkUnusedElt(s, e);}};
-        case 4: return new SetFrobber() {void frob(NavigableSet s) {
-            s.descendingSet().subSet(e, true, e, true).clear();
-            checkUnusedElt(s, e);}};
-        case 5: return new SetFrobber() {void frob(NavigableSet s) {
-            final Iterator it = s.iterator();
-            while (it.hasNext())
-                if (it.next().equals(e)) {
-                    it.remove();
-                    if (maybe(2))
-                        THROWS(IllegalStateException.class,
-                               new Fun(){void f(){ it.remove(); }});
-                }
-            checkUnusedElt(s, e);}};
-        case 6: return new SetFrobber() {void frob(NavigableSet s) {
-            final Iterator it = s.descendingSet().iterator();
-            while (it.hasNext())
-                if (it.next().equals(e)) {
-                    it.remove();
-                    if (maybe(2))
-                        THROWS(IllegalStateException.class,
-                               new Fun(){void f(){ it.remove(); }});
-                }
-            checkUnusedElt(s, e);}};
-        }
+
+        final SetFrobber[] randomRemovers = {
+            new SetFrobber() {void frob(NavigableSet s) {
+                Object e = s.first();
+                equal(s.pollFirst(), e);
+                checkUnusedElt(s, e);}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                Object e = s.last();
+                equal(s.pollLast(), e);
+                checkUnusedElt(s, e);}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                check(s.remove(e));
+                checkUnusedElt(s, e);}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                s.subSet(e, true, e, true).clear();
+                checkUnusedElt(s, e);}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                s.descendingSet().subSet(e, true, e, true).clear();
+                checkUnusedElt(s, e);}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                final Iterator it = s.iterator();
+                while (it.hasNext())
+                    if (it.next().equals(e)) {
+                        it.remove();
+                        if (maybe(2))
+                            THROWS(IllegalStateException.class,
+                                   new Fun(){void f(){ it.remove(); }});
+                    }
+                checkUnusedElt(s, e);}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                final Iterator it = s.descendingSet().iterator();
+                while (it.hasNext())
+                    if (it.next().equals(e)) {
+                        it.remove();
+                        if (maybe(2))
+                            THROWS(IllegalStateException.class,
+                                   new Fun(){void f(){ it.remove(); }});
+                    }
+                checkUnusedElt(s, e);}},
+            new SetFrobber() {void frob(NavigableSet s) {
+                final Iterator it = s.descendingIterator();
+                while (it.hasNext())
+                    if (it.next().equals(e)) {
+                        it.remove();
+                        if (maybe(2))
+                            THROWS(IllegalStateException.class,
+                                   new Fun(){void f(){ it.remove(); }});
+                    }
+                checkUnusedElt(s, e);}}
+        };
+
+        return randomRemovers[rnd.nextInt(randomRemovers.length)];
     }

     static void lockStep(NavigableMap m1,


Martin

On Sat, Apr 19, 2008 at 2:07 PM, charlie hunt <charlie.hunt at sun.com> wrote:
>
> Alan Bateman wrote:
>
> > Martin Buchholz wrote:
> >
> > > :
> > >
> > > 2. Bug creation from Charlie (or some other person empowered to do so)
> > > I suggest making this bug P2-S2.
> > >
> > > I will need the bug id and synopsis to create the proper mercurial
> comment.
> > >
> > >
> > I don't know if Charlie is online today, but as you seem to be ready to
> create the change-set, I've created java/classes_util bug:
> >
> >  6691185: (coll) TreeMap.navigableKeySet's descendingIterator method
> starts at first instead of last entry
> >
> > with a link to this thread. The synopsis can be changed if you want
> something different.
> >
> > -Alan.
> >
>
>  Alan, thanks for filing the bug.  One less item on my list of things to do.
> :-)
>
>  Fwiw, I've looked at Martin's proposed changes.  From the familiarity I've
> gotten with TreeMap over the past week or two, the changes look good to me.
>
>  charlie ...
>
>
>



More information about the core-libs-dev mailing list