classlib: Arrays corner cases fixes (#825)

This commit is contained in:
Ivan Hetman 2023-10-16 20:40:50 +03:00 committed by GitHub
parent cd9db17d73
commit 9242aeb750
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 108 additions and 94 deletions

View File

@ -474,6 +474,9 @@ public class TArrays extends TObject {
}
public static void sort(int[] a, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException();
}
int[] subarray = new int[toIndex - fromIndex];
for (int i = fromIndex; i < toIndex; ++i) {
subarray[i - fromIndex] = a[i];
@ -536,6 +539,9 @@ public class TArrays extends TObject {
}
public static void sort(long[] a, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException();
}
long[] subarray = new long[toIndex - fromIndex];
for (int i = fromIndex; i < toIndex; ++i) {
subarray[i - fromIndex] = a[i];
@ -598,6 +604,9 @@ public class TArrays extends TObject {
}
public static void sort(short[] a, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException();
}
short[] subarray = new short[toIndex - fromIndex];
for (int i = fromIndex; i < toIndex; ++i) {
subarray[i - fromIndex] = a[i];
@ -660,6 +669,9 @@ public class TArrays extends TObject {
}
public static void sort(char[] a, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException();
}
char[] subarray = new char[toIndex - fromIndex];
for (int i = fromIndex; i < toIndex; ++i) {
subarray[i - fromIndex] = a[i];
@ -722,6 +734,9 @@ public class TArrays extends TObject {
}
public static void sort(byte[] a, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException();
}
byte[] subarray = new byte[toIndex - fromIndex];
for (int i = fromIndex; i < toIndex; ++i) {
subarray[i - fromIndex] = a[i];
@ -784,6 +799,9 @@ public class TArrays extends TObject {
}
public static void sort(float[] a, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException();
}
float[] subarray = new float[toIndex - fromIndex];
for (int i = fromIndex; i < toIndex; ++i) {
subarray[i - fromIndex] = a[i];
@ -835,7 +853,7 @@ public class TArrays extends TObject {
}
float p = a[from];
float q = a[from2];
if (p <= q) {
if (Float.compare(p, q) <= 0) {
b[index++] = p;
++from;
} else {
@ -846,6 +864,9 @@ public class TArrays extends TObject {
}
public static void sort(double[] a, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException();
}
double[] subarray = new double[toIndex - fromIndex];
for (int i = fromIndex; i < toIndex; ++i) {
subarray[i - fromIndex] = a[i];
@ -897,7 +918,7 @@ public class TArrays extends TObject {
}
double p = a[from];
double q = a[from2];
if (p <= q) {
if (Double.compare(p, q) <= 0) {
b[index++] = p;
++from;
} else {
@ -916,6 +937,9 @@ public class TArrays extends TObject {
}
public static <T> void sort(T[] a, int fromIndex, int toIndex, TComparator<? super T> c) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException();
}
if (c == null) {
c = TComparator.NaturalOrder.instance();
}
@ -993,28 +1017,20 @@ public class TArrays extends TObject {
if (fromIndex > toIndex) {
throw new TIllegalArgumentException();
}
if (fromIndex == toIndex) {
return -1;
}
int l = fromIndex;
int u = toIndex - 1;
while (true) {
while (l <= u) {
int i = (l + u) / 2;
int e = a[i];
if (e == key) {
return i;
} else if (key < e) {
u = i - 1;
if (u < l) {
return -i - 1;
}
} else {
l = i + 1;
if (l > u) {
return -i - 2;
}
}
}
return -l - 1;
}
public static int binarySearch(long[] a, long key) {
@ -1025,28 +1041,20 @@ public class TArrays extends TObject {
if (fromIndex > toIndex) {
throw new TIllegalArgumentException();
}
if (fromIndex == toIndex) {
return -1;
}
int l = fromIndex;
int u = toIndex - 1;
while (true) {
while (l <= u) {
int i = (l + u) / 2;
long e = a[i];
if (e == key) {
return i;
} else if (e > key) {
u = i - 1;
if (u < l) {
return -i - 1;
}
} else {
l = i + 1;
if (l > u) {
return -i - 2;
}
}
}
return -l - 1;
}
public static int binarySearch(short[] a, short key) {
@ -1057,28 +1065,20 @@ public class TArrays extends TObject {
if (fromIndex > toIndex) {
throw new TIllegalArgumentException();
}
if (fromIndex == toIndex) {
return -1;
}
int l = fromIndex;
int u = toIndex - 1;
while (true) {
while (l <= u) {
int i = (l + u) / 2;
short e = a[i];
if (e == key) {
return i;
} else if (e > key) {
u = i - 1;
if (u < l) {
return -i - 1;
}
} else {
l = i + 1;
if (l > u) {
return -i - 2;
}
}
}
return -l - 1;
}
public static int binarySearch(char[] a, char key) {
@ -1089,28 +1089,20 @@ public class TArrays extends TObject {
if (fromIndex > toIndex) {
throw new TIllegalArgumentException();
}
if (fromIndex == toIndex) {
return -1;
}
int l = fromIndex;
int u = toIndex - 1;
while (true) {
while (l <= u) {
int i = (l + u) / 2;
char e = a[i];
if (e == key) {
return i;
} else if (e > key) {
u = i - 1;
if (u < l) {
return -i - 1;
}
} else {
l = i + 1;
if (l > u) {
return -i - 2;
}
}
}
return -l - 1;
}
public static int binarySearch(byte[] a, byte key) {
@ -1121,28 +1113,20 @@ public class TArrays extends TObject {
if (fromIndex > toIndex) {
throw new TIllegalArgumentException();
}
if (fromIndex == toIndex) {
return -1;
}
int l = fromIndex;
int u = toIndex - 1;
while (true) {
while (l <= u) {
int i = (l + u) / 2;
byte e = a[i];
if (e == key) {
return i;
} else if (e > key) {
u = i - 1;
if (u < l) {
return -i - 1;
}
} else {
l = i + 1;
if (l > u) {
return -i - 2;
}
}
}
return -l - 1;
}
public static int binarySearch(double[] a, double key) {
@ -1153,28 +1137,21 @@ public class TArrays extends TObject {
if (fromIndex > toIndex) {
throw new TIllegalArgumentException();
}
if (fromIndex == toIndex) {
return -1;
}
int l = fromIndex;
int u = toIndex - 1;
while (true) {
while (l <= u) {
int i = (l + u) / 2;
double e = a[i];
if (e == key) {
return i;
} else if (e > key) {
u = i - 1;
if (u < l) {
return -i - 1;
}
} else {
int cmp = Double.compare(e, key);
if (cmp < 0) {
l = i + 1;
if (l > u) {
return -i - 2;
}
} else if (cmp > 0) {
u = i - 1;
} else {
return i;
}
}
return -l - 1;
}
public static int binarySearch(float[] a, float key) {
@ -1185,28 +1162,21 @@ public class TArrays extends TObject {
if (fromIndex > toIndex) {
throw new TIllegalArgumentException();
}
if (fromIndex == toIndex) {
return -1;
}
int l = fromIndex;
int u = toIndex - 1;
while (true) {
while (l <= u) {
int i = (l + u) / 2;
float e = a[i];
if (e == key) {
return i;
} else if (e > key) {
u = i - 1;
if (u < l) {
return -i - 1;
}
} else {
int cmp = Float.compare(e, key);
if (cmp < 0) {
l = i + 1;
if (l > u) {
return -i - 2;
}
} else if (cmp > 0) {
u = i - 1;
} else {
return i;
}
}
return -l - 1;
}
public static int binarySearch(Object[] a, Object key) {
@ -1228,12 +1198,9 @@ public class TArrays extends TObject {
if (fromIndex > toIndex) {
throw new TIllegalArgumentException();
}
if (fromIndex == toIndex) {
return -1;
}
int l = fromIndex;
int u = toIndex - 1;
while (true) {
while (l <= u) {
int i = (l + u) / 2;
T e = a[i];
int cmp = c.compare(key, e);
@ -1241,16 +1208,11 @@ public class TArrays extends TObject {
return i;
} else if (cmp < 0) {
u = i - 1;
if (u < l) {
return -i - 1;
}
} else {
l = i + 1;
if (l > u) {
return -i - 2;
}
}
}
return -l - 1;
}
private static int mismatchImpl(long[] a, int aStart, long[] a2, int a2Start, int length) {
@ -1500,7 +1462,7 @@ public class TArrays extends TObject {
private static int mismatchImpl(float[] a, int aStart, float[] a2, int a2Start, int length) {
for (int i = 0; i < length; ++i) {
if (a[i + aStart] != a2[i + a2Start]) {
if (Float.compare(a[i + aStart], a2[i + a2Start]) != 0) {
return i;
}
}
@ -1549,7 +1511,7 @@ public class TArrays extends TObject {
private static int mismatchImpl(double[] a, int aStart, double[] a2, int a2Start, int length) {
for (int i = 0; i < length; ++i) {
if (a[i + aStart] != a2[i + a2Start]) {
if (Double.compare(a[i + aStart], a2[i + a2Start]) != 0) {
return i;
}
}

View File

@ -25,6 +25,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.teavm.classlib.java.lang.DoubleTest;
import org.teavm.junit.TeaVMTestRunner;
@RunWith(TeaVMTestRunner.class)
@ -40,6 +41,36 @@ public class ArraysTest {
assertEquals(Integer.valueOf(6), array[4]);
assertEquals(Integer.valueOf(7), array[5]);
Arrays.sort(array, null); // NPE check
double[] dSpecials1 = new double[] { Double.NaN, Double.MAX_VALUE,
Double.MIN_VALUE, 0d, -0d, Double.POSITIVE_INFINITY,
Double.NEGATIVE_INFINITY };
double[] dSpecials2 = new double[] { 0d, Double.POSITIVE_INFINITY, -0d,
Double.NEGATIVE_INFINITY, Double.MIN_VALUE, Double.NaN,
Double.MAX_VALUE };
double[] dSorted = new double[] { Double.NEGATIVE_INFINITY, -0d, 0d,
Double.MIN_VALUE, Double.MAX_VALUE, Double.POSITIVE_INFINITY,
Double.NaN };
Arrays.sort(dSpecials1);
assertTrue("specials sort incorrectly 1: " + Arrays.toString(dSpecials1),
Arrays.equals(dSpecials1, dSorted));
Arrays.sort(dSpecials2);
assertTrue("specials sort incorrectly 2: " + Arrays.toString(dSpecials2),
Arrays.equals(dSpecials2, dSorted));
float[] fSpecials1 = new float[] { Float.NaN, Float.MAX_VALUE,
Float.MIN_VALUE, 0f, -0f, Float.POSITIVE_INFINITY,
Float.NEGATIVE_INFINITY };
float[] fSpecials2 = new float[] { 0f, Float.POSITIVE_INFINITY, -0f,
Float.NEGATIVE_INFINITY, Float.MIN_VALUE, Float.NaN,
Float.MAX_VALUE };
float[] fSorted = new float[] { Float.NEGATIVE_INFINITY, -0f, 0f,
Float.MIN_VALUE, Float.MAX_VALUE, Float.POSITIVE_INFINITY,
Float.NaN };
Arrays.sort(fSpecials1);
assertTrue("specials sort incorrectly 1: " + Arrays.toString(fSpecials1),
Arrays.equals(fSpecials1, fSorted));
Arrays.sort(fSpecials2);
assertTrue("specials sort incorrectly 2: " + Arrays.toString(fSpecials2),
Arrays.equals(fSpecials2, fSorted));
}
@Test
@ -54,6 +85,23 @@ public class ArraysTest {
assertEquals(-8, Arrays.binarySearch(array, 15));
assertEquals(-9, Arrays.binarySearch(array, 17));
assertEquals(3, Arrays.binarySearch(array, 8, null)); // NPE check
assertEquals(-6, Arrays.binarySearch(array, 5, 5, 10));
float[] floatSpecials = new float[] { Float.NEGATIVE_INFINITY,
-Float.MAX_VALUE, -2f, -Float.MIN_VALUE, -0f, 0f,
Float.MIN_VALUE, 2f, Float.MAX_VALUE, Float.POSITIVE_INFINITY,
Float.NaN };
for (int i = 0; i < floatSpecials.length; i++) {
int result = Arrays.binarySearch(floatSpecials, floatSpecials[i]);
assertEquals(floatSpecials[i] + " invalid: " + result, result, i);
}
double[] doubleSpecials = new double[] { Double.NEGATIVE_INFINITY,
-Double.MAX_VALUE, -2d, -Double.MIN_VALUE, -0d, 0d,
Double.MIN_VALUE, 2d, Double.MAX_VALUE,
Double.POSITIVE_INFINITY, Double.NaN };
for (int i = 0; i < doubleSpecials.length; i++) {
int result = Arrays.binarySearch(doubleSpecials, doubleSpecials[i]);
assertEquals(doubleSpecials[i] + " invalid: " + result, result, i);
}
}
@Test
@ -162,10 +210,14 @@ public class ArraysTest {
int[] equal = { 1, 2, 3 };
int[] shorter = { 1, 2 };
int[] different = { 3, 1, 2 };
double[] withNaN = { 1.0, Double.NaN };
double[] withOtherNaN = { 1.0, DoubleTest.OTHER_NAN };
// Simple equals
assertTrue(Arrays.equals(array, array));
assertTrue(Arrays.equals(array, equal));
assertTrue(Arrays.equals(withNaN, withNaN));
assertTrue(Arrays.equals(withNaN, withOtherNaN));
// Equal to null
assertTrue(Arrays.equals((int[]) null, null));