undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,261 @@
/*
* Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6415641 6377302
* @summary Concurrent collections are permitted to lie about their size
* @author Martin Buchholz
*/
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
@SuppressWarnings("unchecked")
public class BiggernYours {
static final Random rnd = new Random(18675309);
static void compareCollections(Collection c1, Collection c2) {
Object[] c1Array = c1.toArray();
Object[] c2Array = c2.toArray();
check(c1Array.length == c2Array.length);
for (Object aC1 : c1Array) {
boolean found = false;
for (Object aC2 : c2Array) {
if (Objects.equals(aC1, aC2)) {
found = true;
break;
}
}
if (!found)
fail(aC1 + " not found in " + Arrays.toString(c2Array));
}
}
static void compareMaps(Map m1, Map m2) {
compareCollections(m1.keySet(),
m2.keySet());
compareCollections(m1.values(),
m2.values());
compareCollections(m1.entrySet(),
m2.entrySet());
}
static void compareNavigableMaps(NavigableMap m1, NavigableMap m2) {
compareMaps(m1, m2);
compareMaps(m1.descendingMap(),
m2.descendingMap());
compareMaps(m1.tailMap(Integer.MIN_VALUE),
m2.tailMap(Integer.MIN_VALUE));
compareMaps(m1.headMap(Integer.MAX_VALUE),
m2.headMap(Integer.MAX_VALUE));
}
static void compareNavigableSets(NavigableSet s1, NavigableSet s2) {
compareCollections(s1, s2);
compareCollections(s1.descendingSet(),
s2.descendingSet());
compareCollections(s1.tailSet(Integer.MIN_VALUE),
s2.tailSet(Integer.MIN_VALUE));
}
abstract static class MapFrobber { abstract void frob(Map m); }
abstract static class SetFrobber { abstract void frob(Set s); }
abstract static class ColFrobber { abstract void frob(Collection c); }
static ColFrobber adder(final int i) {
return new ColFrobber() {void frob(Collection c) { c.add(i); }};
}
static final ColFrobber[] adders =
{ adder(1), adder(3), adder(2) };
static MapFrobber putter(final int k, final int v) {
return new MapFrobber() {void frob(Map m) { m.put(k,v); }};
}
static final MapFrobber[] putters =
{ putter(1, -2), putter(3, -6), putter(2, -4) };
static void unexpected(Throwable t, Object suspect) {
System.out.println(suspect.getClass());
unexpected(t);
}
static void testCollections(Collection c1, Collection c2) {
try {
compareCollections(c1, c2);
for (ColFrobber adder : adders) {
for (Collection c : new Collection[]{c1, c2})
adder.frob(c);
compareCollections(c1, c2);
}
} catch (Throwable t) { unexpected(t, c1); }
}
static void testNavigableSets(NavigableSet s1, NavigableSet s2) {
try {
compareNavigableSets(s1, s2);
for (ColFrobber adder : adders) {
for (Set s : new Set[]{s1, s2})
adder.frob(s);
compareNavigableSets(s1, s2);
}
} catch (Throwable t) { unexpected(t, s1); }
}
static void testMaps(Map m1, Map m2) {
try {
compareMaps(m1, m2);
for (MapFrobber putter : putters) {
for (Map m : new Map[]{m1, m2})
putter.frob(m);
compareMaps(m1, m2);
}
} catch (Throwable t) { unexpected(t, m1); }
}
static void testNavigableMaps(NavigableMap m1, NavigableMap m2) {
try {
compareNavigableMaps(m1, m2);
for (MapFrobber putter : putters) {
for (Map m : new Map[]{m1, m2})
putter.frob(m);
compareNavigableMaps(m1, m2);
}
} catch (Throwable t) { unexpected(t, m1); }
}
static int randomize(int size) { return rnd.nextInt(size + 2); }
@SuppressWarnings("serial")
private static void realMain(String[] args) {
testNavigableMaps(
new ConcurrentSkipListMap(),
new ConcurrentSkipListMap() {
public int size() {return randomize(super.size());}});
testNavigableSets(
new ConcurrentSkipListSet(),
new ConcurrentSkipListSet() {
public int size() {return randomize(super.size());}});
testCollections(
new CopyOnWriteArraySet(),
new CopyOnWriteArraySet() {
public int size() {return randomize(super.size());}});
testCollections(
new CopyOnWriteArrayList(),
new CopyOnWriteArrayList() {
public int size() {return randomize(super.size());}});
testCollections(
new TreeSet(),
new TreeSet() {
public int size() {return randomize(super.size());}});
testMaps(
new ConcurrentHashMap(),
new ConcurrentHashMap() {
public int size() {return randomize(super.size());}});
testCollections(
new ConcurrentLinkedDeque(),
new ConcurrentLinkedDeque() {
public int size() {return randomize(super.size());}});
testCollections(
new ConcurrentLinkedQueue(),
new ConcurrentLinkedQueue() {
public int size() {return randomize(super.size());}});
testCollections(
new LinkedTransferQueue(),
new LinkedTransferQueue() {
public int size() {return randomize(super.size());}});
testCollections(
new LinkedBlockingQueue(),
new LinkedBlockingQueue() {
public int size() {return randomize(super.size());}});
testCollections(
new LinkedBlockingDeque(),
new LinkedBlockingDeque() {
public int size() {return randomize(super.size());}});
testCollections(
new ArrayBlockingQueue(5),
new ArrayBlockingQueue(5) {
public int size() {return randomize(super.size());}});
testCollections(
new PriorityBlockingQueue(5),
new PriorityBlockingQueue(5) {
public int size() {return randomize(super.size());}});
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
static void arrayEqual(Object[] x, Object[] y) {
if (x == null ? y == null : Arrays.equals(x, y)) pass();
else fail(Arrays.toString(x) + " not equal to " + Arrays.toString(y));}
public static void main(String[] args) {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
private abstract static class CheckedThread extends Thread {
abstract void realRun() throws Throwable;
public void run() {
try {realRun();} catch (Throwable t) {unexpected(t);}}}
}

View file

@ -0,0 +1,195 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* @test
* @summary Unit tests for extension methods on Collection
* @library testlibrary
* @build CollectionAsserts CollectionSupplier ExtendsAbstractSet ExtendsAbstractCollection
* @run testng CollectionDefaults
*/
public class CollectionDefaults {
public static final Predicate<Integer> pEven = x -> 0 == x % 2;
public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
private static final int SIZE = 100;
private static final List<Function<Collection<Integer>, Collection<Integer>>> TEST_SUPPLIERS = Arrays.asList(
// Collection
ExtendsAbstractCollection<Integer>::new,
java.util.ArrayDeque<Integer>::new,
java.util.concurrent.ConcurrentLinkedDeque<Integer>::new,
java.util.concurrent.ConcurrentLinkedQueue<Integer>::new,
java.util.concurrent.LinkedBlockingDeque<Integer>::new,
java.util.concurrent.LinkedBlockingQueue<Integer>::new,
java.util.concurrent.LinkedTransferQueue<Integer>::new,
(coll) -> new java.util.concurrent.ArrayBlockingQueue<Integer>(
3 * SIZE, false, coll),
// Lists
java.util.ArrayList<Integer>::new,
java.util.LinkedList<Integer>::new,
java.util.Vector<Integer>::new,
java.util.concurrent.CopyOnWriteArrayList<Integer>::new,
ExtendsAbstractList<Integer>::new,
// Sets
java.util.HashSet<Integer>::new,
java.util.LinkedHashSet<Integer>::new,
java.util.TreeSet<Integer>::new,
java.util.concurrent.ConcurrentSkipListSet<Integer>::new,
java.util.concurrent.CopyOnWriteArraySet<Integer>::new,
ExtendsAbstractSet<Integer>::new
);
@DataProvider(name="setProvider", parallel=true)
public static Iterator<Object[]> setCases() {
final List<Object[]> cases = new LinkedList<>();
cases.add(new Object[] { new HashSet<>() });
cases.add(new Object[] { new LinkedHashSet<>() });
cases.add(new Object[] { new TreeSet<>() });
cases.add(new Object[] { new java.util.concurrent.ConcurrentSkipListSet<>() });
cases.add(new Object[] { new java.util.concurrent.CopyOnWriteArraySet<>() });
cases.add(new Object[] { new ExtendsAbstractSet<>() });
cases.add(new Object[] { Collections.newSetFromMap(new HashMap<>()) });
cases.add(new Object[] { Collections.newSetFromMap(new LinkedHashMap<>()) });
cases.add(new Object[] { Collections.newSetFromMap(new TreeMap<>()) });
cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentHashMap<>()) });
cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentSkipListMap<>()) });
cases.add(new Object[] { new HashSet<Integer>(){{add(42);}} });
cases.add(new Object[] { new ExtendsAbstractSet<Integer>(){{add(42);}} });
cases.add(new Object[] { new LinkedHashSet<Integer>(){{add(42);}} });
cases.add(new Object[] { new TreeSet<Integer>(){{add(42);}} });
return cases.iterator();
}
@Test(dataProvider = "setProvider")
public void testProvidedWithNull(final Set<Integer> set) {
try {
set.forEach(null);
fail("expected NPE not thrown");
} catch (NullPointerException expected) { // expected
}
try {
set.removeIf(null);
fail("expected NPE not thrown");
} catch (NullPointerException expected) { // expected
}
}
@Test
public void testForEach() {
@SuppressWarnings("unchecked")
final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier(TEST_SUPPLIERS, SIZE);
for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
final Collection<Integer> original = test.expected;
final Collection<Integer> set = test.collection;
try {
set.forEach(null);
fail("expected NPE not thrown");
} catch (NullPointerException expected) { // expected
}
if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
CollectionAsserts.assertContentsUnordered(set, original, test.toString());
} else {
CollectionAsserts.assertContents(set, original, test.toString());
}
final List<Integer> actual = new LinkedList<>();
set.forEach(actual::add);
if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
CollectionAsserts.assertContentsUnordered(actual, set, test.toString());
CollectionAsserts.assertContentsUnordered(actual, original, test.toString());
} else {
CollectionAsserts.assertContents(actual, set, test.toString());
CollectionAsserts.assertContents(actual, original, test.toString());
}
}
}
@Test
public void testRemoveIf() {
@SuppressWarnings("unchecked")
final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier(TEST_SUPPLIERS, SIZE);
for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
final Collection<Integer> original = test.expected;
final Collection<Integer> set = test.collection;
try {
set.removeIf(null);
fail("expected NPE not thrown");
} catch (NullPointerException expected) { // expected
}
if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
CollectionAsserts.assertContentsUnordered(set, original, test.toString());
} else {
CollectionAsserts.assertContents(set, original, test.toString());
}
set.removeIf(pEven);
for (int i : set) {
assertTrue((i % 2) == 1);
}
for (int i : original) {
if (i % 2 == 1) {
assertTrue(set.contains(i));
}
}
set.removeIf(pOdd);
assertTrue(set.isEmpty());
}
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6355660 6347106 6394004
* @summary methods taking concurrently mutating collection should work
* @author Martin Buchholz
*/
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.PriorityBlockingQueue;
@SuppressWarnings("unchecked")
public class HotPotatoes {
private static void realMain(String[] args) throws Throwable {
testImplementation(Vector.class);
testImplementation(ArrayList.class);
testImplementation(PriorityQueue.class);
testImplementation(PriorityBlockingQueue.class);
}
private static void testImplementation(Class<? extends Collection> implClazz)
throws Throwable
{
testPotato(implClazz, Vector.class);
testPotato(implClazz, CopyOnWriteArrayList.class);
final Constructor<? extends Collection> constr
= implClazz.getConstructor(Collection.class);
final Collection<Object> coll
= constr.newInstance(Arrays.asList(new String[] {}));
coll.add(1);
equal(coll.toString(), "[1]");
}
private static void testPotato(Class<? extends Collection> implClazz,
Class<? extends List> argClazz)
throws Throwable
{
try {
System.out.printf("implClazz=%s, argClazz=%s\n",
implClazz.getName(), argClazz.getName());
final int iterations = 100000;
final List<Integer> list = (List<Integer>)
argClazz.getDeclaredConstructor().newInstance();
final Integer one = Integer.valueOf(1);
final List<Integer> oneElementList = Collections.singletonList(one);
final Constructor<? extends Collection> constr
= implClazz.getConstructor(Collection.class);
final Thread t = new CheckedThread() { public void realRun() {
for (int i = 0; i < iterations; i++) {
list.add(one);
list.remove(one);
}}};
t.setDaemon(true);
t.start();
for (int i = 0; i < iterations; i++) {
Collection<?> coll = constr.newInstance(list);
Object[] elts = coll.toArray();
check(elts.length == 0 ||
(elts.length == 1 && elts[0] == one));
}
} catch (Throwable t) { unexpected(t); }
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
private abstract static class CheckedThread extends Thread {
public abstract void realRun() throws Throwable;
public void run() {
try { realRun(); } catch (Throwable t) { unexpected(t); }}}
}

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6529795
* @summary next() does not change iterator state if throws NoSuchElementException
* @author Martin Buchholz
*/
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.PriorityQueue;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import java.util.WeakHashMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
@SuppressWarnings("unchecked")
public class IteratorAtEnd {
private static final int SIZE = 6;
static void realMain(String[] args) throws Throwable {
testCollection(new ArrayList());
testCollection(new Vector());
testCollection(new LinkedList());
testCollection(new ArrayDeque());
testCollection(new TreeSet());
testCollection(new CopyOnWriteArrayList());
testCollection(new CopyOnWriteArraySet());
testCollection(new ConcurrentSkipListSet());
testCollection(new PriorityQueue());
testCollection(new LinkedBlockingQueue());
testCollection(new ArrayBlockingQueue(100));
testCollection(new ConcurrentLinkedDeque());
testCollection(new ConcurrentLinkedQueue());
testCollection(new LinkedTransferQueue());
testMap(new HashMap());
testMap(new Hashtable());
testMap(new LinkedHashMap());
testMap(new WeakHashMap());
testMap(new IdentityHashMap());
testMap(new ConcurrentHashMap());
testMap(new ConcurrentSkipListMap());
testMap(new TreeMap());
}
static void testCollection(Collection c) {
try {
for (int i = 0; i < SIZE; i++)
c.add(i);
test(c);
} catch (Throwable t) { unexpected(t); }
}
static void testMap(Map m) {
try {
for (int i = 0; i < 3*SIZE; i++)
m.put(i, i);
test(m.values());
test(m.keySet());
test(m.entrySet());
} catch (Throwable t) { unexpected(t); }
}
static void test(Collection c) {
try {
final Iterator it = c.iterator();
THROWS(NoSuchElementException.class,
() -> { while (true) it.next(); });
try { it.remove(); }
catch (UnsupportedOperationException exc) { return; }
pass();
} catch (Throwable t) { unexpected(t); }
if (c instanceof List) {
final List list = (List) c;
try {
final ListIterator it = list.listIterator(0);
it.next();
final Object x = it.previous();
THROWS(NoSuchElementException.class, () -> it.previous());
try { it.remove(); }
catch (UnsupportedOperationException exc) { return; }
pass();
check(! list.get(0).equals(x));
} catch (Throwable t) { unexpected(t); }
try {
final ListIterator it = list.listIterator(list.size());
it.previous();
final Object x = it.next();
THROWS(NoSuchElementException.class, () -> it.next());
try { it.remove(); }
catch (UnsupportedOperationException exc) { return; }
pass();
check(! list.get(list.size()-1).equals(x));
} catch (Throwable t) { unexpected(t); }
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
interface Fun {void f() throws Throwable;}
static void THROWS(Class<? extends Throwable> k, Fun... fs) {
for (Fun f : fs)
try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,628 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary micro-benchmark correctness mode
* @run main IteratorMicroBenchmark iterations=1 size=8 warmup=0
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.stream.Collectors.summingInt;
import static java.util.stream.Collectors.toCollection;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.PriorityQueue;
import java.util.Spliterator;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/**
* Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
*
* To run this in micro-benchmark mode, simply run as a normal java program.
* Be patient; this program runs for a very long time.
* For faster runs, restrict execution using command line args.
*
* @author Martin Buchholz
*/
public class IteratorMicroBenchmark {
abstract static class Job {
private final String name;
public Job(String name) { this.name = name; }
public String name() { return name; }
public abstract void work() throws Throwable;
public void run() {
try { work(); }
catch (Throwable ex) {
// current job cannot always be deduced from stacktrace.
throw new RuntimeException("Job failed: " + name(), ex);
}
}
}
final int iterations;
final int size; // number of elements in collections
final double warmupSeconds;
final long warmupNanos;
final Pattern nameFilter; // select subset of Jobs to run
final boolean reverse; // reverse order of Jobs
final boolean shuffle; // randomize order of Jobs
IteratorMicroBenchmark(String[] args) {
iterations = intArg(args, "iterations", 10_000);
size = intArg(args, "size", 1000);
warmupSeconds = doubleArg(args, "warmup", 7.0);
nameFilter = patternArg(args, "filter");
reverse = booleanArg(args, "reverse");
shuffle = booleanArg(args, "shuffle");
warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
}
// --------------- GC finalization infrastructure ---------------
/** No guarantees, but effective in practice. */
static void forceFullGc() {
long timeoutMillis = 1000L;
CountDownLatch finalized = new CountDownLatch(1);
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> ref = new WeakReference<>(
new Object() {
@SuppressWarnings("deprecation")
protected void finalize() { finalized.countDown(); }},
queue);
try {
for (int tries = 3; tries--> 0; ) {
System.gc();
if (finalized.await(timeoutMillis, MILLISECONDS)
&& queue.remove(timeoutMillis) != null
&& ref.get() == null) {
System.runFinalization(); // try to pick up stragglers
return;
}
timeoutMillis *= 4;
}
} catch (InterruptedException unexpected) {
throw new AssertionError("unexpected InterruptedException");
}
throw new AssertionError("failed to do a \"full\" gc");
}
/**
* Runs each job for long enough that all the runtime compilers
* have had plenty of time to warm up, i.e. get around to
* compiling everything worth compiling.
* Returns array of average times per job per run.
*/
long[] time0(List<Job> jobs) {
final int size = jobs.size();
long[] nanoss = new long[size];
for (int i = 0; i < size; i++) {
if (warmupNanos > 0) forceFullGc();
Job job = jobs.get(i);
long totalTime;
int runs = 0;
long startTime = System.nanoTime();
do { job.run(); runs++; }
while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
nanoss[i] = totalTime/runs;
}
return nanoss;
}
void time(List<Job> jobs) throws Throwable {
if (warmupNanos > 0) time0(jobs); // Warm up run
final int size = jobs.size();
final long[] nanoss = time0(jobs); // Real timing run
final long[] milliss = new long[size];
final double[] ratios = new double[size];
final String nameHeader = "Method";
final String millisHeader = "Millis";
final String ratioHeader = "Ratio";
int nameWidth = nameHeader.length();
int millisWidth = millisHeader.length();
int ratioWidth = ratioHeader.length();
for (int i = 0; i < size; i++) {
nameWidth = Math.max(nameWidth, jobs.get(i).name().length());
milliss[i] = nanoss[i]/(1000L * 1000L);
millisWidth = Math.max(millisWidth,
String.format("%d", milliss[i]).length());
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
ratioWidth = Math.max(ratioWidth,
String.format("%.3f", ratios[i]).length());
}
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
nameWidth, millisWidth, ratioWidth);
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
nameWidth, millisWidth, ratioWidth);
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
// Print out absolute and relative times, calibrated against first job
for (int i = 0; i < size; i++)
System.out.printf(format, jobs.get(i).name(), milliss[i], ratios[i]);
}
private static String keywordValue(String[] args, String keyword) {
for (String arg : args)
if (arg.startsWith(keyword))
return arg.substring(keyword.length() + 1);
return null;
}
private static int intArg(String[] args, String keyword, int defaultValue) {
String val = keywordValue(args, keyword);
return (val == null) ? defaultValue : Integer.parseInt(val);
}
private static double doubleArg(String[] args, String keyword, double defaultValue) {
String val = keywordValue(args, keyword);
return (val == null) ? defaultValue : Double.parseDouble(val);
}
private static Pattern patternArg(String[] args, String keyword) {
String val = keywordValue(args, keyword);
return (val == null) ? null : Pattern.compile(val);
}
private static boolean booleanArg(String[] args, String keyword) {
String val = keywordValue(args, keyword);
if (val == null || val.equals("false")) return false;
if (val.equals("true")) return true;
throw new IllegalArgumentException(val);
}
private static void deoptimize(int sum) {
if (sum == 42)
System.out.println("the answer");
}
private static <T> Iterable<T> backwards(final List<T> list) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return new Iterator<T>() {
final ListIterator<T> it = list.listIterator(list.size());
public boolean hasNext() { return it.hasPrevious(); }
public T next() { return it.previous(); }
public void remove() { it.remove(); }};}};
}
// Checks for correctness *and* prevents loop optimizations
static class Check {
private int sum;
public void sum(int sum) {
if (this.sum == 0)
this.sum = sum;
if (this.sum != sum)
throw new AssertionError("Sum mismatch");
}
}
volatile Check check = new Check();
public static void main(String[] args) throws Throwable {
new IteratorMicroBenchmark(args).run();
}
HashMap<Class<?>, String> goodClassName = new HashMap<>();
String goodClassName(Class<?> klazz) {
return goodClassName.computeIfAbsent(
klazz,
k -> {
String simple = k.getSimpleName();
return (simple.equals("SubList")) // too simple!
? k.getName().replaceFirst(".*\\.", "")
: simple;
});
}
String goodClassName(Object x) {
return goodClassName(x.getClass());
}
static List<Integer> makeSubList(
List<Integer> elements,
UnaryOperator<List<Integer>> copyConstructor) {
final ArrayList<Integer> padded = new ArrayList<>();
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final int frontPorch = rnd.nextInt(3);
final int backPorch = rnd.nextInt(3);
for (int n = frontPorch; n--> 0; ) padded.add(rnd.nextInt());
padded.addAll(elements);
for (int n = backPorch; n--> 0; ) padded.add(rnd.nextInt());
return copyConstructor.apply(padded)
.subList(frontPorch, frontPorch + elements.size());
}
void run() throws Throwable {
final ArrayList<Integer> al = new ArrayList<>(size);
// Populate collections with random data
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
for (int i = 0; i < size; i++)
al.add(rnd.nextInt(size));
final ArrayDeque<Integer> ad = new ArrayDeque<>(al);
final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<>(al.size());
abq.addAll(al);
// shuffle circular array elements so they wrap
for (int i = 0, n = rnd.nextInt(size); i < n; i++) {
ad.addLast(ad.removeFirst());
abq.add(abq.remove());
}
final Integer[] array = al.toArray(new Integer[0]);
final List<Integer> immutableSubList
= makeSubList(al, x -> List.of(x.toArray(new Integer[0])));
Stream<Collection<Integer>> collections = concatStreams(
Stream.of(
// Lists and their subLists
al,
makeSubList(al, ArrayList::new),
new Vector<>(al),
makeSubList(al, Vector::new),
new LinkedList<>(al),
makeSubList(al, LinkedList::new),
new CopyOnWriteArrayList<>(al),
makeSubList(al, CopyOnWriteArrayList::new),
ad,
new PriorityQueue<>(al),
new ConcurrentLinkedQueue<>(al),
new ConcurrentLinkedDeque<>(al),
// Blocking Queues
abq,
new LinkedBlockingQueue<>(al),
new LinkedBlockingDeque<>(al),
new LinkedTransferQueue<>(al),
new PriorityBlockingQueue<>(al),
List.of(al.toArray(new Integer[0]))),
// avoid UnsupportedOperationException in jdk9 and jdk10
(goodClassName(immutableSubList).equals("RandomAccessSubList"))
? Stream.empty()
: Stream.of(immutableSubList));
ArrayList<Job> jobs = collections
.flatMap(x -> jobs(x))
.filter(job ->
nameFilter == null || nameFilter.matcher(job.name()).find())
.collect(toCollection(ArrayList::new));
if (reverse) Collections.reverse(jobs);
if (shuffle) Collections.shuffle(jobs);
time(jobs);
}
@SafeVarargs @SuppressWarnings("varargs")
private static <T> Stream<T> concatStreams(Stream<T> ... streams) {
return Stream.of(streams).flatMap(s -> s);
}
boolean isMutable(Collection<Integer> x) {
return !(x.getClass().getName().contains("ImmutableCollections$"));
}
Stream<Job> jobs(Collection<Integer> x) {
return concatStreams(
collectionJobs(x),
(isMutable(x))
? mutableCollectionJobs(x)
: Stream.empty(),
(x instanceof Deque)
? dequeJobs((Deque<Integer>)x)
: Stream.empty(),
(x instanceof List)
? listJobs((List<Integer>)x)
: Stream.empty(),
(x instanceof List && isMutable(x))
? mutableListJobs((List<Integer>)x)
: Stream.empty());
}
Object sneakyAdder(int[] sneakySum) {
return new Object() {
public int hashCode() { throw new AssertionError(); }
public boolean equals(Object z) {
sneakySum[0] += (int) z; return false; }};
}
Stream<Job> collectionJobs(Collection<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : x)
sum += n;
check.sum(sum);}}},
new Job(klazz + " iterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.iterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job(klazz + " spliterator().tryAdvance()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
Spliterator<Integer> spliterator = x.spliterator();
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
check.sum(sum[0]);}}},
new Job(klazz + " spliterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.spliterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job(klazz + " contains") {
public void work() throws Throwable {
int[] sum = new int[1];
Object sneakyAdder = sneakyAdder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
if (x.contains(sneakyAdder)) throw new AssertionError();
check.sum(sum[0]);}}},
new Job(klazz + " containsAll") {
public void work() throws Throwable {
int[] sum = new int[1];
Collection<Object> sneakyAdderCollection =
Collections.singleton(sneakyAdder(sum));
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
if (x.containsAll(sneakyAdderCollection))
throw new AssertionError();
check.sum(sum[0]);}}},
new Job(klazz + " forEach") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.forEach(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job(klazz + " toArray()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Object o : x.toArray())
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job(klazz + " toArray(a)") {
public void work() throws Throwable {
Integer[] a = new Integer[x.size()];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.toArray(a);
for (Object o : a)
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job(klazz + " toArray(empty)") {
public void work() throws Throwable {
Integer[] empty = new Integer[0];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Integer o : x.toArray(empty))
sum[0] += o;
check.sum(sum[0]);}}},
new Job(klazz + " stream().forEach") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.stream().forEach(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job(klazz + " stream().mapToInt") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
check.sum(x.stream().mapToInt(e -> e).sum());}}},
new Job(klazz + " stream().collect") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
check.sum(x.stream()
.collect(summingInt(e -> e)));}}},
new Job(klazz + " stream()::iterator") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Integer o : (Iterable<Integer>) x.stream()::iterator)
sum[0] += o;
check.sum(sum[0]);}}},
new Job(klazz + " parallelStream().forEach") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
LongAdder sum = new LongAdder();
x.parallelStream().forEach(n -> sum.add(n));
check.sum((int) sum.sum());}}},
new Job(klazz + " parallelStream().mapToInt") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
check.sum(x.parallelStream().mapToInt(e -> e).sum());}}},
new Job(klazz + " parallelStream().collect") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
check.sum(x.parallelStream()
.collect(summingInt(e -> e)));}}},
new Job(klazz + " parallelStream()::iterator") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Integer o : (Iterable<Integer>) x.parallelStream()::iterator)
sum[0] += o;
check.sum(sum[0]);}}});
}
Stream<Job> mutableCollectionJobs(Collection<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
if (x.removeIf(n -> { sum[0] += n; return false; }))
throw new AssertionError();
check.sum(sum[0]);}}},
new Job(klazz + " remove(Object)") {
public void work() throws Throwable {
int[] sum = new int[1];
Object sneakyAdder = sneakyAdder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
if (x.remove(sneakyAdder)) throw new AssertionError();
check.sum(sum[0]);}}});
}
Stream<Job> dequeJobs(Deque<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " descendingIterator() loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
Iterator<Integer> it = x.descendingIterator();
while (it.hasNext())
sum += it.next();
check.sum(sum);}}},
new Job(klazz + " descendingIterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.descendingIterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}});
}
Stream<Job> listJobs(List<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " listIterator forward loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
ListIterator<Integer> it = x.listIterator();
while (it.hasNext())
sum += it.next();
check.sum(sum);}}},
new Job(klazz + " listIterator backward loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
ListIterator<Integer> it = x.listIterator(x.size());
while (it.hasPrevious())
sum += it.previous();
check.sum(sum);}}},
new Job(klazz + " indexOf") {
public void work() throws Throwable {
int[] sum = new int[1];
Object sneakyAdder = sneakyAdder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
if (x.indexOf(sneakyAdder) != -1)
throw new AssertionError();
check.sum(sum[0]);}}},
new Job(klazz + " lastIndexOf") {
public void work() throws Throwable {
int[] sum = new int[1];
Object sneakyAdder = sneakyAdder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
if (x.lastIndexOf(sneakyAdder) != -1)
throw new AssertionError();
check.sum(sum[0]);}}},
new Job(klazz + " equals") {
public void work() throws Throwable {
ArrayList<Integer> copy = new ArrayList<>(x);
for (int i = 0; i < iterations; i++) {
if (!x.equals(copy))
throw new AssertionError();}}},
new Job(klazz + " hashCode") {
public void work() throws Throwable {
int hashCode = Arrays.hashCode(x.toArray());
for (int i = 0; i < iterations; i++) {
if (x.hashCode() != hashCode)
throw new AssertionError();}}});
}
Stream<Job> mutableListJobs(List<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " replaceAll") {
public void work() throws Throwable {
int[] sum = new int[1];
UnaryOperator<Integer> sneakyAdder =
x -> { sum[0] += x; return x; };
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.replaceAll(sneakyAdder);
check.sum(sum[0]);}}});
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,206 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8201518
* @key randomness
* @summary Ensure that randomized iteration order of unmodifiable sets
* and maps is actually randomized. Must be run othervm so that
* the per-VM-instance salt value differs.
* @run main/othervm RandomizedIteration 0
* @run main/othervm RandomizedIteration 1
* @run main/othervm RandomizedIteration 2
* @run main/othervm RandomizedIteration 3
* @run main/othervm RandomizedIteration 4
* @run main/othervm RandomizedIteration verify 5
*/
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static java.util.stream.Collectors.toUnmodifiableMap;
/**
* Test of randomized iteration of unmodifiable sets and maps.
*
* Usage: RandomizedIteration n
* - writes files suffixed with 'n' containing set elements and map keys
* in iteration order
* RandomizedIteration "verify" count
* - reads files 0..count-1 and checks to ensure that their orders differ
*
* The idea is to generate several test files by invoking this test with an arg
* of 0 through count-1. Then invoke the test once more with two args, the first being
* the word "verify" and the second arg being the count. This will read all the generated
* files and perform verification.
*
* The test is considered to pass if any of the runs result in different iteration
* orders. The randomization is not actually very random, so over many runs there is
* the possibility of a couple of the test files having the same order. That's ok, as
* long as the iteration order is usually different. The test fails if *all* of the
* iteration orders are the same.
*/
public class RandomizedIteration {
/**
* Generates a set and a map from the word array, and then writes
* text files "set.#" and "map.#" containing the set elements and
* map keys in iteration order.
*
* @param suffix number used for the file suffix
*/
static void writeFiles(int suffix) throws IOException {
try (PrintStream setOut = new PrintStream("set." + suffix)) {
Set.of(WORDS)
.forEach(setOut::println);
}
try (PrintStream mapOut = new PrintStream("map." + suffix)) {
var map = Map.ofEntries(Arrays.stream(WORDS)
.map(word -> Map.entry(word, ""))
.toArray(Map.Entry<?, ?>[]::new));
map.keySet()
.forEach(mapOut::println);
}
}
/**
* Reads lines from each file derived from the prefix and index from 0..count-1
* into a list, computes its hashcode, and returns a set of those hashcodes.
* The hashcode of the list is order sensitive, so the same lines in a different
* order should have different hashcodes.
*
* @param prefix the file prefix
* @param count the number of files to read
* @return a set of hashcodes of each file
*/
static Set<Integer> readFiles(String prefix, int count) throws IOException {
Set<Integer> hashes = new HashSet<>();
for (int suffix = 0; suffix < count; suffix++) {
String name = prefix + suffix;
int hash = Files.readAllLines(Paths.get(name)).hashCode();
System.out.println(name + ": " + hash);
hashes.add(hash);
}
return hashes;
}
/**
* Test main routine.
*
* @param args n | "verify" count
* @throws IOException if an error occurred
*/
public static void main(String[] args) throws IOException {
if ("verify".equals(args[0])) {
int count = Integer.parseInt(args[1]);
System.out.println("Verifying " + count + " files.");
Set<Integer> setHashes = readFiles("set.", count);
Set<Integer> mapHashes = readFiles("map.", count);
if (setHashes.size() > 1 && mapHashes.size() > 1) {
System.out.println("Passed: differing iteration orders were detected.");
} else {
throw new AssertionError("FAILED: iteration order not randomized!");
}
} else {
int suffix = Integer.parseInt(args[0]);
System.out.println("Generating files: " + suffix);
writeFiles(suffix);
}
}
/**
* List of 63 words of 22 or more letters from BSD /usr/share/dict/words.
*/
static final String[] WORDS = {
"anatomicophysiological",
"anthropomorphologically",
"aquopentamminecobaltic",
"blepharoconjunctivitis",
"blepharosphincterectomy",
"cholecystenterorrhaphy",
"cholecystoduodenostomy",
"choledochoduodenostomy",
"counterexcommunication",
"dacryocystoblennorrhea",
"dacryocystosyringotomy",
"deanthropomorphization",
"duodenocholecystostomy",
"electroencephalography",
"electrotelethermometer",
"epididymodeferentectomy",
"formaldehydesulphoxylate",
"formaldehydesulphoxylic",
"gastroenteroanastomosis",
"hematospectrophotometer",
"hexamethylenetetramine",
"hexanitrodiphenylamine",
"historicocabbalistical",
"hydropneumopericardium",
"hyperconscientiousness",
"laparocolpohysterotomy",
"lymphangioendothelioma",
"macracanthrorhynchiasis",
"microcryptocrystalline",
"naphthylaminesulphonic",
"nonrepresentationalism",
"omnirepresentativeness",
"pancreaticoduodenostomy",
"pancreaticogastrostomy",
"pathologicohistological",
"pathologicopsychological",
"pericardiomediastinitis",
"phenolsulphonephthalein",
"philosophicohistorical",
"philosophicotheological",
"photochronographically",
"photospectroheliograph",
"pneumohydropericardium",
"pneumoventriculography",
"polioencephalomyelitis",
"Prorhipidoglossomorpha",
"Pseudolamellibranchiata",
"pseudolamellibranchiate",
"pseudomonocotyledonous",
"pyopneumocholecystitis",
"scientificogeographical",
"scientificophilosophical",
"scleroticochorioiditis",
"stereophotomicrography",
"tetraiodophenolphthalein",
"theologicoastronomical",
"theologicometaphysical",
"thymolsulphonephthalein",
"thyroparathyroidectomize",
"thyroparathyroidectomy",
"transubstantiationalist",
"ureterocystanastomosis",
"zoologicoarchaeologist"
};
}

View file

@ -0,0 +1,573 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary micro-benchmark correctness mode
* @run main RemoveMicroBenchmark iterations=1 size=8 warmup=0
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.stream.Collectors.toCollection;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/**
* Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
*
* To run this in micro-benchmark mode, simply run as a normal java program.
* Be patient; this program runs for a very long time.
* For faster runs, restrict execution using command line args.
*
* @author Martin Buchholz
*/
public class RemoveMicroBenchmark {
abstract static class Job {
private final String name;
public Job(String name) { this.name = name; }
public String name() { return name; }
public abstract void work() throws Throwable;
public void run() {
try { work(); }
catch (Throwable ex) {
// current job cannot always be deduced from stacktrace.
throw new RuntimeException("Job failed: " + name(), ex);
}
}
}
final int iterations;
final int size; // number of elements in collections
final double warmupSeconds;
final long warmupNanos;
final Pattern nameFilter; // select subset of Jobs to run
final boolean reverse; // reverse order of Jobs
final boolean shuffle; // randomize order of Jobs
final ArrayList<Integer> elements; // contains size random Integers
RemoveMicroBenchmark(String[] args) {
iterations = intArg(args, "iterations", 10_000);
size = intArg(args, "size", 1000);
warmupSeconds = doubleArg(args, "warmup", 7.0);
nameFilter = patternArg(args, "filter");
reverse = booleanArg(args, "reverse");
shuffle = booleanArg(args, "shuffle");
warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
elements = ThreadLocalRandom.current().ints(size)
.mapToObj(x -> x)
.collect(toCollection(ArrayList::new));
}
// --------------- GC finalization infrastructure ---------------
/** No guarantees, but effective in practice. */
static void forceFullGc() {
long timeoutMillis = 1000L;
CountDownLatch finalized = new CountDownLatch(1);
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> ref = new WeakReference<>(
new Object() { protected void finalize() { finalized.countDown(); }},
queue);
try {
for (int tries = 3; tries--> 0; ) {
System.gc();
if (finalized.await(timeoutMillis, MILLISECONDS)
&& queue.remove(timeoutMillis) != null
&& ref.get() == null) {
System.runFinalization(); // try to pick up stragglers
return;
}
timeoutMillis *= 4;
}
} catch (InterruptedException unexpected) {
throw new AssertionError("unexpected InterruptedException");
}
throw new AssertionError("failed to do a \"full\" gc");
}
/**
* Runs each job for long enough that all the runtime compilers
* have had plenty of time to warm up, i.e. get around to
* compiling everything worth compiling.
* Returns array of average times per job per run.
*/
long[] time0(List<Job> jobs) {
final int size = jobs.size();
long[] nanoss = new long[size];
for (int i = 0; i < size; i++) {
if (warmupNanos > 0) forceFullGc();
Job job = jobs.get(i);
long totalTime;
int runs = 0;
long startTime = System.nanoTime();
do { job.run(); runs++; }
while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
nanoss[i] = totalTime/runs;
}
return nanoss;
}
void time(List<Job> jobs) throws Throwable {
if (warmupNanos > 0) time0(jobs); // Warm up run
final int size = jobs.size();
final long[] nanoss = time0(jobs); // Real timing run
final long[] milliss = new long[size];
final double[] ratios = new double[size];
final String nameHeader = "Method";
final String millisHeader = "Millis";
final String ratioHeader = "Ratio";
int nameWidth = nameHeader.length();
int millisWidth = millisHeader.length();
int ratioWidth = ratioHeader.length();
for (int i = 0; i < size; i++) {
nameWidth = Math.max(nameWidth, jobs.get(i).name().length());
milliss[i] = nanoss[i]/(1000L * 1000L);
millisWidth = Math.max(millisWidth,
String.format("%d", milliss[i]).length());
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
ratioWidth = Math.max(ratioWidth,
String.format("%.3f", ratios[i]).length());
}
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
nameWidth, millisWidth, ratioWidth);
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
nameWidth, millisWidth, ratioWidth);
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
// Print out absolute and relative times, calibrated against first job
for (int i = 0; i < size; i++)
System.out.printf(format, jobs.get(i).name(), milliss[i], ratios[i]);
}
private static String keywordValue(String[] args, String keyword) {
for (String arg : args)
if (arg.startsWith(keyword))
return arg.substring(keyword.length() + 1);
return null;
}
private static int intArg(String[] args, String keyword, int defaultValue) {
String val = keywordValue(args, keyword);
return (val == null) ? defaultValue : Integer.parseInt(val);
}
private static double doubleArg(String[] args, String keyword, double defaultValue) {
String val = keywordValue(args, keyword);
return (val == null) ? defaultValue : Double.parseDouble(val);
}
private static Pattern patternArg(String[] args, String keyword) {
String val = keywordValue(args, keyword);
return (val == null) ? null : Pattern.compile(val);
}
private static boolean booleanArg(String[] args, String keyword) {
String val = keywordValue(args, keyword);
if (val == null || val.equals("false")) return false;
if (val.equals("true")) return true;
throw new IllegalArgumentException(val);
}
private static void deoptimize(int sum) {
if (sum == 42)
System.out.println("the answer");
}
private static <T> Iterable<T> backwards(final List<T> list) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return new Iterator<T>() {
final ListIterator<T> it = list.listIterator(list.size());
public boolean hasNext() { return it.hasPrevious(); }
public T next() { return it.previous(); }
public void remove() { it.remove(); }};}};
}
// Checks for correctness *and* prevents loop optimizations
static class Check {
private int sum;
public void sum(int sum) {
if (this.sum == 0)
this.sum = sum;
if (this.sum != sum)
throw new AssertionError("Sum mismatch");
}
}
volatile Check check = new Check();
public static void main(String[] args) throws Throwable {
new RemoveMicroBenchmark(args).run();
}
HashMap<Class<?>, String> goodClassName = new HashMap<>();
String goodClassName(Class<?> klazz) {
return goodClassName.computeIfAbsent(
klazz,
k -> {
String simple = k.getSimpleName();
return (simple.equals("SubList")) // too simple!
? k.getName().replaceFirst(".*\\.", "")
: simple;
});
}
String goodClassName(Object x) {
return goodClassName(x.getClass());
}
static List<Integer> makeSubList(List<Integer> list) {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
int size = rnd.nextInt(4);
for (int i = size; i--> 0; )
list.add(rnd.nextInt());
int index = rnd.nextInt(size + 1);
return list.subList(index, index);
}
private static <T> List<T> asSubList(List<T> list) {
return list.subList(0, list.size());
}
@SafeVarargs @SuppressWarnings("varargs")
private static <T> Stream<T> concatStreams(Stream<T> ... streams) {
return Stream.of(streams).flatMap(s -> s);
}
Class<?> topLevelClass(Object x) {
for (Class<?> k = x.getClass();; ) {
Class<?> enclosing = k.getEnclosingClass();
if (enclosing == null)
return k;
k = enclosing;
}
}
void run() throws Throwable {
ArrayList<Job> jobs = Stream.<Collection<Integer>>of(
new ArrayList<>(),
makeSubList(new ArrayList<>()),
new LinkedList<>(),
makeSubList(new LinkedList<>()),
new Vector<>(),
makeSubList(new Vector<>()),
new CopyOnWriteArrayList<>(),
makeSubList(new CopyOnWriteArrayList<>()),
new ArrayDeque<>(),
new PriorityQueue<>(),
new ArrayBlockingQueue<>(elements.size()),
new ConcurrentLinkedQueue<>(),
new ConcurrentLinkedDeque<>(),
new LinkedBlockingQueue<>(),
new LinkedBlockingDeque<>(),
new LinkedTransferQueue<>(),
new PriorityBlockingQueue<>())
.flatMap(x -> jobs(x))
.filter(job ->
nameFilter == null || nameFilter.matcher(job.name()).find())
.collect(toCollection(ArrayList::new));
if (reverse) Collections.reverse(jobs);
if (shuffle) Collections.shuffle(jobs);
time(jobs);
}
Stream<Job> jobs(Collection<Integer> x) {
return concatStreams(
collectionJobs(x),
(CopyOnWriteArrayList.class.isAssignableFrom(topLevelClass(x)))
? Stream.empty()
: iteratorRemoveJobs(x),
(x instanceof Queue)
? queueJobs((Queue<Integer>)x)
: Stream.empty(),
(x instanceof Deque)
? dequeJobs((Deque<Integer>)x)
: Stream.empty(),
(x instanceof BlockingQueue)
? blockingQueueJobs((BlockingQueue<Integer>)x)
: Stream.empty(),
(x instanceof BlockingDeque)
? blockingDequeJobs((BlockingDeque<Integer>)x)
: Stream.empty());
}
Collection<Integer> universeRecorder(int[] sum) {
return new ArrayList<>() {
public boolean contains(Object x) {
sum[0] += (Integer) x;
return true;
}};
}
Collection<Integer> emptyRecorder(int[] sum) {
return new ArrayList<>() {
public boolean contains(Object x) {
sum[0] += (Integer) x;
return false;
}};
}
Stream<Job> collectionJobs(Collection<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
x.removeIf(n -> { sum[0] += n; return true; });
check.sum(sum[0]);}}},
new Job(klazz + " removeIf rnd-two-pass") {
public void work() throws Throwable {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
x.removeIf(n -> {
boolean b = rnd.nextBoolean();
if (b) sum[0] += n;
return b; });
x.removeIf(n -> { sum[0] += n; return true; });
check.sum(sum[0]);}}},
new Job(klazz + " removeAll") {
public void work() throws Throwable {
int[] sum = new int[1];
Collection<Integer> universe = universeRecorder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
x.removeAll(universe);
check.sum(sum[0]);}}},
new Job(klazz + " retainAll") {
public void work() throws Throwable {
int[] sum = new int[1];
Collection<Integer> empty = emptyRecorder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
x.retainAll(empty);
check.sum(sum[0]);}}},
new Job(klazz + " clear") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
x.forEach(e -> sum[0] += e);
x.clear();
check.sum(sum[0]);}}});
}
Stream<Job> iteratorRemoveJobs(Collection<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " Iterator.remove") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
Iterator<Integer> it = x.iterator();
while (it.hasNext()) {
sum[0] += it.next();
it.remove();
}
check.sum(sum[0]);}}},
new Job(klazz + " Iterator.remove-rnd-two-pass") {
public void work() throws Throwable {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
for (Iterator<Integer> it = x.iterator();
it.hasNext(); ) {
Integer e = it.next();
if (rnd.nextBoolean()) {
sum[0] += e;
it.remove();
}
}
for (Iterator<Integer> it = x.iterator();
it.hasNext(); ) {
sum[0] += it.next();
it.remove();
}
check.sum(sum[0]);}}});
}
Stream<Job> queueJobs(Queue<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " poll()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
for (Integer e; (e = x.poll()) != null; )
sum[0] += e;
check.sum(sum[0]);}}});
}
Stream<Job> dequeJobs(Deque<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " descendingIterator().remove") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
Iterator<Integer> it = x.descendingIterator();
while (it.hasNext()) {
sum[0] += it.next();
it.remove();
}
check.sum(sum[0]);}}},
new Job(klazz + " pollFirst()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
for (Integer e; (e = x.pollFirst()) != null; )
sum[0] += e;
check.sum(sum[0]);}}},
new Job(klazz + " pollLast()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
for (Integer e; (e = x.pollLast()) != null; )
sum[0] += e;
check.sum(sum[0]);}}});
}
Stream<Job> blockingQueueJobs(BlockingQueue<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " timed poll()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
for (Integer e; (e = x.poll(0L, TimeUnit.DAYS)) != null; )
sum[0] += e;
check.sum(sum[0]);}}},
new Job(klazz + " drainTo(sink)") {
public void work() throws Throwable {
ArrayList<Integer> sink = new ArrayList<>();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
sink.clear();
x.addAll(elements);
x.drainTo(sink);
sink.forEach(e -> sum[0] += e);
check.sum(sum[0]);}}},
new Job(klazz + " drainTo(sink, n)") {
public void work() throws Throwable {
ArrayList<Integer> sink = new ArrayList<>();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
sink.clear();
x.addAll(elements);
x.drainTo(sink, elements.size());
sink.forEach(e -> sum[0] += e);
check.sum(sum[0]);}}});
}
Stream<Job> blockingDequeJobs(BlockingDeque<Integer> x) {
final String klazz = goodClassName(x);
return Stream.of(
new Job(klazz + " timed pollFirst()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
for (Integer e; (e = x.pollFirst(0L, TimeUnit.DAYS)) != null; )
sum[0] += e;
check.sum(sum[0]);}}},
new Job(klazz + " timed pollLast()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
x.addAll(elements);
for (Integer e; (e = x.pollLast(0L, TimeUnit.DAYS)) != null; )
sum[0] += e;
check.sum(sum[0]);}}});
}
}

View file

@ -0,0 +1,345 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertNotSame;
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
/*
* @test
* @bug 8048330
* @summary Test convenience static factory methods on Set.
* @run testng SetFactories
*/
public class SetFactories {
static final int NUM_STRINGS = 20; // should be larger than the largest fixed-arg overload
static final String[] stringArray;
static {
String[] sa = new String[NUM_STRINGS];
for (int i = 0; i < NUM_STRINGS; i++) {
sa[i] = String.valueOf((char)('a' + i));
}
stringArray = sa;
}
static Object[] a(Set<String> act, Set<String> exp) {
return new Object[] { act, exp };
}
static Set<String> hashSetOf(String... args) {
return new HashSet<>(Arrays.asList(args));
}
@DataProvider(name="empty")
public Iterator<Object[]> empty() {
return Collections.singletonList(
// actual, expected
a(Set.of(), Collections.emptySet())
).iterator();
}
@DataProvider(name="nonempty")
public Iterator<Object[]> nonempty() {
return Arrays.asList(
// actual, expected
a( Set.of("a"),
hashSetOf("a")),
a( Set.of("a", "b"),
hashSetOf("a", "b")),
a( Set.of("a", "b", "c"),
hashSetOf("a", "b", "c")),
a( Set.of("a", "b", "c", "d"),
hashSetOf("a", "b", "c", "d")),
a( Set.of("a", "b", "c", "d", "e"),
hashSetOf("a", "b", "c", "d", "e")),
a( Set.of("a", "b", "c", "d", "e", "f"),
hashSetOf("a", "b", "c", "d", "e", "f")),
a( Set.of("a", "b", "c", "d", "e", "f", "g"),
hashSetOf("a", "b", "c", "d", "e", "f", "g")),
a( Set.of("a", "b", "c", "d", "e", "f", "g", "h"),
hashSetOf("a", "b", "c", "d", "e", "f", "g", "h")),
a( Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i"),
hashSetOf("a", "b", "c", "d", "e", "f", "g", "h", "i")),
a( Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"),
hashSetOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")),
a( Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"),
Set.of("j", "i", "h", "g", "f", "e", "d", "c", "b", "a")),
a( Set.of(stringArray),
hashSetOf(stringArray))
).iterator();
}
@DataProvider(name="all")
public Iterator<Object[]> all() {
List<Object[]> all = new ArrayList<>();
empty().forEachRemaining(all::add);
nonempty().forEachRemaining(all::add);
return all.iterator();
}
@Test(dataProvider="all", expectedExceptions=UnsupportedOperationException.class)
public void cannotAdd(Set<String> act, Set<String> exp) {
act.add("x");
}
@Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class)
public void cannotRemove(Set<String> act, Set<String> exp) {
act.remove(act.iterator().next());
}
@Test(dataProvider="all")
public void contentsMatch(Set<String> act, Set<String> exp) {
assertEquals(act, exp);
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowed2() {
Set<String> set = Set.of("a", "a");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowed3() {
Set<String> set = Set.of("a", "b", "a");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowed4() {
Set<String> set = Set.of("a", "b", "c", "a");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowed5() {
Set<String> set = Set.of("a", "b", "c", "d", "a");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowed6() {
Set<String> set = Set.of("a", "b", "c", "d", "e", "a");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowed7() {
Set<String> set = Set.of("a", "b", "c", "d", "e", "f", "a");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowed8() {
Set<String> set = Set.of("a", "b", "c", "d", "e", "f", "g", "a");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowed9() {
Set<String> set = Set.of("a", "b", "c", "d", "e", "f", "g", "h", "a");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowed10() {
Set<String> set = Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "a");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupsDisallowedN() {
String[] array = stringArray.clone();
array[0] = array[1];
Set<String> set = Set.of(array);
}
@Test(dataProvider="all")
public void hashCodeEqual(Set<String> act, Set<String> exp) {
assertEquals(act.hashCode(), exp.hashCode());
}
@Test(dataProvider="all")
public void containsAll(Set<String> act, Set<String> exp) {
assertTrue(act.containsAll(exp));
assertTrue(exp.containsAll(act));
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed1() {
Set.of((String)null); // force one-arg overload
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed2a() {
Set.of("a", null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed2b() {
Set.of(null, "b");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed3() {
Set.of("a", "b", null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed4() {
Set.of("a", "b", "c", null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed5() {
Set.of("a", "b", "c", "d", null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed6() {
Set.of("a", "b", "c", "d", "e", null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed7() {
Set.of("a", "b", "c", "d", "e", "f", null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed8() {
Set.of("a", "b", "c", "d", "e", "f", "g", null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed9() {
Set.of("a", "b", "c", "d", "e", "f", "g", "h", null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowed10() {
Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullDisallowedN() {
String[] array = stringArray.clone();
array[0] = null;
Set.of(array);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullArrayDisallowed() {
Set.of((Object[])null);
}
@Test(dataProvider="all", expectedExceptions=NullPointerException.class)
public void containsNullShouldThrowNPE(Set<String> act, Set<String> exp) {
act.contains(null);
}
@Test(dataProvider="all")
public void serialEquality(Set<String> act, Set<String> exp) {
// assume that act.equals(exp) tested elsewhere
Set<String> copy = serialClone(act);
assertEquals(act, copy);
assertEquals(copy, exp);
}
@SuppressWarnings("unchecked")
static <T> T serialClone(T obj) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(obj);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new AssertionError(e);
}
}
Set<Integer> genSet() {
return new HashSet<>(Arrays.asList(1, 2, 3));
}
@Test
public void copyOfResultsEqual() {
Set<Integer> orig = genSet();
Set<Integer> copy = Set.copyOf(orig);
assertEquals(orig, copy);
assertEquals(copy, orig);
}
@Test
public void copyOfModifiedUnequal() {
Set<Integer> orig = genSet();
Set<Integer> copy = Set.copyOf(orig);
orig.add(4);
assertNotEquals(orig, copy);
assertNotEquals(copy, orig);
}
@Test
public void copyOfIdentity() {
Set<Integer> orig = genSet();
Set<Integer> copy1 = Set.copyOf(orig);
Set<Integer> copy2 = Set.copyOf(copy1);
assertNotSame(orig, copy1);
assertSame(copy1, copy2);
}
@Test(expectedExceptions=NullPointerException.class)
public void copyOfRejectsNullCollection() {
Set<Integer> set = Set.copyOf(null);
}
@Test(expectedExceptions=NullPointerException.class)
public void copyOfRejectsNullElements() {
Set<Integer> set = Set.copyOf(Arrays.asList(1, null, 3));
}
@Test
public void copyOfAcceptsDuplicates() {
Set<Integer> set = Set.copyOf(Arrays.asList(1, 1, 2, 3, 3, 3));
assertEquals(set, Set.of(1, 2, 3));
}
}

View file

@ -0,0 +1,216 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
/**
* @library
* CollectionAssert -- assertion methods for lambda test cases
*/
public class CollectionAsserts {
private CollectionAsserts() {
// no instances
}
public static void assertCountSum(Iterable<? super Integer> it, int count, int sum) {
assertCountSum(it.iterator(), count, sum);
}
public static void assertCountSum(Iterator<? super Integer> it, int count, int sum) {
int c = 0;
int s = 0;
while (it.hasNext()) {
int i = (Integer) it.next();
c++;
s += i;
}
assertEquals(c, count);
assertEquals(s, sum);
}
public static void assertConcat(Iterator<Character> it, String result) {
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
sb.append(it.next());
}
assertEquals(result, sb.toString());
}
public static<T extends Comparable<? super T>> void assertSorted(Iterator<T> i) {
if (!i.hasNext())
return;
T last = i.next();
while (i.hasNext()) {
T t = i.next();
assertTrue(last.compareTo(t) <= 0);
assertTrue(t.compareTo(last) >= 0);
last = t;
}
}
public static<T> void assertSorted(Iterator<T> i, Comparator<? super T> comp) {
if (!i.hasNext())
return;
T last = i.next();
while (i.hasNext()) {
T t = i.next();
assertTrue(comp.compare(last, t) <= 0);
assertTrue(comp.compare(t, last) >= 0);
last = t;
}
}
public static<T extends Comparable<? super T>> void assertSorted(Iterable<T> iter) {
assertSorted(iter.iterator());
}
public static<T> void assertSorted(Iterable<T> iter, Comparator<? super T> comp) {
assertSorted(iter.iterator(), comp);
}
public static <T> void assertUnique(Iterable<T> iter) {
assertUnique(iter.iterator());
}
public static<T> void assertUnique(Iterator<T> iter) {
if (!iter.hasNext()) {
return;
}
Set<T> uniq = new HashSet<>();
while (iter.hasNext()) {
T each = iter.next();
assertTrue(!uniq.contains(each));
uniq.add(each);
}
}
public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected) {
assertContents(actual, expected, null);
}
public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected, String msg) {
assertContents(actual.iterator(), expected.iterator(), msg);
}
public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected) {
assertContents(actual, expected, null);
}
public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected, String msg) {
List<T> history = new ArrayList<>();
while (expected.hasNext()) {
if (!actual.hasNext()) {
List<T> expectedData = new ArrayList<>(history);
while (expected.hasNext())
expectedData.add(expected.next());
fail(String.format("%s Premature end of data; expected=%s, found=%s",
(msg == null ? "" : msg), expectedData, history));
}
T a = actual.next();
T e = expected.next();
history.add(a);
if (!Objects.equals(a, e))
fail(String.format("%s Data mismatch; preceding=%s, nextExpected=%s, nextFound=%s",
(msg == null ? "" : msg), history, e, a));
}
if (actual.hasNext()) {
List<T> rest = new ArrayList<>();
while (actual.hasNext())
rest.add(actual.next());
fail(String.format("%s Unexpected data %s after %s",
(msg == null ? "" : msg), rest, history));
}
}
@SafeVarargs
@SuppressWarnings("varargs")
public static<T> void assertContents(Iterator<T> actual, T... expected) {
assertContents(actual, Arrays.asList(expected).iterator());
}
public static<T extends Comparable<? super T>> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
assertContentsUnordered(actual, expected, null);
}
public static<T extends Comparable<? super T>> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected, String msg) {
List<T> allExpected = new ArrayList<>();
for (T t : expected) {
allExpected.add(t);
}
for (T t : actual) {
assertTrue(allExpected.remove(t), msg + " element '" + String.valueOf(t) + "' not found");
}
assertTrue(allExpected.isEmpty(), msg + "expected contained additional elements");
}
static <T> void assertSplitContents(Iterable<Iterable<T>> splits, Iterable<T> list) {
Iterator<Iterable<T>> mI = splits.iterator();
Iterator<T> pI = null;
Iterator<T> lI = list.iterator();
while (lI.hasNext()) {
if (pI == null)
pI = mI.next().iterator();
while (!pI.hasNext()) {
if (!mI.hasNext()) {
break;
}
else {
pI = mI.next().iterator();
}
}
assertTrue(pI.hasNext());
T pT = pI.next();
T lT = lI.next();
assertEquals(pT, lT);
}
if (pI != null) {
assertTrue(!pI.hasNext());
}
while (mI.hasNext()) {
pI = mI.next().iterator();
assertTrue(!pI.hasNext());
}
}
}

View file

@ -0,0 +1,250 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.Exception;
import java.lang.Integer;
import java.lang.Iterable;
import java.lang.Override;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import org.testng.TestException;
import static org.testng.Assert.assertTrue;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @library
* @summary A Supplier of test cases for Collection tests
*/
public final class CollectionSupplier<C extends Collection<Integer>> implements Supplier<Iterable<CollectionSupplier.TestCase<C>>> {
private final List<Function<Collection<Integer>, C>> suppliers;
private final int size;
/**
* A Collection test case.
*/
public static final class TestCase<C extends Collection<Integer>> {
/**
* The name of the test case.
*/
public final String name;
/**
* The supplier of a collection
*/
public Function<Collection<Integer>, C> supplier;
/**
* Unmodifiable reference collection, useful for comparisons.
*/
public final List<Integer> expected;
/**
* A modifiable test collection.
*/
public final C collection;
/**
* Create a Collection test case.
*
* @param name name of the test case
* @param collection the modifiable test collection
*/
public TestCase(String name, Function<Collection<Integer>, C> supplier, C collection) {
this.name = name;
this.supplier = supplier;
this.expected = Collections.unmodifiableList(
Arrays.asList(collection.toArray(new Integer[0])));
this.collection = collection;
}
@Override
public String toString() {
return name + " " + collection.getClass().toString();
}
}
/**
* Shuffle a list using a PRNG with known seed for repeatability
*
* @param list the list to be shuffled
*/
public static <E> void shuffle(final List<E> list) {
// PRNG with known seed for repeatable tests
final Random prng = new Random(13);
final int size = list.size();
for (int i = 0; i < size; i++) {
// random index in interval [i, size)
final int j = i + prng.nextInt(size - i);
// swap elements at indices i & j
final E e = list.get(i);
list.set(i, list.get(j));
list.set(j, e);
}
}
/**
* Create a {@code CollectionSupplier} that creates instances of specified
* collection suppliers of the specified size.
*
* @param suppliers the suppliers names that supply {@code Collection}
* instances
* @param size the desired size of each collection
*/
public CollectionSupplier(List<Function<Collection<Integer>, C>> suppliers, int size) {
this.suppliers = suppliers;
this.size = size;
}
@Override
public Iterable<TestCase<C>> get() {
final Collection<TestCase<C>> cases = new LinkedList<>();
for (final Function<Collection<Integer>, C> supplier : suppliers)
try {
cases.add(new TestCase<>("empty", supplier, supplier.apply(Collections.emptyList())));
cases.add(new TestCase<>("single", supplier, supplier.apply(Arrays.asList(42))));
final Collection<Integer> regular = new ArrayList<>();
for (int i = 0; i < size; i++) {
regular.add(i);
}
cases.add(new TestCase<>("regular", supplier, supplier.apply(regular)));
final Collection<Integer> reverse = new ArrayList<>();
for (int i = size; i >= 0; i--) {
reverse.add(i);
}
cases.add(new TestCase<>("reverse", supplier, supplier.apply(reverse)));
final Collection<Integer> odds = new ArrayList<>();
for (int i = 0; i < size; i++) {
odds.add((i * 2) + 1);
}
cases.add(new TestCase<>("odds", supplier, supplier.apply(odds)));
final Collection<Integer> evens = new ArrayList<>();
for (int i = 0; i < size; i++) {
evens.add(i * 2);
}
cases.add(new TestCase<>("evens", supplier, supplier.apply(evens)));
final Collection<Integer> fibonacci = new ArrayList<>();
int prev2 = 0;
int prev1 = 1;
for (int i = 0; i < size; i++) {
final int n = prev1 + prev2;
if (n < 0) { // stop on overflow
break;
}
fibonacci.add(n);
prev2 = prev1;
prev1 = n;
}
cases.add(new TestCase<>("fibonacci", supplier, supplier.apply(fibonacci)));
boolean isStructurallyModifiable = false;
try {
C t = supplier.apply(Collections.emptyList());
t.add(1);
isStructurallyModifiable = true;
} catch (UnsupportedOperationException e) { }
if (!isStructurallyModifiable)
continue;
// variants where the size of the backing storage != reported size
// created by removing half of the elements
final C emptyWithSlack = supplier.apply(Collections.emptyList());
emptyWithSlack.add(42);
assertTrue(emptyWithSlack.remove(42));
cases.add(new TestCase<>("emptyWithSlack", supplier, emptyWithSlack));
final C singleWithSlack = supplier.apply(Collections.emptyList());
singleWithSlack.add(42);
singleWithSlack.add(43);
assertTrue(singleWithSlack.remove(43));
cases.add(new TestCase<>("singleWithSlack", supplier, singleWithSlack));
final C regularWithSlack = supplier.apply(Collections.emptyList());
for (int i = 0; i < (2 * size); i++) {
regularWithSlack.add(i);
}
assertTrue(regularWithSlack.removeIf(x -> x < size));
cases.add(new TestCase<>("regularWithSlack", supplier, regularWithSlack));
final C reverseWithSlack = supplier.apply(Collections.emptyList());
for (int i = 2 * size; i >= 0; i--) {
reverseWithSlack.add(i);
}
assertTrue(reverseWithSlack.removeIf(x -> x < size));
cases.add(new TestCase<>("reverseWithSlack", supplier, reverseWithSlack));
final C oddsWithSlack = supplier.apply(Collections.emptyList());
for (int i = 0; i < 2 * size; i++) {
oddsWithSlack.add((i * 2) + 1);
}
assertTrue(oddsWithSlack.removeIf(x -> x >= size));
cases.add(new TestCase<>("oddsWithSlack", supplier, oddsWithSlack));
final C evensWithSlack = supplier.apply(Collections.emptyList());
for (int i = 0; i < 2 * size; i++) {
evensWithSlack.add(i * 2);
}
assertTrue(evensWithSlack.removeIf(x -> x >= size));
cases.add(new TestCase<>("evensWithSlack", supplier, evensWithSlack));
final C fibonacciWithSlack = supplier.apply(Collections.emptyList());
prev2 = 0;
prev1 = 1;
for (int i = 0; i < size; i++) {
final int n = prev1 + prev2;
if (n < 0) { // stop on overflow
break;
}
fibonacciWithSlack.add(n);
prev2 = prev1;
prev1 = n;
}
assertTrue(fibonacciWithSlack.removeIf(x -> x < 20));
cases.add(new TestCase<>("fibonacciWithSlack", supplier, fibonacciWithSlack));
}
catch (Exception failed) {
throw new TestException(failed);
}
return cases;
}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.Supplier;
/**
* @library
*
* A simple mutable collection implementation that provides only default
* implementations of all methods. ie. none of the Collection interface default
* methods have overridden implementations.
*
* @param <E> type of collection elements
*/
public class ExtendsAbstractCollection<E> extends AbstractCollection<E> {
protected final Collection<E> coll;
public ExtendsAbstractCollection() {
this(ArrayList<E>::new);
}
public ExtendsAbstractCollection(Collection<E> source) {
this();
coll.addAll(source);
}
protected ExtendsAbstractCollection(Supplier<Collection<E>> backer) {
this.coll = backer.get();
}
public boolean add(E element) {
return coll.add(element);
}
public boolean remove(Object element) {
return coll.remove(element);
}
public Iterator<E> iterator() {
return new Iterator<E>() {
Iterator<E> source = coll.iterator();
public boolean hasNext() {
return source.hasNext();
}
public E next() {
return source.next();
}
public void remove() {
source.remove();
}
};
}
public int size() {
return coll.size();
}
}

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.ArrayList;
import java.util.AbstractList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.function.Supplier;
/**
* @library
*
* A simple mutable list implementation that provides only default
* implementations of all methods. ie. none of the List interface default
* methods have overridden implementations.
*
* @param <E> type of list elements
*/
public class ExtendsAbstractList<E> extends AbstractList<E> {
protected final List<E> list;
public ExtendsAbstractList() {
this(ArrayList<E>::new);
}
protected ExtendsAbstractList(Supplier<List<E>> supplier) {
this.list = supplier.get();
}
public ExtendsAbstractList(Collection<E> source) {
this();
addAll(source);
}
public boolean add(E element) {
return list.add(element);
}
public E get(int index) {
return list.get(index);
}
public boolean remove(Object element) {
return list.remove(element);
}
public E set(int index, E element) {
return list.set(index, element);
}
public void add(int index, E element) {
list.add(index, element);
}
public E remove(int index) {
return list.remove(index);
}
public Iterator<E> iterator() {
return new Iterator<E>() {
Iterator<E> source = list.iterator();
public boolean hasNext() {
return source.hasNext();
}
public E next() {
return source.next();
}
public void remove() {
source.remove();
}
};
}
public int size() {
return list.size();
}
}

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.HashSet;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Supplier;
/**
* @library
*
* A simple mutable set implementation that provides only default
* implementations of all methods. ie. none of the Set interface default methods
* have overridden implementations.
*
* @param <E> type of set members
*/
public class ExtendsAbstractSet<E> extends AbstractSet<E> {
protected final Set<E> set;
public ExtendsAbstractSet() {
this(HashSet<E>::new);
}
public ExtendsAbstractSet(Collection<E> source) {
this();
addAll(source);
}
protected ExtendsAbstractSet(Supplier<Set<E>> backer) {
this.set = backer.get();
}
public boolean add(E element) {
return set.add(element);
}
public boolean remove(Object element) {
return set.remove(element);
}
public Iterator<E> iterator() {
return new Iterator<E>() {
Iterator<E> source = set.iterator();
public boolean hasNext() {
return source.hasNext();
}
public E next() {
return source.next();
}
public void remove() {
source.remove();
}
};
}
public int size() {
return set.size();
}
}