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,506 @@
/*
* Copyright (c) 2003, 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 4906359 6239296
* @summary Basic test for content-based array object methods
* @author Josh Bloch, Martin Buchholz
* @key randomness
*/
import java.util.*;
import java.io.*;
public class ArrayObjectMethods {
int[] sizes = {0, 10, 100, 200, 1000};
void test(String[] args) throws Throwable {
equal(Arrays.deepToString(null), "null");
equal(Arrays.deepToString(new Object[]{}), "[]");
equal(Arrays.deepToString(new Object[]{null}), "[null]");
equal(Arrays.deepToString(new Object[]{null, 1}), "[null, 1]");
equal(Arrays.deepToString(new Object[]{1, null}), "[1, null]");
equal(Arrays.deepToString(new Object[]{new Object[]{}, null}), "[[], null]");
{
Object[] a = {1, null};
a[1] = a;
equal(Arrays.deepToString(a), "[1, [...]]");
a[0] = a;
equal(Arrays.deepToString(a), "[[...], [...]]");
a[0] = a[1] = new Object[]{1, null, a};
equal(Arrays.deepToString(a), "[[1, null, [...]], [1, null, [...]]]");
}
for (int size : sizes) {
{
long[] a = Rnd.longArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
int[] a = Rnd.intArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
short[] a = Rnd.shortArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
char[] a = Rnd.charArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
byte[] a = Rnd.byteArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
boolean[] a = Rnd.booleanArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
double[] a = Rnd.doubleArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
float[] a = Rnd.floatArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
Object[] a = Rnd.flatObjectArray(size);
equal(Arrays.toString(a), Arrays.asList(a).toString());
equal(Arrays.deepToString(a), Arrays.asList(a).toString());
equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
}
if (size <= 200) {
Object[] a = Rnd.nestedObjectArray(size);
List aList = deepToList(a);
equal(Arrays.toString(a), Arrays.asList(a).toString());
equal(Arrays.deepToString(a), aList.toString());
equal(Arrays.deepHashCode(a), aList.hashCode());
equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
Object[] deepCopy = (Object[]) deepCopy(a);
check(Arrays.deepEquals(a, deepCopy));
check(Arrays.deepEquals(deepCopy, a));
// Make deepCopy != a
if (size == 0)
deepCopy = new Object[] {"foo"};
else if (deepCopy[deepCopy.length - 1] == null)
deepCopy[deepCopy.length - 1] = "baz";
else
deepCopy[deepCopy.length - 1] = null;
check(! Arrays.deepEquals(a, deepCopy));
check(! Arrays.deepEquals(deepCopy, a));
}
}
}
// Utility method to turn an array into a list "deeply," turning
// all primitives into objects
List<Object> deepToList(Object[] a) {
List<Object> result = new ArrayList<Object>();
for (Object e : a) {
if (e instanceof byte[])
result.add(PrimitiveArrays.asList((byte[])e));
else if (e instanceof short[])
result.add(PrimitiveArrays.asList((short[])e));
else if (e instanceof int[])
result.add(PrimitiveArrays.asList((int[])e));
else if (e instanceof long[])
result.add(PrimitiveArrays.asList((long[])e));
else if (e instanceof char[])
result.add(PrimitiveArrays.asList((char[])e));
else if (e instanceof double[])
result.add(PrimitiveArrays.asList((double[])e));
else if (e instanceof float[])
result.add(PrimitiveArrays.asList((float[])e));
else if (e instanceof boolean[])
result.add(PrimitiveArrays.asList((boolean[])e));
else if (e instanceof Object[])
result.add(deepToList((Object[])e));
else
result.add(e);
}
return result;
}
// Utility method to do a deep copy of an object *very slowly* using
// serialization/deserialization
Object deepCopy(Object oldObj) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(oldObj);
oos.flush();
ByteArrayInputStream bin = new ByteArrayInputStream(
bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin);
return ois.readObject();
} catch(Exception e) {
throw new IllegalArgumentException(e);
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
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 {
new ArrayObjectMethods().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(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");}
}
/**
* Methods to generate "interesting" random primitives and primitive
* arrays. Unlike Random.nextXxx, these methods return small values
* and boundary values (e.g., 0, -1, NaN) with greater than normal
* likelihood.
*/
class Rnd {
private static Random rnd = new Random();
public static long nextLong() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Long.MIN_VALUE;
case 2: return Long.MAX_VALUE;
case 3: case 4: case 5:
return (long) (rnd.nextInt(20) - 10);
default: return rnd.nextLong();
}
}
public static int nextInt() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Integer.MIN_VALUE;
case 2: return Integer.MAX_VALUE;
case 3: case 4: case 5:
return rnd.nextInt(20) - 10;
default: return rnd.nextInt();
}
}
public static short nextShort() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Short.MIN_VALUE;
case 2: return Short.MAX_VALUE;
case 3: case 4: case 5:
return (short) (rnd.nextInt(20) - 10);
default: return (short) rnd.nextInt();
}
}
public static char nextChar() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Character.MIN_VALUE;
case 2: return Character.MAX_VALUE;
case 3: case 4: case 5:
return (char) (rnd.nextInt(20) - 10);
default: return (char) rnd.nextInt();
}
}
public static byte nextByte() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Byte.MIN_VALUE;
case 2: return Byte.MAX_VALUE;
case 3: case 4: case 5:
return (byte) (rnd.nextInt(20) - 10);
default: return (byte) rnd.nextInt();
}
}
public static boolean nextBoolean() {
return rnd.nextBoolean();
}
public static double nextDouble() {
switch(rnd.nextInt(20)) {
case 0: return 0;
case 1: return -0.0;
case 2: return Double.MIN_VALUE;
case 3: return Double.MAX_VALUE;
case 4: return Double.NaN;
case 5: return Double.NEGATIVE_INFINITY;
case 6: return Double.POSITIVE_INFINITY;
case 7: case 8: case 9:
return (rnd.nextInt(20) - 10);
default: return rnd.nextDouble();
}
}
public static float nextFloat() {
switch(rnd.nextInt(20)) {
case 0: return 0;
case 1: return -0.0f;
case 2: return Float.MIN_VALUE;
case 3: return Float.MAX_VALUE;
case 4: return Float.NaN;
case 5: return Float.NEGATIVE_INFINITY;
case 6: return Float.POSITIVE_INFINITY;
case 7: case 8: case 9:
return (rnd.nextInt(20) - 10);
default: return rnd.nextFloat();
}
}
public static Object nextObject() {
switch(rnd.nextInt(10)) {
case 0: return null;
case 1: return "foo";
case 2: case 3: case 4:
return Double.valueOf(nextDouble());
default: return Integer.valueOf(nextInt());
}
}
public static long[] longArray(int length) {
long[] result = new long[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextLong();
return result;
}
public static int[] intArray(int length) {
int[] result = new int[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextInt();
return result;
}
public static short[] shortArray(int length) {
short[] result = new short[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextShort();
return result;
}
public static char[] charArray(int length) {
char[] result = new char[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextChar();
return result;
}
public static byte[] byteArray(int length) {
byte[] result = new byte[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextByte();
return result;
}
public static boolean[] booleanArray(int length) {
boolean[] result = new boolean[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextBoolean();
return result;
}
public static double[] doubleArray(int length) {
double[] result = new double[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextDouble();
return result;
}
public static float[] floatArray(int length) {
float[] result = new float[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextFloat();
return result;
}
public static Object[] flatObjectArray(int length) {
Object[] result = new Object[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextObject();
return result;
}
// Calling this for length >> 100 is likely to run out of memory! It
// should be perhaps be tuned to allow for longer arrays
public static Object[] nestedObjectArray(int length) {
Object[] result = new Object[length];
for (int i = 0; i < length; i++) {
switch(rnd.nextInt(16)) {
case 0: result[i] = nestedObjectArray(length/2);
break;
case 1: result[i] = longArray(length/2);
break;
case 2: result[i] = intArray(length/2);
break;
case 3: result[i] = shortArray(length/2);
break;
case 4: result[i] = charArray(length/2);
break;
case 5: result[i] = byteArray(length/2);
break;
case 6: result[i] = floatArray(length/2);
break;
case 7: result[i] = doubleArray(length/2);
break;
case 8: result[i] = longArray(length/2);
break;
default: result[i] = Rnd.nextObject();
}
}
return result;
}
}
/**
* Primitive arrays viewed as lists. Inefficient but cool.
* This utility should be generally useful in writing regression/unit/basic
* tests.
*/
class PrimitiveArrays {
public static List<Long> asList(final long[] a) {
return new AbstractList<Long>() {
public Long get(int i) { return a[i]; }
public int size() { return a.length; }
public Long set(int i, Long e) {
long oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Integer> asList(final int[] a) {
return new AbstractList<Integer>() {
public Integer get(int i) { return a[i]; }
public int size() { return a.length; }
public Integer set(int i, Integer e) {
int oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Short> asList(final short[] a) {
return new AbstractList<Short>() {
public Short get(int i) { return a[i]; }
public int size() { return a.length; }
public Short set(int i, Short e) {
short oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Character> asList(final char[] a) {
return new AbstractList<Character>() {
public Character get(int i) { return a[i]; }
public int size() { return a.length; }
public Character set(int i, Character e) {
Character oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Byte> asList(final byte[] a) {
return new AbstractList<Byte>() {
public Byte get(int i) { return a[i]; }
public int size() { return a.length; }
public Byte set(int i, Byte e) {
Byte oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Boolean> asList(final boolean[] a) {
return new AbstractList<Boolean>() {
public Boolean get(int i) { return a[i]; }
public int size() { return a.length; }
public Boolean set(int i, Boolean e) {
Boolean oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Double> asList(final double[] a) {
return new AbstractList<Double>() {
public Double get(int i) { return a[i]; }
public int size() { return a.length; }
public Double set(int i, Double e) {
Double oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Float> asList(final float[] a) {
return new AbstractList<Float>() {
public Float get(int i) { return a[i]; }
public int size() { return a.length; }
public Float set(int i, Float e) {
Float oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2016, 2026, 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 8155600
* @summary Tests for Arrays.asList()
* @run junit AsList
*/
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.stream.IntStream;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class AsList {
/*
* Iterator contract test
*/
@ParameterizedTest
@MethodSource("arrays")
public void testIterator(Object[] array) {
Iterator<Object> itr = Arrays.asList(array).iterator();
for (Object o : array) {
assertTrue(itr.hasNext());
assertTrue(itr.hasNext()); // must be idempotent
assertSame(o, itr.next());
assertThrows(UnsupportedOperationException.class, itr::remove);
}
for (int i = 0; i < 3; i++) {
assertFalse(itr.hasNext());
assertThrows(NoSuchElementException.class, itr::next);
}
}
public static Object[][] arrays() {
return new Object[][] {
{ new Object[] { } },
{ new Object[] { 1 } },
{ new Object[] { null } },
{ new Object[] { null, 1 } },
{ new Object[] { 1, null } },
{ new Object[] { null, null } },
{ new Object[] { null, 1, 2 } },
{ new Object[] { 1, null, 2 } },
{ new Object[] { 1, 2, null } },
{ new Object[] { null, null, null } },
{ new Object[] { 1, 2, 3, null, 4 } },
{ new Object[] { "a", "a", "a", "a" } },
{ IntStream.range(0, 100).boxed().toArray() }
};
}
}

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2006, 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.
*/
/*
* @test
* @bug 5045582
* @summary arrays larger than 1<<30
* @author Martin Buchholz
*/
// A proper regression test for 5045582 requires too much memory.
// If you have a really big machine, run like this:
// java -Xms25g -Xmx25g Big 30
import java.util.*;
public class Big {
private static void realMain(String[] args) throws Throwable {
final int shift = intArg(args, 0, 10); // "30" is real test
final int tasks = intArg(args, 1, ~0); // all tasks
final int n = (1<<shift) + 47;
// To test byte arrays larger than 1<<30, you need 1600MB. Run like:
// java -Xms1600m -Xmx1600m Big 30 1
if ((tasks & 0x1) != 0) {
System.out.println("byte[]");
System.gc();
byte[] a = new byte[n];
a[0] = (byte) -44;
a[1] = (byte) -43;
a[n-2] = (byte) +43;
a[n-1] = (byte) +44;
for (int i : new int[] { 0, 1, n-2, n-1 })
try { equal(i, Arrays.binarySearch(a, a[i])); }
catch (Throwable t) { unexpected(t); }
for (int i : new int[] { n-2, n-1 })
try { equal(i, Arrays.binarySearch(a, n-5, n, a[i])); }
catch (Throwable t) { unexpected(t); }
a[n-19] = (byte) 45;
try { Arrays.sort(a, n-29, n); }
catch (Throwable t) { unexpected(t); }
equal(a[n-1], (byte) 45);
equal(a[n-2], (byte) 44);
equal(a[n-3], (byte) 43);
equal(a[n-4], (byte) 0);
}
// To test Object arrays larger than 1<<30, you need 13GB. Run like:
// java -Xms13g -Xmx13g Big 30 2
if ((tasks & 0x2) != 0) {
System.out.println("Integer[]");
System.gc();
Integer[] a = new Integer[n];
Integer ZERO = 0;
Arrays.fill(a, ZERO);
a[0] = -44;
a[1] = -43;
a[n-2] = +43;
a[n-1] = +44;
for (int i : new int[] { 0, 1, n-2, n-1 })
try { equal(i, Arrays.binarySearch(a, a[i])); }
catch (Throwable t) { unexpected(t); }
for (int i : new int[] { n-2, n-1 })
try { equal(i, Arrays.binarySearch(a, n-5, n, a[i])); }
catch (Throwable t) { unexpected(t); }
a[n-19] = 45;
try { Arrays.sort(a, n-29, n); }
catch (Throwable t) { unexpected(t); }
equal(a[n-1], 45);
equal(a[n-2], 44);
equal(a[n-3], 43);
equal(a[n-4], 0);
}
}
//--------------------- 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");}
static int intArg(String[] args, int i, int defaultValue) {
return args.length > i ? Integer.parseInt(args[i]) : defaultValue;}
}

View file

@ -0,0 +1,425 @@
/*
* Copyright (c) 2005, 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 4655503
* @summary Test for array cloning and slicing methods.
* @author John Rose
* @key randomness
*/
import java.util.*;
import java.lang.reflect.*;
public class CopyMethods {
static int muzzle; // if !=0, suppresses ("muzzles") messages
static int maxLen = 40; // maximum length of test arrays
static int shortStepsNear = 4; // interesting span near critical values
static int downShift = 3;
static int testCasesRun = 0;
static long consing = 0;
// very simple tests, mainly to test the framework itself
static void simpleTests() {
int[] a = (int[]) makeArray(3, int.class);
if (muzzle == 0)
System.out.println("int[] a = "+Arrays.toString(a));
check(a.length == 3);
check(a[0] == testValues[0]);
check(a[1] == testValues[1]);
check(a[2] == testValues[2]);
checkArray(a, int.class, 3, 0, 3);
// negative test of testing framework:
for (int bad = -2; bad < a.length; bad++) {
try {
int[] aa = a.clone();
if (bad < 0) aa = new int[4];
else aa[bad] = 0;
++muzzle;
// the following check should fail!
if (bad == -2)
checkArray(new String[3], int.class, 0, 0, a.length);
else
checkArray(aa, int.class, 0, 0, a.length);
throw new Error("Should Not Reach Here");
} catch (RuntimeException ee) {
--muzzle;
if (muzzle == 0)
System.out.println("Expected: "+ee);
}
}
checkArray(Arrays.copyOf(a, 0), int.class, 0, 0, 3);
checkArray(Arrays.copyOf(a, 1), int.class, 1, 0, 3);
checkArray(Arrays.copyOf(a, 2), int.class, 2, 0, 3);
checkArray(Arrays.copyOf(a, 3), int.class, 3, 0, 3);
checkArray(Arrays.copyOf(a, 4), int.class, 4, 0, 3);
// quick test of copyOfRange
int[] ar = Arrays.copyOfRange(a, 1, 3);
check(ar.length == 2);
check(ar[0] == a[1]);
check(ar[1] == a[2]);
checkArray(ar, int.class, 2, 1, 2);
ar = Arrays.copyOfRange(a, 2, 4);
check(ar.length == 2);
check(ar[0] == a[2]);
check(ar[1] == 0);
checkArray(ar, int.class, 2, 2, 1);
ar = Arrays.copyOfRange(a, 3, 5);
check(ar.length == 2);
check(ar[0] == 0);
check(ar[1] == 0);
checkArray(ar, int.class, 2, 3, 0);
byte[] ba = (byte[]) makeArray(3, byte.class);
if (muzzle == 0)
System.out.println("byte[] ba = "+Arrays.toString(ba));
for (int j = 0; j <= ba.length+2; j++) {
byte[] bb = Arrays.copyOf(ba, j);
if (muzzle == 0)
System.out.println("copyOf(ba,"+j+") = "+
Arrays.toString(bb));
checkArray(bb, byte.class, j, 0, ba.length);
byte[] bbr = Arrays.copyOfRange(ba, 0, j);
check(Arrays.equals(bb, bbr));
}
for (int i = 0; i <= a.length; i++) {
for (int j = i; j <= a.length+2; j++) {
byte[] br = Arrays.copyOfRange(ba, i, j);
if (muzzle == 0)
System.out.println("copyOfRange(ba,"+i+","+j+") = "+
Arrays.toString(br));
checkArray(br, byte.class, j-i, i, ba.length-i);
}
}
String[] sa = (String[]) makeArray(3, String.class);
if (muzzle == 0)
System.out.println("String[] sa = "+Arrays.toString(sa));
check(sa[0].equals(Integer.toHexString(testValues[0])));
check(sa[1].equals(Integer.toHexString(testValues[1])));
check(sa[2].equals(Integer.toHexString(testValues[2])));
checkArray(sa, String.class, sa.length, 0, sa.length);
String[] sa4 = Arrays.copyOf(sa, sa.length+1);
check(sa4[0] == sa[0]);
check(sa4[1] == sa[1]);
check(sa4[2] == sa[2]);
check(sa4[sa.length] == null);
checkArray(sa4, String.class, sa4.length, 0, sa.length);
String[] sr4 = Arrays.copyOfRange(sa, 1, 5);
check(sr4[0] == sa[1]);
check(sr4[1] == sa[2]);
check(sr4[2] == null);
check(sr4[3] == null);
checkArray(sr4, String.class, 4, 1, sa.length-1);
if (muzzle == 0)
System.out.println("simpleTests done");
}
// the framework: a fixed series of test values
static final int[] testValues;
static {
testValues = new int[1000];
Random r = new Random();
for (int i = 0; i < testValues.length; i++) {
testValues[i] = r.nextInt();
}
}
/** Return a canonical test value of a desired index and type.
* The original test values are random ints. Derive other test
* values as follows:
* <pre>
* int tv = testValues[i]
* (C)tv C is byte, short, char, long, float, double
* (tv&1)!=0 C is boolean
* (Integer)tv C is Object and tv%16 != 0
* null C is Object and tv%16 == 0
* Integer.toHexString(tv) C is String and tv != 0
* null C is String and tv == 0
* </pre>
* are derived by ordinary Java coercions, except that boolean
* samples the LSB of the int value, and String is the hex numeral.
*
* (Also, the 0th String is null, and the 0th Object mod 16 is null,
* regardless of the original int test value.)
*/
static Object testValue(int i, Class<?> c) {
int tv = testValues[i % testValues.length];
if (i >= testValues.length) tv ^= i;
// Turn the canonical int to a float, boolean, String, whatever:
return invoke(coercers.get(c), tv);
}
/** Build a test array of the given length,
* packed with a subsequence of the test values.
* The first element of the array is always testValue(0).
*/
static Object makeArray(int len, Class<?> c) {
Object a = Array.newInstance(c, len);
for (int i = 0; i < len; i++) {
Array.set(a, i, testValue(i, c));
}
return a;
}
/** Check that the given array has the required length.
* Check also that it is packed, up to firstNull, with
* a particular subsequence of the canonical test values.
* The subsequence must begin with a[0] == testValue(offset).
* At a[firstNull] and beyond, the array must contain null values.
*/
static void checkArray(Object a, Class<?> c, int requiredLen, int offset, int firstNull) {
check(c == a.getClass().getComponentType());
Object nullValue = nullValues.get(c);
// Note: asserts in here are not part of the test program.
// They verify the integrity of the test method itself.
assert(nullValues.containsKey(c));
int misses = 0;
int firstMiss = -1;
// Check required length first.
int length = Array.getLength(a);
if (length != requiredLen && requiredLen != -1) {
if (muzzle == 0)
System.out.println("*** a.length = "+length+" != "+requiredLen);
++misses;
}
for (int i = 0; i < length; i++) {
Object tv = (i >= firstNull) ? nullValue : testValue(i+offset, c);
Object ai = Array.get(a, i);
if (!eq(ai, tv)) {
if (muzzle == 0)
System.out.println("*** a["+i+"] = "+ai+" != "+tv);
if (misses == 0) firstMiss = i;
if (++misses > 10) break;
}
}
if (misses != 0) {
Method toString = toStrings.get(c);
if (toString == null) toString = toStrings.get(Object.class);
throw new RuntimeException("checkArray failed at "+firstMiss
+" "+c+"[]"
+" : "+invoke(toString, a));
}
}
// Typical comparison helper. Why isn't this a method somewhere.
static boolean eq(Object x, Object y) {
return x == null? y == null: x.equals(y);
}
// Exception-ignoring invoke function.
static Object invoke(Method m, Object... args) {
Exception ex;
try {
return m.invoke(null, args);
} catch (InvocationTargetException ee) {
ex = ee;
} catch (IllegalAccessException ee) {
ex = ee;
} catch (IllegalArgumentException ee) {
ex = ee;
}
ArrayList<Object> call = new ArrayList<Object>();
call.add(m); Collections.addAll(call, args);
throw new RuntimeException(call+" : "+ex);
}
// version of assert() that runs unconditionally
static void check(boolean z) {
if (!z) throw new RuntimeException("check failed");
}
/** Run about 10**5 distinct parameter combinations
* on copyOf and copyOfRange. Use all primitive types,
* and String and Object.
* Try to all critical values, looking for fencepost errors.
*/
static void fullTests(int maxLen, Class<?> c) {
Method cloner = cloners.get(c);
assert(cloner != null) : c;
Method cloneRanger = cloneRangers.get(c);
// Note: asserts in here are not part of the test program.
// They verify the integrity of the test method itself.
assert(cloneRanger != null) : c;
for (int src = 0; src <= maxLen; src = inc(src, 0, maxLen)) {
Object a = makeArray(src, c);
for (int x : new ArrayList<Integer>()) {}
for (int j = 0; j <= maxLen; j = inc(j, src, maxLen)) {
// b = Arrays.copyOf(a, j);
Object b = invoke(cloner, a, j);
checkArray(b, c, j, 0, src);
testCasesRun++;
consing += j;
int maxI = Math.min(src, j);
for (int i = 0; i <= maxI; i = inc(i, src, maxI)) {
// r = Arrays.copyOfRange(a, i, j);
Object r = invoke(cloneRanger, a, i, j);
checkArray(r, c, j-i, i, src-i);
//System.out.println("case c="+c+" src="+src+" i="+i+" j="+j);
testCasesRun++;
consing += j-i;
}
}
}
}
// Increment x by at least one. Increment by a little more unless
// it is near a critical value, either zero, crit1, or crit2.
static int inc(int x, int crit1, int crit2) {
int D = shortStepsNear;
if (crit1 > crit2) { int t = crit1; crit1 = crit2; crit2 = t; }
assert(crit1 <= crit2);
assert(x <= crit2); // next1 or next2 must be the limit value
x += 1;
if (x > D) {
if (x < crit1-D) {
x += (x << 1) >> downShift; // giant step toward crit1-D
if (x > crit1-D) x = crit1-D;
} else if (x >= crit1+D && x < crit2-D) {
x += (x << 1) >> downShift; // giant step toward crit2-D
if (x > crit2-D) x = crit2-D;
}
}
return x;
}
public static void main(String[] av) {
boolean verbose = (av.length != 0);
muzzle = (verbose? 0: 1);
if (muzzle == 0)
System.out.println("test values: "+Arrays.toString(Arrays.copyOf(testValues, 5))+"...");
simpleTests();
muzzle = 0; // turn on print statements (affects failures only)
fullTests();
if (verbose)
System.out.println("ran "+testCasesRun+" tests, avg len="
+(float)consing/testCasesRun);
// test much larger arrays, more sparsely
maxLen = 500;
shortStepsNear = 2;
downShift = 0;
testCasesRun = 0;
consing = 0;
fullTests();
if (verbose)
System.out.println("ran "+testCasesRun+" tests, avg len="
+(float)consing/testCasesRun);
}
static void fullTests() {
for (Class<?> c : allTypes) {
fullTests(maxLen, c);
}
}
// We must run all the our tests on each of 8 distinct primitive types,
// and two reference types (Object, String) for good measure.
// This would be a pain to write out by hand, statically typed.
// So, use reflection. Following are the tables of methods we use.
// (The initial simple tests exercise enough of the static typing
// features of the API to ensure that they compile as advertised.)
static Object coerceToObject(int x) { return (x & 0xF) == 0? null: new Integer(x); }
static String coerceToString(int x) { return (x == 0)? null: Integer.toHexString(x); }
static Integer coerceToInteger(int x) { return (x == 0)? null: x; }
static byte coerceToByte(int x) { return (byte)x; }
static short coerceToShort(int x) { return (short)x; }
static int coerceToInt(int x) { return x; }
static long coerceToLong(int x) { return x; }
static char coerceToChar(int x) { return (char)x; }
static float coerceToFloat(int x) { return x; }
static double coerceToDouble(int x) { return x; }
static boolean coerceToBoolean(int x) { return (x&1) != 0; }
static Integer[] copyOfIntegerArray(Object[] a, int len) {
// This guy exercises the API based on a type-token.
// Note the static typing.
return Arrays.copyOf(a, len, Integer[].class);
}
static Integer[] copyOfIntegerArrayRange(Object[] a, int m, int n) {
// This guy exercises the API based on a type-token.
// Note the static typing.
return Arrays.copyOfRange(a, m, n, Integer[].class);
}
static final List<Class<?>> allTypes
= Arrays.asList(new Class<?>[]
{ Object.class, String.class, Integer.class,
byte.class, short.class, int.class, long.class,
char.class, float.class, double.class,
boolean.class
});
static final HashMap<Class<?>,Method> coercers;
static final HashMap<Class<?>,Method> cloners;
static final HashMap<Class<?>,Method> cloneRangers;
static final HashMap<Class<?>,Method> toStrings;
static final HashMap<Class<?>,Object> nullValues;
static {
coercers = new HashMap<Class<?>,Method>();
Method[] testMethods = CopyMethods.class.getDeclaredMethods();
Method cia = null, ciar = null;
for (int i = 0; i < testMethods.length; i++) {
Method m = testMethods[i];
if (!Modifier.isStatic(m.getModifiers())) continue;
Class<?> rt = m.getReturnType();
if (m.getName().startsWith("coerceTo") && allTypes.contains(rt))
coercers.put(m.getReturnType(), m);
if (m.getName().equals("copyOfIntegerArray"))
cia = m;
if (m.getName().equals("copyOfIntegerArrayRange"))
ciar = m;
}
Method[] arrayMethods = Arrays.class.getDeclaredMethods();
cloners = new HashMap<Class<?>,Method>();
cloneRangers = new HashMap<Class<?>,Method>();
toStrings = new HashMap<Class<?>,Method>();
for (int i = 0; i < arrayMethods.length; i++) {
Method m = arrayMethods[i];
if (!Modifier.isStatic(m.getModifiers())) continue;
Class<?> rt = m.getReturnType();
if (m.getName().equals("copyOf")
&& m.getParameterTypes().length == 2)
cloners.put(rt.getComponentType(), m);
if (m.getName().equals("copyOfRange")
&& m.getParameterTypes().length == 3)
cloneRangers.put(rt.getComponentType(), m);
if (m.getName().equals("toString")) {
Class<?> pt = m.getParameterTypes()[0];
toStrings.put(pt.getComponentType(), m);
}
}
cloners.put(String.class, cloners.get(Object.class));
cloneRangers.put(String.class, cloneRangers.get(Object.class));
assert(cia != null);
cloners.put(Integer.class, cia);
assert(ciar != null);
cloneRangers.put(Integer.class, ciar);
nullValues = new HashMap<Class<?>,Object>();
for (Class<?> c : allTypes) {
nullValues.put(c, invoke(coercers.get(c), 0));
}
}
}

View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2002, 2026, 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 4726380 8037097
* @summary Check that different sorts give equivalent results.
* @key randomness
* @run junit Correct
*/
import java.util.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class Correct {
static final Random rnd = new Random();
static final int ITERATIONS = 1000;
static final int TEST_SIZE = 1000;
@Test
public void testDefaultSort() {
for (int i=0; i<ITERATIONS; i++) {
int size = rnd.nextInt(TEST_SIZE) + 1;
Integer[] array1 = getIntegerArray(size);
Integer[] array2 = Arrays.copyOf(array1, array1.length);
Arrays.sort(array1, array1.length/3, array1.length/2);
stupidSort(array2, array2.length/3, array2.length/2);
Assertions.assertArrayEquals(array2, array1, "Arrays did not match. size=" + size);
}
}
@ParameterizedTest
@MethodSource("comparators")
public void testComparatorSort(Comparator<Integer> comparator) {
for (int i=0; i<ITERATIONS; i++) {
int size = rnd.nextInt(TEST_SIZE) + 1;
Integer[] array1 = getIntegerArray(size);
Integer[] array2 = Arrays.copyOf(array1, array1.length);
Arrays.sort(array1, array1.length/3, array1.length/2, comparator);
stupidSort(array2, array2.length/3, array2.length/2, comparator);
Assertions.assertArrayEquals(array2, array1, "Arrays did not match. size=" + size);
}
}
static Integer[] getIntegerArray(int size) {
Integer[] blah = new Integer[size];
for (int x=0; x<size; x++) {
blah[x] = new Integer(rnd.nextInt());
}
return blah;
}
static void stupidSort(Integer[] a1, int from, int to) {
if (from > to - 1 )
return;
for (int x=from; x<to; x++) {
Integer lowest = a1[x];
int lowestIndex = x;
for (int y=x + 1; y<to; y++) {
if (((Comparable)a1[y]).compareTo((Comparable)lowest) < 0) {
lowest = a1[y];
lowestIndex = y;
}
}
if (lowestIndex != x) {
swap(a1, x, lowestIndex);
}
}
}
static void stupidSort(Integer[] a1, int from, int to, Comparator<Integer> comparator) {
if (from > to - 1 )
return;
for (int x=from; x<to; x++) {
Integer lowest = a1[x];
int lowestIndex = x;
for (int y=x + 1; y<to; y++) {
if (comparator.compare(a1[y], lowest) < 0) {
lowest = a1[y];
lowestIndex = y;
}
}
if (lowestIndex != x) {
swap(a1, x, lowestIndex);
}
}
}
static <T> void swap(T[] x, int a, int b) {
T t = x[a];
x[a] = x[b];
x[b] = t;
}
public static Iterator<Object[]> comparators() {
Object[][] comparators = new Object[][] {
new Object[] { Comparator.naturalOrder() },
new Object[] { Comparator.<Integer>naturalOrder().reversed() },
new Object[] { STANDARD_ORDER },
new Object[] { STANDARD_ORDER.reversed() },
new Object[] { REVERSE_ORDER },
new Object[] { REVERSE_ORDER.reversed() },
new Object[] { Comparator.comparingInt(Integer::intValue) }
};
return Arrays.asList(comparators).iterator();
}
private static final Comparator<Integer> STANDARD_ORDER = new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
private static final Comparator<Integer> REVERSE_ORDER = new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return - o1.compareTo(o2);
}
};
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2005, 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 4229892
* @summary Arrays.fill(Object[], ...) should throw ArrayStoreException
* @author Martin Buchholz
*/
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class Fill {
private static void realMain(String[] args) throws Throwable {
try {
Arrays.fill(new Integer[3], "foo");
fail("Expected ArrayStoreException");
}
catch (ArrayStoreException e) { pass(); }
catch (Throwable t) { unexpected(t); }
try {
Arrays.fill(new Integer[3], 0, 2, "foo");
fail("Expected ArrayStoreException");
}
catch (ArrayStoreException e) { pass(); }
catch (Throwable t) { unexpected(t); }
try {
Arrays.fill(new Integer[3], 0, 4, "foo");
fail("Expected ArrayIndexOutOfBoundsException");
}
catch (ArrayIndexOutOfBoundsException e) { pass(); }
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");}
}

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 1998, 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
* @bug 4143272 6548425
* @summary The natural ordering on Float and Double was not even a partial
* order (i.e., it violated the contract of Comparable.compareTo).
* Now it's a total ordering. Arrays.sort(double[])
* and Arrays.sort(double[]) reflect the new ordering. Also,
* Arrays.equals(double[], double[]) and
* Arrays.equals(float[], float[]) reflect the definition of
* equality used by Float and Double.
*/
import java.util.*;
@SuppressWarnings("unchecked")
public class FloatDoubleOrder {
void test(String[] args) throws Throwable {
double[] unsortedDbl = new double[] {1.0d, 3.7d, Double.NaN, -2.0d,
Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0d, -0.0d};
double[] sortedDbl = new double[] {Double.NEGATIVE_INFINITY, -2.0d,
-0.0d, 0.0d, 1.0d, 3.7d, Double.POSITIVE_INFINITY, Double.NaN};
List list = new ArrayList();
for (int i=0; i<unsortedDbl.length; i++)
list.add(new Double(unsortedDbl[i]));
Collections.sort(list);
List sortedList = new ArrayList();
for (int i=0; i<sortedDbl.length; i++)
sortedList.add(new Double(sortedDbl[i]));
check(list.equals(sortedList));
Arrays.sort(unsortedDbl);
check(Arrays.equals(unsortedDbl, sortedDbl));
double negNan = Double.longBitsToDouble(0xfff8000000000000L);
for (int i = 0; i < sortedDbl.length; i++) {
equal(Arrays.binarySearch(sortedDbl, sortedDbl[i]), i);
if (Double.isNaN(sortedDbl[i]))
equal(Arrays.binarySearch(sortedDbl, negNan), i);
}
float[] unsortedFlt = new float[] {1.0f, 3.7f, Float.NaN, -2.0f,
Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, 0.0f, -0.0f};
float[] sortedFlt = new float[] {Float.NEGATIVE_INFINITY, -2.0f,
-0.0f, 0.0f, 1.0f, 3.7f, Float.POSITIVE_INFINITY, Float.NaN};
list.clear();
for (int i=0; i<unsortedFlt.length; i++)
list.add(new Float(unsortedFlt[i]));
Collections.sort(list);
sortedList.clear();
for (int i=0; i<sortedFlt.length; i++)
sortedList.add(new Float(sortedFlt[i]));
check(list.equals(sortedList));
Arrays.sort(unsortedFlt);
check(Arrays.equals(unsortedFlt, sortedFlt));
float negNaN = Float.intBitsToFloat(0xFfc00000);
for (int i = 0; i < sortedDbl.length; i++) {
equal(Arrays.binarySearch(sortedFlt, sortedFlt[i]), i);
if (Float.isNaN(sortedFlt[i]))
equal(Arrays.binarySearch(sortedFlt, negNaN), i);
}
// 6548425: Arrays.sort incorrectly sorts a double array
// containing negative zeros
double[] da = {-0.0d, -0.0d, 0.0d, -0.0d};
Arrays.sort(da, 1, 4);
check(Arrays.equals(da, new double[] {-0.0d, -0.0d, -0.0d, 0.0d}));
float[] fa = {-0.0f, -0.0f, 0.0f, -0.0f};
Arrays.sort(fa, 1, 4);
check(Arrays.equals(fa, new float[] {-0.0f, -0.0f, -0.0f, 0.0f}));
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
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 {
new FloatDoubleOrder().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(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");}
}

View file

@ -0,0 +1,174 @@
/*
* Copyright (c) 2022, 2024, Oracle, Inc. 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 Basic array hashCode functionality
* @run main/othervm --add-exports java.base/jdk.internal.util=ALL-UNNAMED
* --add-opens java.base/jdk.internal.util=ALL-UNNAMED -Xcomp -Xbatch HashCode
*/
import java.lang.reflect.Method;
import java.util.Arrays;
public class HashCode {
private static String[] tests = { "", " ", "a", "abcdefg",
"It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only. -- Charles Dickens, Tale of Two Cities",
"C'était le meilleur des temps, c'était le pire des temps, c'était l'âge de la sagesse, c'était l'âge de la folie, c'était l'époque de la croyance, c'était l'époque de l'incrédulité, c'était la saison de la Lumière, c'était C'était la saison des Ténèbres, c'était le printemps de l'espoir, c'était l'hiver du désespoir, nous avions tout devant nous, nous n'avions rien devant nous, nous allions tous directement au Ciel, nous allions tous directement dans l'autre sens bref, la période ressemblait tellement à la période actuelle, que certaines de ses autorités les plus bruyantes ont insisté pour qu'elle soit reçue, pour le bien ou pour le mal, au degré superlatif de la comparaison seulement. -- Charles Dickens, Tale of Two Cities (in French)",
"禅道修行を志した雲水は、一般に参禅のしきたりを踏んだうえで一人の師につき、各地にある専門道場と呼ばれる養成寺院に入門し、与えられた公案に取り組むことになる。公案は、師家(老師)から雲水が悟りの境地へと進んで行くために手助けとして課す問題であり、悟りの境地に達していない人には容易に理解し難い難問だが、屁理屈や詭弁が述べられているわけではなく、頓知や謎かけとも異なる。"
};
byte[][] zeroes = new byte[64][];
private static byte[][] testBytes = new byte[tests.length][];
private static short[][] testShorts = new short[tests.length][];
private static char[][] testChars = new char[tests.length][];
private static int[][] testInts = new int[tests.length][];
private static int[] expected = { 1, 63, 128, 536518979, -1174896354, -1357593156, 428276276};
private static int[] expectedUnsigned = { 1, 63, 128, 536518979, -1174896354, 584369596, -2025326028};
public static void main(String[] args) throws Exception {
// Deep introspection into range-based hash functions
Class<?> arraysSupport = Class.forName("jdk.internal.util.ArraysSupport");
Method vectorizedHashCode = arraysSupport.getDeclaredMethod("vectorizedHashCode", Object.class, int.class, int.class, int.class, int.class);
vectorizedHashCode.setAccessible(true);
for (int i = 0; i < tests.length; i++) {
testBytes[i] = tests[i].getBytes("UTF-8");
int len = testBytes[i].length;
testChars[i] = new char[len];
testShorts[i] = new short[len];
testInts[i] = new int[len];
for (int j = 0; j < len; j++) {
testChars[i][j] = (char) testBytes[i][j];
testShorts[i][j] = testBytes[i][j];
testInts[i][j] = testBytes[i][j];
}
}
boolean failed = false;
try {
int zeroResult = 1;
for (int i = 0; i < 64; i++) {
byte[] zeroes = new byte[i];
byte[] extraZeroes = new byte[i + 47];
for (int j = 0; j < 10_000; j++) {
int hashCode = Arrays.hashCode(zeroes);
if (hashCode != zeroResult) {
throw new RuntimeException("byte[] \"" + Arrays.toString(zeroes) + "\": "
+ " e = " + zeroResult
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
hashCode = (int) vectorizedHashCode.invoke(null, extraZeroes, 17, i, 1, /* ArraysSupport.T_BYTE */ 8);
if (hashCode != zeroResult) {
throw new RuntimeException("byte[] subrange \"" + Arrays.toString(extraZeroes)
+ "\" at offset 17, limit " + i + ": "
+ " e = " + zeroResult
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
zeroResult *= 31;
}
for (int i = 0; i < tests.length; i++) {
for (int j = 0; j < 64; j++) {
int e = expected[i];
int hashCode = Arrays.hashCode(testBytes[i]);
if (hashCode != e) {
throw new RuntimeException("byte[] \"" + Arrays.toString(testBytes[i]) + "\": "
+ " e = " + e
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
}
System.out.println("byte[] tests passed");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
failed = true;
}
try {
for (int i = 0; i < tests.length; i++) {
for (int j = 0; j < 64; j++) {
int e = expected[i];
int hashCode = Arrays.hashCode(testShorts[i]);
if (hashCode != e) {
throw new RuntimeException("short[] \"" + Arrays.toString(testShorts[i]) + "\": "
+ " e = " + e
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
}
System.out.println("short[] tests passed");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
failed = true;
}
try {
for (int i = 0; i < tests.length; i++) {
for (int j = 0; j < 64; j++) {
int e = expected[i];
int hashCode = Arrays.hashCode(testInts[i]);
if (hashCode != e) {
throw new RuntimeException("int[] \"" + Arrays.toString(testInts[i]) + "\": "
+ " e = " + e
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
}
System.out.println("int[] tests passed");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
failed = true;
}
try {
for (int i = 0; i < tests.length; i++) {
for (int j = 0; j < 64; j++) {
int e = expectedUnsigned[i];
int hashCode = Arrays.hashCode(testChars[i]);
if (hashCode != e) {
throw new RuntimeException("char[] \"" + Arrays.toString(testChars[i]) + "\": "
+ " e = " + e
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
}
System.out.println("char[] tests passed");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
failed = true;
}
if (failed) {
throw new RuntimeException("Some tests failed");
}
}
}

View file

@ -0,0 +1,282 @@
/*
* Copyright (c) 2013, 2026, 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 8012650
* @summary Unit test for setAll, parallelSetAll variants
* @run junit SetAllTest
*/
import java.util.Arrays;
import java.util.function.IntFunction;
import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction;
import java.util.function.IntUnaryOperator;
import org.junit.jupiter.api.Assertions;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class SetAllTest {
private static final IntFunction<String> toString = i -> "N" + Integer.valueOf(i);
private static final IntFunction<String> fillString = i -> "X";
private static final String[] r0 = {};
private static final String[] r1 = { "N0" };
private static final String[] r10 = { "N0", "N1", "N2", "N3", "N4", "N5", "N6", "N7", "N8", "N9" };
private Object[][] stringData = new Object[][] {
{ "empty", 0, toString, r0 },
{ "one", 1, toString, r1 },
{ "ten", 10, toString, r10 },
{ "fill", 3, fillString, new String[] { "X", "X", "X" }}
};
private static final IntUnaryOperator toInt = i -> i << 1;
private static final IntUnaryOperator fillInt = i -> 99;
private static final int[] ir0 = {};
private static final int[] ir1 = { 0 };
private static final int[] ir10 = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 };
private Object[][] intData = new Object[][] {
{ "empty", 0, toInt, ir0 },
{ "one", 1, toInt, ir1 },
{ "ten", 10, toInt, ir10 },
{ "fill", 3, fillInt, new int[] { 99, 99, 99 }}
};
private static final IntToLongFunction toLong = i -> i << 1;
private static final IntToLongFunction fillLong = i -> 9999L;
private static final long[] lr0 = {};
private static final long[] lr1 = { 0L };
private static final long[] lr10 = { 0L, 2L, 4L, 6L, 8L, 10L, 12L, 14L, 16L, 18L };
private Object[][] longData = new Object[][] {
{ "empty", 0, toLong, lr0 },
{ "one", 1, toLong, lr1 },
{ "ten", 10, toLong, lr10 },
{ "fill", 3, fillLong, new long[] { 9999L, 9999L, 9999L }}
};
private static final IntToDoubleFunction toDouble = i -> i * 1.1;
private static final IntToDoubleFunction fillDouble = i -> 3.14;
private static final double[] dr0 = {};
private static final double[] dr1 = { 0.0 };
private static final double[] dr10 = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
private Object[][] doubleData = new Object[][] {
{ "empty", 0, toDouble, dr0 },
{ "one", 1, toDouble, dr1 },
{ "ten", 10, toDouble, dr10 },
{ "fill", 3, fillDouble, new double[] { 3.14, 3.14, 3.14 }}
};
public Object[][] stringTests() { return stringData; }
public Object[][] intTests() { return intData; }
public Object[][] longTests() { return longData; }
public Object[][] doubleTests() { return doubleData; }
@ParameterizedTest
@MethodSource("stringTests")
public void testSetAllString(String name, int size, IntFunction<String> generator, String[] expected) {
String[] result = new String[size];
Arrays.setAll(result, generator);
Assertions.assertArrayEquals(expected, result, "setAll(String[], IntFunction<String>) case " + name + " failed.");
// ensure fresh array
result = new String[size];
Arrays.parallelSetAll(result, generator);
Assertions.assertArrayEquals(expected, result, "parallelSetAll(String[], IntFunction<String>) case " + name + " failed.");
}
@ParameterizedTest
@MethodSource("intTests")
public void testSetAllInt(String name, int size, IntUnaryOperator generator, int[] expected) {
int[] result = new int[size];
Arrays.setAll(result, generator);
Assertions.assertArrayEquals(expected, result, "setAll(int[], IntUnaryOperator) case " + name + " failed.");
// ensure fresh array
result = new int[size];
Arrays.parallelSetAll(result, generator);
Assertions.assertArrayEquals(expected, result, "parallelSetAll(int[], IntUnaryOperator) case " + name + " failed.");
}
@ParameterizedTest
@MethodSource("longTests")
public void testSetAllLong(String name, int size, IntToLongFunction generator, long[] expected) {
long[] result = new long[size];
Arrays.setAll(result, generator);
Assertions.assertArrayEquals(expected, result, "setAll(long[], IntToLongFunction) case " + name + " failed.");
// ensure fresh array
result = new long[size];
Arrays.parallelSetAll(result, generator);
Assertions.assertArrayEquals(expected, result, "parallelSetAll(long[], IntToLongFunction) case " + name + " failed.");
}
private void assertDoubleArrayEquals(double[] actual, double[] expected, double delta, String msg) {
if (actual.length != expected.length) {
fail(msg + ": length mismatch, expected " + expected.length + ", got " + actual.length);
}
for (int i = 0; i < actual.length; i++) {
assertEquals(actual[i], expected[i], delta, msg + "(mismatch at index " + i + ")");
}
}
@ParameterizedTest
@MethodSource("doubleTests")
public void testSetAllDouble(String name, int size, IntToDoubleFunction generator, double[] expected) {
double[] result = new double[size];
Arrays.setAll(result, generator);
assertDoubleArrayEquals(result, expected, 0.05, "setAll(double[], IntToDoubleFunction) case " + name + " failed.");
// ensure fresh array
result = new double[size];
Arrays.parallelSetAll(result, generator);
assertDoubleArrayEquals(result, expected, 0.05, "setAll(double[], IntToDoubleFunction) case " + name + " failed.");
}
@Test
public void testStringSetNulls() {
String[] ar = new String[2];
try {
Arrays.setAll(null, (IntFunction<String>) i -> "X");
fail("Arrays.setAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(null, (IntFunction<String>) i -> "X");
fail("Arrays.parallelSetAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.setAll(ar, null);
fail("Arrays.setAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(ar, null);
fail("Arrays.parallelSetAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
}
@Test
public void testIntSetNulls() {
int[] ar = new int[2];
try {
Arrays.setAll(null, (IntUnaryOperator) i -> i);
fail("Arrays.setAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(null, (IntUnaryOperator) i -> i);
fail("Arrays.parallelSetAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.setAll(ar, null);
fail("Arrays.setAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(ar, null);
fail("Arrays.parallelSetAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
}
@Test
public void testLongSetNulls() {
long[] ar = new long[2];
try {
Arrays.setAll(null, (IntToLongFunction) i -> Long.MAX_VALUE);
fail("Arrays.setAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(null, (IntToLongFunction) i -> Long.MAX_VALUE);
fail("Arrays.parallelSetAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.setAll(ar, null);
fail("Arrays.setAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(ar, null);
fail("Arrays.parallelSetAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
}
@Test
public void testDoubleSetNulls() {
double[] ar = new double[2];
try {
Arrays.setAll(null, (IntToDoubleFunction) i -> Math.E);
fail("Arrays.setAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(null, (IntToDoubleFunction) i -> Math.E);
fail("Arrays.parallelSetAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.setAll(ar, null);
fail("Arrays.setAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(ar, null);
fail("Arrays.parallelSetAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,708 @@
/*
* Copyright 2015 Goldman Sachs.
* Copyright (c) 2015, 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 org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
public class SortingIntBenchmarkTestJMH {
private static final int QUICKSORT_THRESHOLD = 286;
private static final int MAX_RUN_COUNT = 67;
private static final int INSERTION_SORT_THRESHOLD = 47;
public static final int MAX_VALUE = 1_000_000;
@Param({"pairFlipZeroPairFlip", "pairFlipOneHundredPairFlip"
, "zeroHi", "hiZeroLow", "hiFlatLow", "identical",
"randomDups", "randomNoDups", "sortedReversedSorted", "pairFlip", "endLessThan"})
public String listType;
private int[] array;
private static final int LIST_SIZE = 10_000_000;
public static final int NUMBER_OF_ITERATIONS = 10;
@Setup
public void setUp() {
Random random = new Random(123456789012345L);
this.array = new int[LIST_SIZE];
int threeQuarters = (int) (LIST_SIZE * 0.75);
if ("zeroHi".equals(this.listType)) {
for (int i = 0; i < threeQuarters; i++) {
this.array[i] = 0;
}
int k = 1;
for (int i = threeQuarters; i < LIST_SIZE; i++) {
this.array[i] = k;
k++;
}
}
else if ("hiFlatLow".equals(this.listType)) {
int oneThird = LIST_SIZE / 3;
for (int i = 0; i < oneThird; i++) {
this.array[i] = i;
}
int twoThirds = oneThird * 2;
int constant = oneThird - 1;
for (int i = oneThird; i < twoThirds; i++) {
this.array[i] = constant;
}
for (int i = twoThirds; i < LIST_SIZE; i++) {
this.array[i] = constant - i + twoThirds;
}
}
else if ("hiZeroLow".equals(this.listType)) {
int oneThird = LIST_SIZE / 3;
for (int i = 0; i < oneThird; i++) {
this.array[i] = i;
}
int twoThirds = oneThird * 2;
for (int i = oneThird; i < twoThirds; i++) {
this.array[i] = 0;
}
for (int i = twoThirds; i < LIST_SIZE; i++) {
this.array[i] = oneThird - i + twoThirds;
}
}
else if ("identical".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = 0;
}
}
else if ("randomDups".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = random.nextInt(1000);
}
}
else if ("randomNoDups".equals(this.listType)) {
Set<Integer> set = new HashSet();
while (set.size() < LIST_SIZE + 1) {
set.add(random.nextInt());
}
List<Integer> list = new ArrayList<>(LIST_SIZE);
list.addAll(set);
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = list.get(i);
}
}
else if ("sortedReversedSorted".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE / 2; i++) {
this.array[i] = i;
}
int num = 0;
for (int i = LIST_SIZE / 2; i < LIST_SIZE; i++) {
this.array[i] = LIST_SIZE - num;
num++;
}
}
else if ("pairFlip".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = i;
}
for (int i = 0; i < LIST_SIZE; i += 2) {
int temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
}
else if ("endLessThan".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE - 1; i++) {
this.array[i] = 3;
}
this.array[LIST_SIZE - 1] = 1;
}
else if ("pairFlipZeroPairFlip".equals(this.listType)) {
//pairflip
for (int i = 0; i < 64; i++) {
this.array[i] = i;
}
for (int i = 0; i < 64; i += 2) {
int temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
//zero
for (int i = 64; i < this.array.length - 64; i++) {
this.array[i] = 0;
}
//pairflip
for (int i = this.array.length - 64; i < this.array.length; i++) {
this.array[i] = i;
}
for (int i = this.array.length - 64; i < this.array.length; i += 2) {
int temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
}
else if ("pairFlipOneHundredPairFlip".equals(this.listType)) {
//10, 5
for (int i = 0; i < 64; i++) {
if (i % 2 == 0) {
this.array[i] = 10;
}
else {
this.array[i] = 5;
}
}
//100
for (int i = 64; i < this.array.length - 64; i++) {
this.array[i] = 100;
}
//10, 5
for (int i = this.array.length - 64; i < this.array.length; i++) {
if (i % 2 == 0) {
this.array[i] = 10;
}
else {
this.array[i] = 5;
}
}
}
}
@Warmup(iterations = 20)
@Measurement(iterations = 10)
@Benchmark
public void sortNewWay() {
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
SortingIntTestJMH.sort(this.array, 0, this.array.length - 1, null, 0, 0);
}
}
@Warmup(iterations = 20)
@Measurement(iterations = 10)
@Benchmark
public void sortCurrentWay() {
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
Arrays.sort(this.array);
}
}
static void sort(int[] a, int left, int right,
int[] work, int workBase, int workLen) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
SortingIntTestJMH.sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT + 1];
int count = 0;
run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
while (k < right && a[k] == a[k + 1])
k++;
if (k == right) break;
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]) ;
}
else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]) ;
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
int t = a[lo];
a[lo] = a[hi];
a[hi] = t;
}
}
if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
count--;
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
// Implementation note: variable "right" is increased by 1.
if (run[count] == right++) {
run[++count] = right;
}
if (count <= 1) { // The array is already sorted
return;
}
// Determine alternation base for merge
byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1) {
}
// Use or create temporary array b for merging
int[] b; // temp array; alternates with a
int ao, bo; // array offsets from 'left'
int blen = right - left; // space needed for b
if (work == null || workLen < blen || workBase + blen > work.length) {
work = new int[blen];
workBase = 0;
}
if (odd == 0) {
System.arraycopy(a, left, work, workBase, blen);
b = a;
bo = 0;
a = work;
ao = workBase - left;
}
else {
b = work;
ao = 0;
bo = workBase - left;
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
b[i + bo] = a[p++ + ao];
}
else {
b[i + bo] = a[q++ + ao];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i + bo] = a[i + ao]
) {
}
run[++last] = right;
}
int[] t = a;
a = b;
b = t;
int o = ao;
ao = bo;
bo = o;
}
}
private static void sort(int[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
// Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) {
/*
* Traditional (without sentinel) insertion sort,
* optimized for server VM, is used in case of
* the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
int ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left) {
break;
}
}
a[j + 1] = ai;
}
}
else {
/*
* Skip the longest ascending sequence.
*/
do {
if (left >= right) {
return;
}
}
while (a[++left] >= a[left - 1]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the more optimized algorithm, so called pair insertion
* sort, which is faster (in the context of Quicksort)
* than traditional implementation of insertion sort.
*/
for (int k = left; ++left <= right; k = ++left) {
int a1 = a[k], a2 = a[left];
if (a1 < a2) {
a2 = a1;
a1 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
int last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
}
return;
}
// Inexpensive approximation of length / 7
int seventh = (length >> 3) + (length >> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
* center element in the range. These elements will be used for
* pivot selection as described below. The choice for spacing
* these elements was empirically determined to work well on
* a wide variety of inputs.
*/
int e3 = (left + right) >>> 1; // The midpoint
int e2 = e3 - seventh;
int e1 = e2 - seventh;
int e4 = e3 + seventh;
int e5 = e4 + seventh;
// Sort these elements using insertion sort
if (a[e2] < a[e1]) {
int t = a[e2];
a[e2] = a[e1];
a[e1] = t;
}
if (a[e3] < a[e2]) {
int t = a[e3];
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
if (a[e4] < a[e3]) {
int t = a[e4];
a[e4] = a[e3];
a[e3] = t;
if (t < a[e2]) {
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
}
if (a[e5] < a[e4]) {
int t = a[e5];
a[e5] = a[e4];
a[e4] = t;
if (t < a[e3]) {
a[e4] = a[e3];
a[e3] = t;
if (t < a[e2]) {
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
}
}
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
* Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2.
*/
int pivot1 = a[e2];
int pivot2 = a[e4];
/*
* The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning
* is complete, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
a[e2] = a[left];
a[e4] = a[right];
/*
* Skip elements, which are less or greater than pivot values.
*/
while (a[++less] < pivot1) {
}
while (a[--great] > pivot2) {
}
/*
* Partitioning:
*
* left part center part right part
* +--------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +--------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part.
*/
outer:
for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
/*
* Here and below we use "a[i] = b; i++;" instead
* of "a[i++] = b;" due to performance issue.
*/
a[less] = ak;
++less;
}
else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
++less;
}
else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak;
--great;
}
}
// Swap pivots into their final positions
a[left] = a[less - 1];
a[less - 1] = pivot1;
a[right] = a[great + 1];
a[great + 1] = pivot2;
// Sort left and right parts recursively, excluding known pivots
SortingIntTestJMH.sort(a, left, less - 2, leftmost);
SortingIntTestJMH.sort(a, great + 2, right, false);
/*
* If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends.
*/
if (less < e1 && e5 < great) {
/*
* Skip elements, which are equal to pivot values.
*/
while (a[less] == pivot1) {
++less;
}
while (a[great] == pivot2) {
--great;
}
/*
* Partitioning:
*
* left part center part right part
* +----------------------------------------------------------+
* | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
* +----------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (*, less) == pivot1
* pivot1 < all in [less, k) < pivot2
* all in (great, *) == pivot2
*
* Pointer k is the first index of ?-part.
*/
outer:
for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
++less;
}
else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
* assignment a[less] = pivot1 may be incorrect,
* if a[great] and pivot1 are floating-point zeros
* of different signs. Therefore in float and
* double sorting methods we have to use more
* accurate assignment a[less] = a[great].
*/
a[less] = pivot1;
++less;
}
else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great] = ak;
--great;
}
}
}
// Sort center part recursively
SortingIntTestJMH.sort(a, less, great, false);
}
else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
int pivot = a[e3];
/*
* Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
* +-------------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +-------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part.
*/
for (int k = less; k <= great; ++k) {
if (a[k] == pivot) {
continue;
}
int ak = a[k];
if (ak < pivot) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
++less;
}
else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot) {
--great;
}
if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less];
a[less] = a[great];
++less;
}
else { // a[great] == pivot
/*
* Even though a[great] equals to pivot, the
* assignment a[k] = pivot may be incorrect,
* if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float
* and double sorting methods we have to use
* more accurate assignment a[k] = a[great].
*/
a[k] = pivot;
}
a[great] = ak;
--great;
}
}
/*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
SortingIntTestJMH.sort(a, left, less - 1, leftmost);
SortingIntTestJMH.sort(a, great + 1, right, false);
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}

View file

@ -0,0 +1,725 @@
/*
* Copyright 2015 Goldman Sachs.
* Copyright (c) 2015, 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 org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
public class SortingLongBenchmarkTestJMH {
private static final int QUICKSORT_THRESHOLD = 286;
private static final int MAX_RUN_COUNT = 67;
private static final int INSERTION_SORT_THRESHOLD = 47;
public static final int MAX_VALUE = 1_000_000;
@Param({"pairFlipZeroPairFlip", "descendingAscending", "zeroHi", "hiZeroLow", "hiFlatLow", "identical",
"randomDups", "randomNoDups", "sortedReversedSorted", "pairFlip", "endLessThan"})
public String listType;
private long[] array;
private static final int LIST_SIZE = 10_000_000;
public static final int NUMBER_OF_ITERATIONS = 10;
@Setup
public void setUp() {
Random random = new Random(123456789012345L);
this.array = new long[LIST_SIZE];
int threeQuarters = (int) (LIST_SIZE * 0.75);
if ("zeroHi".equals(this.listType)) {
for (int i = 0; i < threeQuarters; i++) {
this.array[i] = 0;
}
int k = 1;
for (int i = threeQuarters; i < LIST_SIZE; i++) {
this.array[i] = k;
k++;
}
}
else if ("hiFlatLow".equals(this.listType)) {
int oneThird = LIST_SIZE / 3;
for (int i = 0; i < oneThird; i++) {
this.array[i] = i;
}
int twoThirds = oneThird * 2;
int constant = oneThird - 1;
for (int i = oneThird; i < twoThirds; i++) {
this.array[i] = constant;
}
for (int i = twoThirds; i < LIST_SIZE; i++) {
this.array[i] = constant - i + twoThirds;
}
}
else if ("hiZeroLow".equals(this.listType)) {
int oneThird = LIST_SIZE / 3;
for (int i = 0; i < oneThird; i++) {
this.array[i] = i;
}
int twoThirds = oneThird * 2;
for (int i = oneThird; i < twoThirds; i++) {
this.array[i] = 0;
}
for (int i = twoThirds; i < LIST_SIZE; i++) {
this.array[i] = oneThird - i + twoThirds;
}
}
else if ("identical".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = 0;
}
}
else if ("randomDups".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = random.nextInt(1000);
}
}
else if ("randomNoDups".equals(this.listType)) {
Set<Integer> set = new HashSet<>();
while (set.size() < LIST_SIZE + 1) {
set.add(random.nextInt());
}
List<Integer> list = new ArrayList<>(LIST_SIZE);
list.addAll(set);
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = list.get(i);
}
}
else if ("sortedReversedSorted".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE / 2; i++) {
this.array[i] = i;
}
int num = 0;
for (int i = LIST_SIZE / 2; i < LIST_SIZE; i++) {
this.array[i] = LIST_SIZE - num;
num++;
}
}
else if ("pairFlip".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = i;
}
for (int i = 0; i < LIST_SIZE; i += 2) {
long temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
}
else if ("endLessThan".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE - 1; i++) {
this.array[i] = 3;
}
this.array[LIST_SIZE - 1] = 1;
}
else if ("pairFlipZeroPairFlip".equals(this.listType)) {
//pairflip
for (int i = 0; i < 64; i++) {
this.array[i] = i;
}
for (int i = 0; i < 64; i += 2) {
long temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
//zero
for (int i = 64; i < this.array.length - 64; i++) {
this.array[i] = 0;
}
//pairflip
for (int i = this.array.length - 64; i < this.array.length; i++) {
this.array[i] = i;
}
for (int i = this.array.length - 64; i < this.array.length; i += 2) {
long temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
}
else if ("pairFlipOneHundredPairFlip".equals(this.listType)) {
//10, 5
for (int i = 0; i < 64; i++) {
if (i % 2 == 0) {
this.array[i] = 10;
}
else {
this.array[i] = 5;
}
}
//100
for (int i = 64; i < this.array.length - 64; i++) {
this.array[i] = 100;
}
//10, 5
for (int i = this.array.length - 64; i < this.array.length; i++) {
if (i % 2 == 0) {
this.array[i] = 10;
}
else {
this.array[i] = 5;
}
}
}
}
@Warmup(iterations = 20)
@Measurement(iterations = 10)
@Benchmark
public void sortNewWay() {
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
SortingLongTestJMH.sort(this.array, 0, this.array.length - 1, null, 0, 0);
}
}
@Warmup(iterations = 20)
@Measurement(iterations = 10)
@Benchmark
public void sortOldWay() {
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
Arrays.sort(this.array);
}
}
/**
* Sorts the specified range of the array using the given
* workspace array slice if possible for merging
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
* @param work a workspace array (slice)
* @param workBase origin of usable space in work array
* @param workLen usable size of work array
*/
static void sort(long[] a, int left, int right,
long[] work, int workBase, int workLen) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
SortingLongTestJMH.sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT + 1];
int count = 0;
run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
while (k < right && a[k] == a[k + 1])
k++;
if (k == right) break;
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]) ;
}
else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]) ;
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
long t = a[lo];
a[lo] = a[hi];
a[hi] = t;
}
}
if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
count--;
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
// Implementation note: variable "right" is increased by 1.
if (run[count] == right++) {
run[++count] = right;
}
if (count <= 1) { // The array is already sorted
return;
}
// Determine alternation base for merge
byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1) {
}
// Use or create temporary array b for merging
long[] b; // temp array; alternates with a
int ao, bo; // array offsets from 'left'
int blen = right - left; // space needed for b
if (work == null || workLen < blen || workBase + blen > work.length) {
work = new long[blen];
workBase = 0;
}
if (odd == 0) {
System.arraycopy(a, left, work, workBase, blen);
b = a;
bo = 0;
a = work;
ao = workBase - left;
}
else {
b = work;
ao = 0;
bo = workBase - left;
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
b[i + bo] = a[p++ + ao];
}
else {
b[i + bo] = a[q++ + ao];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i + bo] = a[i + ao]
) {
}
run[++last] = right;
}
long[] t = a;
a = b;
b = t;
int o = ao;
ao = bo;
bo = o;
}
}
/**
* Sorts the specified range of the array by Dual-Pivot Quicksort.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if this part is the leftmost in the range
*/
private static void sort(long[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
// Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) {
/*
* Traditional (without sentinel) insertion sort,
* optimized for server VM, is used in case of
* the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
long ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left) {
break;
}
}
a[j + 1] = ai;
}
}
else {
/*
* Skip the longest ascending sequence.
*/
do {
if (left >= right) {
return;
}
}
while (a[++left] >= a[left - 1]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the more optimized algorithm, so called pair insertion
* sort, which is faster (in the context of Quicksort)
* than traditional implementation of insertion sort.
*/
for (int k = left; ++left <= right; k = ++left) {
long a1 = a[k], a2 = a[left];
if (a1 < a2) {
a2 = a1;
a1 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
long last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
}
return;
}
// Inexpensive approximation of length / 7
int seventh = (length >> 3) + (length >> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
* center element in the range. These elements will be used for
* pivot selection as described below. The choice for spacing
* these elements was empirically determined to work well on
* a wide variety of inputs.
*/
int e3 = (left + right) >>> 1; // The midpoint
int e2 = e3 - seventh;
int e1 = e2 - seventh;
int e4 = e3 + seventh;
int e5 = e4 + seventh;
// Sort these elements using insertion sort
if (a[e2] < a[e1]) {
long t = a[e2];
a[e2] = a[e1];
a[e1] = t;
}
if (a[e3] < a[e2]) {
long t = a[e3];
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
if (a[e4] < a[e3]) {
long t = a[e4];
a[e4] = a[e3];
a[e3] = t;
if (t < a[e2]) {
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
}
if (a[e5] < a[e4]) {
long t = a[e5];
a[e5] = a[e4];
a[e4] = t;
if (t < a[e3]) {
a[e4] = a[e3];
a[e3] = t;
if (t < a[e2]) {
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
}
}
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
* Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2.
*/
long pivot1 = a[e2];
long pivot2 = a[e4];
/*
* The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning
* is complete, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
a[e2] = a[left];
a[e4] = a[right];
/*
* Skip elements, which are less or greater than pivot values.
*/
while (a[++less] < pivot1) {
}
while (a[--great] > pivot2) {
}
/*
* Partitioning:
*
* left part center part right part
* +--------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +--------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part.
*/
outer:
for (int k = less - 1; ++k <= great; ) {
long ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
/*
* Here and below we use "a[i] = b; i++;" instead
* of "a[i++] = b;" due to performance issue.
*/
a[less] = ak;
++less;
}
else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
++less;
}
else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak;
--great;
}
}
// Swap pivots into their final positions
a[left] = a[less - 1];
a[less - 1] = pivot1;
a[right] = a[great + 1];
a[great + 1] = pivot2;
// Sort left and right parts recursively, excluding known pivots
SortingLongTestJMH.sort(a, left, less - 2, leftmost);
SortingLongTestJMH.sort(a, great + 2, right, false);
/*
* If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends.
*/
if (less < e1 && e5 < great) {
/*
* Skip elements, which are equal to pivot values.
*/
while (a[less] == pivot1) {
++less;
}
while (a[great] == pivot2) {
--great;
}
/*
* Partitioning:
*
* left part center part right part
* +----------------------------------------------------------+
* | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
* +----------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (*, less) == pivot1
* pivot1 < all in [less, k) < pivot2
* all in (great, *) == pivot2
*
* Pointer k is the first index of ?-part.
*/
outer:
for (int k = less - 1; ++k <= great; ) {
long ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
++less;
}
else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
* assignment a[less] = pivot1 may be incorrect,
* if a[great] and pivot1 are floating-point zeros
* of different signs. Therefore in float and
* double sorting methods we have to use more
* accurate assignment a[less] = a[great].
*/
a[less] = pivot1;
++less;
}
else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great] = ak;
--great;
}
}
}
// Sort center part recursively
SortingLongTestJMH.sort(a, less, great, false);
}
else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
long pivot = a[e3];
/*
* Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
* +-------------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +-------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part.
*/
for (int k = less; k <= great; ++k) {
if (a[k] == pivot) {
continue;
}
long ak = a[k];
if (ak < pivot) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
++less;
}
else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot) {
--great;
}
if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less];
a[less] = a[great];
++less;
}
else { // a[great] == pivot
/*
* Even though a[great] equals to pivot, the
* assignment a[k] = pivot may be incorrect,
* if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float
* and double sorting methods we have to use
* more accurate assignment a[k] = a[great].
*/
a[k] = pivot;
}
a[great] = ak;
--great;
}
}
/*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
SortingLongTestJMH.sort(a, left, less - 1, leftmost);
SortingLongTestJMH.sort(a, great + 1, right, false);
}
}
private static void swap(long[] arr, int i, int j) {
long tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}

View file

@ -0,0 +1,358 @@
/*
* Copyright 2015 Goldman Sachs.
* Copyright (c) 2015, 2026, 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 8154049
* @summary Tests the sorting of a large array of sorted primitive values,
* predominently for cases where the array is nearly sorted. This tests
* code that detects patterns in the array to determine if it is nearly
* sorted and if so employs and optimizes merge sort rather than a
* Dual-Pivot QuickSort.
*
* @run junit SortingNearlySortedPrimitive
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;
import java.util.function.IntFunction;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class SortingNearlySortedPrimitive {
static final int BASE = 3;
static final int WIDTH = 4;
// Should be > DualPivotQuicksort.QUICKSORT_THRESHOLD
static final int PAD = 300;
Stream<int[]> createCombinations() {
// Create all combinations for the BASE value and double the WIDTH
// elements
// This is create various combinations of ascending, descending and
// equal runs to exercise the nearly sorted code paths
return IntStream.range(0, (int) Math.pow(BASE, 2 * WIDTH)).
mapToObj(this::createArray);
}
// Create an array which at either end is filled with -ve and +ve elements
// according to the base value and padded with zeros in between
int[] createArray(int v) {
int[] a = new int[WIDTH + PAD + WIDTH];
// Fill head of array
for (int j = 0; j < WIDTH; j++) {
a[j] = (v % BASE) - (BASE / 2);
v /= BASE;
}
// Fill tail of array
for (int j = 0; j < WIDTH; j++) {
a[WIDTH + PAD + j] = (v % BASE) - (BASE / 2);
v /= BASE;
}
return a;
}
@Test
public void testCombination() {
createCombinations().forEach(a -> {
try {
// Clone source array to ensure it is not modified
this.sortAndAssert(a.clone());
this.sortAndAssert(floatCopyFromInt(a));
this.sortAndAssert(doubleCopyFromInt(a));
this.sortAndAssert(longCopyFromInt(a));
this.sortAndAssert(shortCopyFromInt(a));
this.sortAndAssert(charCopyFromInt(a));
} catch (AssertionError sae) {
AssertionError ae = new AssertionError("Sort failed for " + arrayToString(a));
ae.addSuppressed(sae);
throw ae;
}
});
}
String arrayToString(int[] a) {
int[] l = Arrays.copyOfRange(a, 0, WIDTH + 2);
int[] r = Arrays.copyOfRange(a, a.length - (WIDTH + 2), a.length);
StringJoiner sj = new StringJoiner(",", "[", "]");
for (int i : l) {
sj.add(Integer.toString(i));
}
sj.add("...");
for (int i : r) {
sj.add(Integer.toString(i));
}
return sj.toString();
}
public Object[][] createShapes() {
Stream<List<Object>> baseCases = Stream.of(
List.of("hiZeroLowTest", (IntFunction<int[]>) this::hiZeroLowData),
List.of("endLessThanTest", (IntFunction<int[]>) this::endLessThanData),
List.of("highFlatLowTest", (IntFunction<int[]>) this::highFlatLowData),
List.of("identicalTest", (IntFunction<int[]>) this::identicalData),
List.of("sortedReversedSortedTest", (IntFunction<int[]>) this::sortedReversedSortedData),
List.of("pairFlipTest", (IntFunction<int[]>) this::pairFlipData),
List.of("zeroHiTest", (IntFunction<int[]>) this::zeroHiData)
);
// Ensure the following inequality holds for certain sizes
// DualPivotQuicksort.QUICKSORT_THRESHOLD <= size - 1
// < DualPivotQuicksort.COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR
// This guarantees that code paths are taken for checking nearly sorted
// arrays for all primitive types
List<Integer> sizes = List.of(100, 1_000, 10_000, 1_000_000);
return baseCases.
flatMap(l -> sizes.stream().map(s -> append(l, s))).
toArray(Object[][]::new);
}
Object[] append(List<Object> l, Object value) {
List<Object> nl = new ArrayList<>(l);
nl.add(value);
return nl.toArray();
}
@ParameterizedTest
@MethodSource("createShapes")
public void testShapes(String testName, IntFunction<int[]> dataMethod, int size) {
int[] intSourceArray = dataMethod.apply(size);
// Clone source array to ensure it is not modified
this.sortAndAssert(intSourceArray.clone());
this.sortAndAssert(floatCopyFromInt(intSourceArray));
this.sortAndAssert(doubleCopyFromInt(intSourceArray));
this.sortAndAssert(longCopyFromInt(intSourceArray));
this.sortAndAssert(shortCopyFromInt(intSourceArray));
this.sortAndAssert(charCopyFromInt(intSourceArray));
}
private float[] floatCopyFromInt(int[] src) {
float[] result = new float[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = src[i];
}
return result;
}
private double[] doubleCopyFromInt(int[] src) {
double[] result = new double[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = src[i];
}
return result;
}
private long[] longCopyFromInt(int[] src) {
long[] result = new long[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = src[i];
}
return result;
}
private short[] shortCopyFromInt(int[] src) {
short[] result = new short[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = (short) src[i];
}
return result;
}
private char[] charCopyFromInt(int[] src) {
char[] result = new char[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = (char) src[i];
}
return result;
}
private void sortAndAssert(int[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(char[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(short[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(double[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(float[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(long[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private int[] zeroHiData(int size) {
int[] array = new int[size];
int threeQuarters = (int) (size * 0.75);
for (int i = 0; i < threeQuarters; i++) {
array[i] = 0;
}
int k = 1;
for (int i = threeQuarters; i < size; i++) {
array[i] = k;
k++;
}
return array;
}
private int[] hiZeroLowData(int size) {
int[] array = new int[size];
int oneThird = size / 3;
for (int i = 0; i < oneThird; i++) {
array[i] = i;
}
int twoThirds = oneThird * 2;
for (int i = oneThird; i < twoThirds; i++) {
array[i] = 0;
}
for (int i = twoThirds; i < size; i++) {
array[i] = oneThird - i + twoThirds;
}
return array;
}
private int[] highFlatLowData(int size) {
int[] array = new int[size];
int oneThird = size / 3;
for (int i = 0; i < oneThird; i++) {
array[i] = i;
}
int twoThirds = oneThird * 2;
int constant = oneThird - 1;
for (int i = oneThird; i < twoThirds; i++) {
array[i] = constant;
}
for (int i = twoThirds; i < size; i++) {
array[i] = constant - i + twoThirds;
}
return array;
}
private int[] identicalData(int size) {
int[] array = new int[size];
int listNumber = 24;
for (int i = 0; i < size; i++) {
array[i] = listNumber;
}
return array;
}
private int[] endLessThanData(int size) {
int[] array = new int[size];
for (int i = 0; i < size - 1; i++) {
array[i] = 3;
}
array[size - 1] = 1;
return array;
}
private int[] sortedReversedSortedData(int size) {
int[] array = new int[size];
for (int i = 0; i < size / 2; i++) {
array[i] = i;
}
int num = 0;
for (int i = size / 2; i < size; i++) {
array[i] = size - num;
num++;
}
return array;
}
private int[] pairFlipData(int size) {
int[] array = new int[size];
for (int i = 0; i < size; i++) {
array[i] = i;
}
for (int i = 0; i < size; i += 2) {
int temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
return array;
}
}

View file

@ -0,0 +1,136 @@
/*
* Copyright (c) 2014, 2026, 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 8037857
* @summary tests for stream and spliterator factory methods
* @run junit StreamAndSpliterator
*/
import java.util.Arrays;
import java.util.Spliterators;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
public class StreamAndSpliterator {
@Test
public void testStreamNPEs() {
assertThrowsNPE(() -> Arrays.stream((int[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.stream((long[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.stream((double[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.stream((String[]) null, 0, 0));
}
@Test
public void testStreamAIOBEs() {
// origin > fence
assertThrowsAIOOB(() -> Arrays.stream(new int[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new long[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new double[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new String[]{}, 1, 0));
// bad origin
assertThrowsAIOOB(() -> Arrays.stream(new int[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new long[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new double[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new String[]{}, -1, 0));
// bad fence
assertThrowsAIOOB(() -> Arrays.stream(new int[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.stream(new long[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.stream(new double[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.stream(new String[]{}, 0, 1));
}
@Test
public void testSpliteratorNPEs() {
assertThrowsNPE(() -> Arrays.spliterator((int[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.spliterator((long[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.spliterator((double[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.spliterator((String[]) null, 0, 0));
}
@Test
public void testSpliteratorAIOBEs() {
// origin > fence
assertThrowsAIOOB(() -> Arrays.spliterator(new int[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new long[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new double[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new String[]{}, 1, 0));
// bad origin
assertThrowsAIOOB(() -> Arrays.spliterator(new int[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new long[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new double[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new String[]{}, -1, 0));
// bad fence
assertThrowsAIOOB(() -> Arrays.spliterator(new int[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.spliterator(new long[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.spliterator(new double[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.spliterator(new String[]{}, 0, 1));
}
@Test
public void testSpliteratorNPEsFromSpliterators() {
assertThrowsNPE(() -> Spliterators.spliterator((int[]) null, 0, 0, 0));
assertThrowsNPE(() -> Spliterators.spliterator((long[]) null, 0, 0, 0));
assertThrowsNPE(() -> Spliterators.spliterator((double[]) null, 0, 0, 0));
assertThrowsNPE(() -> Spliterators.spliterator((String[]) null, 0, 0, 0));
}
@Test
public void testSpliteratorAIOBEsFromSpliterators() {
// origin > fence
assertThrowsAIOOB(() -> Spliterators.spliterator(new int[]{}, 1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new long[]{}, 1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new double[]{}, 1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new String[]{}, 1, 0, 0));
// bad origin
assertThrowsAIOOB(() -> Spliterators.spliterator(new int[]{}, -1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new long[]{}, -1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new double[]{}, -1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new String[]{}, -1, 0, 0));
// bad fence
assertThrowsAIOOB(() -> Spliterators.spliterator(new int[]{}, 0, 1, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new long[]{}, 0, 1, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new double[]{}, 0, 1, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new String[]{}, 0, 1, 0));
}
void assertThrowsNPE(Executable r) {
assertThrows(NullPointerException.class, r);
}
void assertThrowsAIOOB(Executable r) {
assertThrows(ArrayIndexOutOfBoundsException.class, r);
}
}

View file

@ -0,0 +1 @@
disallowedActions=testng

View file

@ -0,0 +1,116 @@
/*
* Copyright (c) 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.
*/
/*
* @test
* @bug 8011944
* @summary Test TimSort stack size
*/
import java.util.Arrays;
import java.util.ArrayDeque;
public class TimSortStackSize {
public static void main(String[] args) {
testComparableTimSort();
testTimSort();
}
static void testComparableTimSort() {
System.out.printf("testComparableTimSort()%n");
Arrays.sort(genData());
}
static void testTimSort() {
System.out.printf("testTimSort()%n");
Arrays.sort(genData(), Integer::compare);
}
private static final int MIN = 16;
private static final int BOUND1 = 2 * MIN + 1;
private static final int BOUND2 = BOUND1 + MIN + 2;
private static final int BOUND3 = BOUND1 + 1 + BOUND2;
private static final int BOUND4 = BOUND2 + 1 + BOUND3;
private static final int BOUND5 = BOUND3 + 1 + BOUND4;
static int build(int size, int B, ArrayDeque<Integer> chunks) {
chunks.addFirst(B);
if (size < BOUND1) {
chunks.addFirst(size);
return size;
}
int asize = (size + 2) / 2;
if (size >= BOUND2 && asize < BOUND1) {
asize = BOUND1;
} else if (size >= BOUND3 && asize < BOUND2) {
asize = BOUND2;
} else if (size >= BOUND4 && asize < BOUND3) {
asize = BOUND3;
} else if (size >= BOUND5 && asize < BOUND4) {
asize = BOUND4;
}
if (size - asize >= B) {
throw new AssertionError(" " + size + " , " + asize + " , " + B);
}
return build(asize, size - asize, chunks);
}
static Integer[] genData() {
ArrayDeque<Integer> chunks = new ArrayDeque<Integer>();
chunks.addFirst(MIN);
int B = MIN + 4;
int A = B + MIN + 1;
for (int i = 0; i < 8; i++) {
int eps = build(A, B, chunks);
B = B + A + 1;
A = B + eps + 1;
}
chunks.addFirst(B);
chunks.addFirst(A);
int total = 0;
for (Integer len : chunks) {
total += len;
}
int pow = MIN;
while (pow < total) {
pow += pow;
}
chunks.addLast(pow - total);
System.out.println(" Total: " + total);
Integer[] array = new Integer[pow];
int off = 0;
int pos = 0;
for (Integer len : chunks) {
for (int i = 0; i < len; i++) {
array[pos++] = Integer.valueOf(i == 0 ? 0 : 1);
}
off++;
}
return array;
}
}

View file

@ -0,0 +1,214 @@
/*
* Copyright (c) 2015, 2022, 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 8072909
* @summary Test TimSort stack size on big arrays
* @library /test/lib
* @modules java.management
* @requires (vm.debug == false)
* @build TimSortStackSize2
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI TimSortStackSize2
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.whitebox.WhiteBox;
public class TimSortStackSize2 {
public static void main(String[] args) {
if ( args == null || args.length == 0 ){
startMeWithArgs();
} else {
doTestOfTwoTimSorts(Integer.parseInt(args[0]));
}
}
private static void startMeWithArgs(){
/*
* big tests not for regular execution on all platforms:
* run main/othervm -Xmx8g TimSortStackSize2 1073741824
* run main/othervm -Xmx16g TimSortStackSize2 2147483644
*/
try {
Boolean compressedOops = WhiteBox.getWhiteBox()
.getBooleanVMFlag("UseCompressedOops");
long memory = (compressedOops == null || compressedOops) ? 385 : 770;
final String xmsValue = "-Xms" + memory + "m";
final String xmxValue = "-Xmx" + 2 * memory + "m";
System.out.printf("compressedOops: %s; Test will be started with \"%s %s\"%n",
compressedOops, xmsValue, xmxValue);
OutputAnalyzer output = ProcessTools.executeTestJava(xmsValue,
xmxValue,
"TimSortStackSize2",
"67108864");
System.out.println(output.getOutput());
output.shouldHaveExitValue(0);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private static void doTestOfTwoTimSorts(final int lengthOfTest){
boolean passed = doTest("TimSort", lengthOfTest,
(Integer [] a) -> Arrays.sort(a));
passed = doTest("ComparableTimSort", lengthOfTest, (Integer [] a) ->
Arrays.sort(a, (Object first, Object second) -> {
return ((Comparable<Object>)first).compareTo(second);
}))
&& passed;
if ( !passed ){
throw new RuntimeException();
}
}
private static boolean doTest(final String msg, final int lengthOfTest,
final Consumer<Integer[]> c){
Integer [] a = null;
try {
a = new TimSortStackSize2(lengthOfTest).createArray();
long begin = System.nanoTime();
c.accept(a);
long end = System.nanoTime();
System.out.println(msg + " OK. Time: " + (end - begin) + "ns");
} catch (ArrayIndexOutOfBoundsException e){
System.out.println(msg + " broken:");
e.printStackTrace();
return false;
} finally {
a = null;
}
return true;
}
private static final int MIN_MERGE = 32;
private final int minRun;
private final int length;
private final List<Long> runs = new ArrayList<Long>();
public TimSortStackSize2(final int len) {
this.length = len;
minRun = minRunLength(len);
fillRunsJDKWorstCase();
}
private static int minRunLength(int n) {
assert n >= 0;
int r = 0; // Becomes 1 if any 1 bits are shifted off
while (n >= MIN_MERGE) {
r |= (n & 1);
n >>= 1;
}
return n + r;
}
/**
* Adds a sequence x_1, ..., x_n of run lengths to <code>runs</code> such that:<br>
* 1. X = x_1 + ... + x_n <br>
* 2. x_j >= minRun for all j <br>
* 3. x_1 + ... + x_{j-2} < x_j < x_1 + ... + x_{j-1} for all j <br>
* These conditions guarantee that TimSort merges all x_j's one by one
* (resulting in X) using only merges on the second-to-last element.
* @param X The sum of the sequence that should be added to runs.
*/
private void generateJDKWrongElem(long X) {
for(long newTotal; X >= 2 * minRun + 1; X = newTotal) {
//Default strategy
newTotal = X / 2 + 1;
//Specialized strategies
if(3 * minRun + 3 <= X && X <= 4*minRun+1) {
// add x_1=MIN+1, x_2=MIN, x_3=X-newTotal to runs
newTotal = 2 * minRun + 1;
} else if (5 * minRun + 5 <= X && X <= 6 * minRun + 5) {
// add x_1=MIN+1, x_2=MIN, x_3=MIN+2, x_4=X-newTotal to runs
newTotal = 3 * minRun + 3;
} else if (8 * minRun + 9 <= X && X <= 10 * minRun + 9) {
// add x_1=MIN+1, x_2=MIN, x_3=MIN+2, x_4=2MIN+2, x_5=X-newTotal to runs
newTotal = 5 * minRun + 5;
} else if (13 * minRun + 15 <= X && X <= 16 * minRun + 17) {
// add x_1=MIN+1, x_2=MIN, x_3=MIN+2, x_4=2MIN+2, x_5=3MIN+4, x_6=X-newTotal to runs
newTotal = 8 * minRun + 9;
}
runs.add(0, X - newTotal);
}
runs.add(0, X);
}
/**
* Fills <code>runs</code> with a sequence of run lengths of the form<br>
* Y_n x_{n,1} x_{n,2} ... x_{n,l_n} <br>
* Y_{n-1} x_{n-1,1} x_{n-1,2} ... x_{n-1,l_{n-1}} <br>
* ... <br>
* Y_1 x_{1,1} x_{1,2} ... x_{1,l_1}<br>
* The Y_i's are chosen to satisfy the invariant throughout execution,
* but the x_{i,j}'s are merged (by <code>TimSort.mergeCollapse</code>)
* into an X_i that violates the invariant.
* X is the sum of all run lengths that will be added to <code>runs</code>.
*/
private void fillRunsJDKWorstCase() {
long runningTotal = 0;
long Y = minRun + 4;
long X = minRun;
while (runningTotal + Y + X <= length) {
runningTotal += X + Y;
generateJDKWrongElem(X);
runs.add(0, Y);
// X_{i+1} = Y_i + x_{i,1} + 1, since runs.get(1) = x_{i,1}
X = Y + runs.get(1) + 1;
// Y_{i+1} = X_{i+1} + Y_i + 1
Y += X + 1;
}
if (runningTotal + X <= length) {
runningTotal += X;
generateJDKWrongElem(X);
}
runs.add(length - runningTotal);
}
private Integer [] createArray() {
Integer [] a = new Integer[length];
Arrays.fill(a, 0);
int endRun = -1;
for (long len : runs) {
a[endRun += len] = 1;
}
a[length - 1] = 0;
return a;
}
}

View file

@ -0,0 +1,350 @@
/*
* Copyright (c) 2019, 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.
*/
package java.util;
/**
* This class provides access to package-private
* methods of DualPivotQuicksort class.
*
* @author Vladimir Yaroslavskiy
*
* @version 2019.09.19
*
* @since 14
*/
public enum SortingHelper {
DUAL_PIVOT_QUICKSORT("Dual-Pivot Quicksort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
DualPivotQuicksort.sort((int[]) a, SEQUENTIAL, 0, ((int[]) a).length);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort((long[]) a, SEQUENTIAL, 0, ((long[]) a).length);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, 0, ((byte[]) a).length);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, SEQUENTIAL, 0, ((char[]) a).length);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, SEQUENTIAL, 0, ((short[]) a).length);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort((float[]) a, SEQUENTIAL, 0, ((float[]) a).length);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort((double[]) a, SEQUENTIAL, 0, ((double[]) a).length);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
DualPivotQuicksort.sort((int[]) a, SEQUENTIAL, low, high);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort((long[]) a, SEQUENTIAL, low, high);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, low, high);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, SEQUENTIAL, low, high);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, SEQUENTIAL, low, high);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort((float[]) a, SEQUENTIAL, low, high);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort((double[]) a, SEQUENTIAL, low, high);
} else {
fail(a);
}
}
@Override
public void sort(Object[] a) {
fail(a);
}
@Override
public void sort(Object[] a, Comparator comparator) {
fail(a);
}
},
PARALLEL_SORT("Parallel sort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
DualPivotQuicksort.sort((int[]) a, PARALLEL, 0, ((int[]) a).length);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort((long[]) a, PARALLEL, 0, ((long[]) a).length);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, 0, ((byte[]) a).length);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, PARALLEL, 0, ((char[]) a).length);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, PARALLEL, 0, ((short[]) a).length);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort((float[]) a, PARALLEL, 0, ((float[]) a).length);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort((double[]) a, PARALLEL, 0, ((double[]) a).length);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
DualPivotQuicksort.sort((int[]) a, PARALLEL, low, high);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort((long[]) a, PARALLEL, low, high);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, low, high);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, PARALLEL, low, high);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, PARALLEL, low, high);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort((float[]) a, PARALLEL, low, high);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort((double[]) a, PARALLEL, low, high);
} else {
fail(a);
}
}
@Override
public void sort(Object[] a) {
fail(a);
}
@Override
public void sort(Object[] a, Comparator comparator) {
fail(a);
}
},
HEAP_SORT("Heap sort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
DualPivotQuicksort.sort(null, (int[]) a, BIG_DEPTH, 0, ((int[]) a).length);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort(null, (long[]) a, BIG_DEPTH, 0, ((long[]) a).length);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, 0, ((byte[]) a).length);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, BIG_DEPTH, 0, ((char[]) a).length);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, BIG_DEPTH, 0, ((short[]) a).length);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort(null, (float[]) a, BIG_DEPTH, 0, ((float[]) a).length);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort(null, (double[]) a, BIG_DEPTH, 0, ((double[]) a).length);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
DualPivotQuicksort.sort(null, (int[]) a, BIG_DEPTH, low, high);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort(null, (long[]) a, BIG_DEPTH, low, high);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, low, high);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, BIG_DEPTH, low, high);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, BIG_DEPTH, low, high);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort(null, (float[]) a, BIG_DEPTH, low, high);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort(null, (double[]) a, BIG_DEPTH, low, high);
} else {
fail(a);
}
}
@Override
public void sort(Object[] a) {
fail(a);
}
@Override
public void sort(Object[] a, Comparator comparator) {
fail(a);
}
},
ARRAYS_SORT("Arrays.sort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
Arrays.sort((int[]) a);
} else if (a instanceof long[]) {
Arrays.sort((long[]) a);
} else if (a instanceof byte[]) {
Arrays.sort((byte[]) a);
} else if (a instanceof char[]) {
Arrays.sort((char[]) a);
} else if (a instanceof short[]) {
Arrays.sort((short[]) a);
} else if (a instanceof float[]) {
Arrays.sort((float[]) a);
} else if (a instanceof double[]) {
Arrays.sort((double[]) a);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
Arrays.sort((int[]) a, low, high);
} else if (a instanceof long[]) {
Arrays.sort((long[]) a, low, high);
} else if (a instanceof byte[]) {
Arrays.sort((byte[]) a, low, high);
} else if (a instanceof char[]) {
Arrays.sort((char[]) a, low, high);
} else if (a instanceof short[]) {
Arrays.sort((short[]) a, low, high);
} else if (a instanceof float[]) {
Arrays.sort((float[]) a, low, high);
} else if (a instanceof double[]) {
Arrays.sort((double[]) a, low, high);
} else {
fail(a);
}
}
@Override
public void sort(Object[] a) {
Arrays.sort(a);
}
@Override
@SuppressWarnings("unchecked")
public void sort(Object[] a, Comparator comparator) {
Arrays.sort(a, comparator);
}
},
ARRAYS_PARALLEL_SORT("Arrays.parallelSort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
Arrays.parallelSort((int[]) a);
} else if (a instanceof long[]) {
Arrays.parallelSort((long[]) a);
} else if (a instanceof byte[]) {
Arrays.parallelSort((byte[]) a);
} else if (a instanceof char[]) {
Arrays.parallelSort((char[]) a);
} else if (a instanceof short[]) {
Arrays.parallelSort((short[]) a);
} else if (a instanceof float[]) {
Arrays.parallelSort((float[]) a);
} else if (a instanceof double[]) {
Arrays.parallelSort((double[]) a);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
Arrays.parallelSort((int[]) a, low, high);
} else if (a instanceof long[]) {
Arrays.parallelSort((long[]) a, low, high);
} else if (a instanceof byte[]) {
Arrays.parallelSort((byte[]) a, low, high);
} else if (a instanceof char[]) {
Arrays.parallelSort((char[]) a, low, high);
} else if (a instanceof short[]) {
Arrays.parallelSort((short[]) a, low, high);
} else if (a instanceof float[]) {
Arrays.parallelSort((float[]) a, low, high);
} else if (a instanceof double[]) {
Arrays.parallelSort((double[]) a, low, high);
} else {
fail(a);
}
}
@Override
@SuppressWarnings("unchecked")
public void sort(Object[] a) {
Arrays.parallelSort((Comparable[]) a);
}
@Override
@SuppressWarnings("unchecked")
public void sort(Object[] a, Comparator comparator) {
Arrays.parallelSort(a, comparator);
}
};
abstract public void sort(Object a);
abstract public void sort(Object a, int low, int high);
abstract public void sort(Object[] a);
abstract public void sort(Object[] a, Comparator comparator);
private SortingHelper(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
private static void fail(Object a) {
throw new RuntimeException("Unexpected type of array: " + a.getClass().getName());
}
private String name;
/**
* Parallelism level for sequential and parallel sorting.
*/
private static final int SEQUENTIAL = 0;
private static final int PARALLEL = 87;
/**
* Heap sort will be invoked, if recursion depth is too big.
* Value is taken from DualPivotQuicksort.MAX_RECURSION_DEPTH.
*/
private static final int BIG_DEPTH = 64 * (3 << 1);
}

View file

@ -0,0 +1,313 @@
/*
* Copyright (c) 2013, 2026, 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 8014076 8025067
* @summary unit test for Arrays.ParallelPrefix().
* @modules java.management jdk.management
* @run junit/othervm -Xms256m -Xmx1024m ParallelPrefix
*/
import java.lang.management.ManagementFactory;
import java.util.Arrays;
import java.util.function.BinaryOperator;
import java.util.function.DoubleBinaryOperator;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.LongBinaryOperator;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import com.sun.management.OperatingSystemMXBean;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ParallelPrefix {
//Array size less than MIN_PARTITION
private static final int SMALL_ARRAY_SIZE = 1 << 3;
//Array size equals MIN_PARTITION
private static final int THRESHOLD_ARRAY_SIZE = 1 << 4;
//Array size greater than MIN_PARTITION
private static final int MEDIUM_ARRAY_SIZE = 1 << 8;
//Array size much greater than MIN_PARTITION
private static final int LARGE_ARRAY_SIZE = 1 << 14;
private static int[] arraySizeCollection;
@BeforeAll
public static void setup() {
java.lang.management.OperatingSystemMXBean bean =
ManagementFactory.getOperatingSystemMXBean();
if (bean instanceof OperatingSystemMXBean) {
OperatingSystemMXBean os = (OperatingSystemMXBean)bean;
long physicalMemorySize = os.getTotalPhysicalMemorySize() / (1024 * 1024);
System.out.println("System memory size: " + physicalMemorySize + "M");
// when we can get system memory size, and it's larger than 2G,
// then we enable large array size test below,
// else disable large array size test below.
if (physicalMemorySize > (2 * 1024)) {
arraySizeCollection = new int[]{
SMALL_ARRAY_SIZE,
THRESHOLD_ARRAY_SIZE,
MEDIUM_ARRAY_SIZE,
LARGE_ARRAY_SIZE
};
System.out.println("System memory is large enough, add large array size test");
return;
}
}
arraySizeCollection = new int[]{
SMALL_ARRAY_SIZE,
THRESHOLD_ARRAY_SIZE,
MEDIUM_ARRAY_SIZE
};
System.out.println("System memory is not large enough, remove large array size test");
}
public static Object[][] intSet(){
return genericData(size -> IntStream.range(0, size).toArray(),
new IntBinaryOperator[]{
Integer::sum,
Integer::min});
}
public static Object[][] longSet(){
return genericData(size -> LongStream.range(0, size).toArray(),
new LongBinaryOperator[]{
Long::sum,
Long::min});
}
public static Object[][] doubleSet(){
return genericData(size -> IntStream.range(0, size).mapToDouble(i -> (double)i).toArray(),
new DoubleBinaryOperator[]{
Double::sum,
Double::min});
}
public static Object[][] stringSet(){
Function<Integer, String[]> stringsFunc = size ->
IntStream.range(0, size).mapToObj(Integer::toString).toArray(String[]::new);
BinaryOperator<String> concat = String::concat;
return genericData(stringsFunc,
(BinaryOperator<String>[]) new BinaryOperator[]{
concat });
}
private static <T, OPS> Object[][] genericData(Function<Integer, T> generateFunc, OPS[] ops) {
//test arrays which size is equals n-1, n, n+1, test random data
Object[][] data = new Object[arraySizeCollection.length * 3 * ops.length][4];
for(int n = 0; n < arraySizeCollection.length; n++ ) {
for(int testValue = -1 ; testValue <= 1; testValue++) {
int array_size = arraySizeCollection[n] + testValue;
for(int opsN = 0; opsN < ops.length; opsN++) {
int index = n * 3 * ops.length + (testValue + 1) * ops.length + opsN;
data[index][0] = generateFunc.apply(array_size);
data[index][1] = array_size / 3;
data[index][2] = 2 * array_size / 3;
data[index][3] = ops[opsN];
}
}
}
return data;
}
@ParameterizedTest
@MethodSource("intSet")
public void testParallelPrefixForInt(int[] data, int fromIndex, int toIndex, IntBinaryOperator op) {
int[] sequentialResult = data.clone();
for (int index = fromIndex + 1; index < toIndex; index++) {
sequentialResult[index ] = op.applyAsInt(sequentialResult[index - 1], sequentialResult[index]);
}
int[] parallelResult = data.clone();
Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
assertArraysEqual(sequentialResult, parallelResult);
int[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
Arrays.parallelPrefix(parallelRangeResult, op);
assertArraysEqual(Arrays.copyOfRange(sequentialResult, fromIndex, toIndex), parallelRangeResult);
}
@ParameterizedTest
@MethodSource("longSet")
public void testParallelPrefixForLong(long[] data, int fromIndex, int toIndex, LongBinaryOperator op) {
long[] sequentialResult = data.clone();
for (int index = fromIndex + 1; index < toIndex; index++) {
sequentialResult[index ] = op.applyAsLong(sequentialResult[index - 1], sequentialResult[index]);
}
long[] parallelResult = data.clone();
Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
assertArraysEqual(sequentialResult, parallelResult);
long[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
Arrays.parallelPrefix(parallelRangeResult, op);
assertArraysEqual(Arrays.copyOfRange(sequentialResult, fromIndex, toIndex), parallelRangeResult);
}
@ParameterizedTest
@MethodSource("doubleSet")
public void testParallelPrefixForDouble(double[] data, int fromIndex, int toIndex, DoubleBinaryOperator op) {
double[] sequentialResult = data.clone();
for (int index = fromIndex + 1; index < toIndex; index++) {
sequentialResult[index ] = op.applyAsDouble(sequentialResult[index - 1], sequentialResult[index]);
}
double[] parallelResult = data.clone();
Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
assertArraysEqual(sequentialResult, parallelResult);
double[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
Arrays.parallelPrefix(parallelRangeResult, op);
assertArraysEqual(Arrays.copyOfRange(sequentialResult, fromIndex, toIndex), parallelRangeResult);
}
@ParameterizedTest
@MethodSource("stringSet")
public void testParallelPrefixForStringr(String[] data , int fromIndex, int toIndex, BinaryOperator<String> op) {
String[] sequentialResult = data.clone();
for (int index = fromIndex + 1; index < toIndex; index++) {
sequentialResult[index ] = op.apply(sequentialResult[index - 1], sequentialResult[index]);
}
String[] parallelResult = data.clone();
Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
assertArraysEqual(sequentialResult, parallelResult);
String[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
Arrays.parallelPrefix(parallelRangeResult, op);
assertArraysEqual(Arrays.copyOfRange(sequentialResult, fromIndex, toIndex), parallelRangeResult);
}
@Test
public void testNPEs() {
// null array
assertThrowsNPE(() -> Arrays.parallelPrefix((int[]) null, Integer::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((long []) null, Long::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((double []) null, Double::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((String []) null, String::concat));
// null array w/ range
assertThrowsNPE(() -> Arrays.parallelPrefix((int[]) null, 0, 0, Integer::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((long []) null, 0, 0, Long::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((double []) null, 0, 0, Double::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((String []) null, 0, 0, String::concat));
// null op
assertThrowsNPE(() -> Arrays.parallelPrefix(new int[] {}, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new long[] {}, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new double[] {}, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new String[] {}, null));
// null op w/ range
assertThrowsNPE(() -> Arrays.parallelPrefix(new int[] {}, 0, 0, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new long[] {}, 0, 0, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new double[] {}, 0, 0, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new String[] {}, 0, 0, null));
}
@Test
public void testIAEs() {
assertThrowsIAE(() -> Arrays.parallelPrefix(new int[] {}, 1, 0, Integer::max));
assertThrowsIAE(() -> Arrays.parallelPrefix(new long[] {}, 1, 0, Long::max));
assertThrowsIAE(() -> Arrays.parallelPrefix(new double[] {}, 1, 0, Double::max));
assertThrowsIAE(() -> Arrays.parallelPrefix(new String[] {}, 1, 0, String::concat));
}
@Test
public void testAIOOBEs() {
// bad "fromIndex"
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new int[] {}, -1, 0, Integer::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new long[] {}, -1, 0, Long::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new double[] {}, -1, 0, Double::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new String[] {}, -1, 0, String::concat));
// bad "toIndex"
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new int[] {}, 0, 1, Integer::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new long[] {}, 0, 1, Long::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new double[] {}, 0, 1, Double::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new String[] {}, 0, 1, String::concat));
}
// "library" code
private void assertThrowsNPE(Executable r) {
assertThrows(NullPointerException.class, r);
}
private void assertThrowsIAE(Executable r) {
assertThrows(IllegalArgumentException.class, r);
}
private void assertThrowsAIOOB(Executable r) {
assertThrows(ArrayIndexOutOfBoundsException.class, r);
}
static void assertArraysEqual(int[] expected, int[] actual) {
try {
assertArrayEquals(expected, actual, "");
} catch (AssertionError x) {
throw new AssertionError(String.format("Expected:%s, actual:%s",
Arrays.toString(expected), Arrays.toString(actual)), x);
}
}
static void assertArraysEqual(long[] expected, long[] actual) {
try {
assertArrayEquals(expected, actual, "");
} catch (AssertionError x) {
throw new AssertionError(String.format("Expected:%s, actual:%s",
Arrays.toString(expected), Arrays.toString(actual)), x);
}
}
static void assertArraysEqual(double[] expected, double[] actual) {
try {
assertArrayEquals(expected, actual, "");
} catch (AssertionError x) {
throw new AssertionError(String.format("Expected:%s, actual:%s",
Arrays.toString(expected), Arrays.toString(actual)), x);
}
}
static void assertArraysEqual(String[] expected, String[] actual) {
try {
assertArrayEquals(expected, actual, "");
} catch (AssertionError x) {
throw new AssertionError(String.format("Expected:%s, actual:%s",
Arrays.toString(expected), Arrays.toString(actual)), x);
}
}
}