OpenJDK / portola / portola
changeset 50238:45093fb73c6d
8202685: Optimize ArrayList subList replaceAll
Reviewed-by: martin, psandoz, igerasim, redestad, dholmes, smarks, jrose, plevart
author | dl |
---|---|
date | Tue, 22 May 2018 21:46:51 -0700 |
parents | 7b259287cdd2 |
children | 6b29ef846c5c |
files | src/java.base/share/classes/java/util/ArrayList.java test/jdk/java/util/concurrent/tck/Collection8Test.java |
diffstat | 2 files changed, 58 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java.base/share/classes/java/util/ArrayList.java Tue May 22 16:19:31 2018 -0700 +++ b/src/java.base/share/classes/java/util/ArrayList.java Tue May 22 21:46:51 2018 -0700 @@ -1221,6 +1221,10 @@ return true; } + public void replaceAll(UnaryOperator<E> operator) { + root.replaceAllRange(operator, offset, offset + size); + } + public boolean removeAll(Collection<?> c) { return batchRemove(c, false); } @@ -1724,15 +1728,18 @@ @Override public void replaceAll(UnaryOperator<E> operator) { + replaceAllRange(operator, 0, size); + modCount++; + } + + private void replaceAllRange(UnaryOperator<E> operator, int i, int end) { Objects.requireNonNull(operator); final int expectedModCount = modCount; final Object[] es = elementData; - final int size = this.size; - for (int i = 0; modCount == expectedModCount && i < size; i++) + for (; modCount == expectedModCount && i < end; i++) es[i] = operator.apply(elementAt(es, i)); if (modCount != expectedModCount) throw new ConcurrentModificationException(); - modCount++; } @Override
--- a/test/jdk/java/util/concurrent/tck/Collection8Test.java Tue May 22 16:19:31 2018 -0700 +++ b/test/jdk/java/util/concurrent/tck/Collection8Test.java Tue May 22 21:46:51 2018 -0700 @@ -616,15 +616,32 @@ public void testRemoveAfterForEachRemaining() { Collection c = impl.emptyCollection(); ThreadLocalRandom rnd = ThreadLocalRandom.current(); + ArrayList copy = new ArrayList(); + boolean ordered = c.spliterator().hasCharacteristics(Spliterator.ORDERED); testCollection: { int n = 3 + rnd.nextInt(2); - for (int i = 0; i < n; i++) c.add(impl.makeElement(i)); + for (int i = 0; i < n; i++) { + Object x = impl.makeElement(i); + c.add(x); + copy.add(x); + } Iterator it = c.iterator(); - assertTrue(it.hasNext()); - assertEquals(impl.makeElement(0), it.next()); - assertTrue(it.hasNext()); - assertEquals(impl.makeElement(1), it.next()); - it.forEachRemaining(e -> assertTrue(c.contains(e))); + if (ordered) { + if (rnd.nextBoolean()) assertTrue(it.hasNext()); + assertEquals(impl.makeElement(0), it.next()); + if (rnd.nextBoolean()) assertTrue(it.hasNext()); + assertEquals(impl.makeElement(1), it.next()); + } else { + if (rnd.nextBoolean()) assertTrue(it.hasNext()); + assertTrue(copy.contains(it.next())); + if (rnd.nextBoolean()) assertTrue(it.hasNext()); + assertTrue(copy.contains(it.next())); + } + if (rnd.nextBoolean()) assertTrue(it.hasNext()); + it.forEachRemaining( + e -> { + assertTrue(c.contains(e)); + assertTrue(copy.contains(e));}); if (testImplementationDetails) { if (c instanceof java.util.concurrent.ArrayBlockingQueue) { assertIteratorExhausted(it); @@ -634,14 +651,17 @@ break testCollection; } assertEquals(n - 1, c.size()); - for (int i = 0; i < n - 1; i++) - assertTrue(c.contains(impl.makeElement(i))); - assertFalse(c.contains(impl.makeElement(n - 1))); + if (ordered) { + for (int i = 0; i < n - 1; i++) + assertTrue(c.contains(impl.makeElement(i))); + assertFalse(c.contains(impl.makeElement(n - 1))); + } } } } if (c instanceof Deque) { Deque d = (Deque) impl.emptyCollection(); + assertTrue(ordered); int n = 3 + rnd.nextInt(2); for (int i = 0; i < n; i++) d.add(impl.makeElement(i)); Iterator it = d.descendingIterator(); @@ -959,6 +979,25 @@ } catch (java.io.NotSerializableException acceptable) {} } + public void DISABLED_testReplaceAllIsNotStructuralModification() { + Collection c = impl.emptyCollection(); + if (!(c instanceof List)) + return; + List list = (List) c; + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + for (int n = rnd.nextInt(2, 10); n--> 0; ) + list.add(impl.makeElement(rnd.nextInt())); + ArrayList copy = new ArrayList(list); + int size = list.size(), half = size / 2; + Iterator it = list.iterator(); + for (int i = 0; i < half; i++) + assertEquals(it.next(), copy.get(i)); + list.replaceAll(n -> n); + // ConcurrentModificationException must not be thrown here. + for (int i = half; i < size; i++) + assertEquals(it.next(), copy.get(i)); + } + // public void testCollection8DebugFail() { // fail(impl.klazz().getSimpleName()); // }