Add java.util Java 8 APIs for Arrays

Change-Id: I5fa08e7b9f5361ae1f9d28b6c78e2359a0d92744
diff --git a/user/super/com/google/gwt/emul/java/util/Arrays.java b/user/super/com/google/gwt/emul/java/util/Arrays.java
index aef8ac0..72da442 100644
--- a/user/super/com/google/gwt/emul/java/util/Arrays.java
+++ b/user/super/com/google/gwt/emul/java/util/Arrays.java
@@ -19,13 +19,21 @@
 import static javaemul.internal.Coercions.ensureInt;
 import static javaemul.internal.InternalPreconditions.checkArgument;
 import static javaemul.internal.InternalPreconditions.checkArraySize;
+import static javaemul.internal.InternalPreconditions.checkCriticalArrayBounds;
 import static javaemul.internal.InternalPreconditions.checkCriticalPositionIndexes;
 import static javaemul.internal.InternalPreconditions.checkElementIndex;
 import static javaemul.internal.InternalPreconditions.checkNotNull;
-import static javaemul.internal.InternalPreconditions.checkPositionIndexes;
 
 import java.io.Serializable;
+import java.util.function.BinaryOperator;
 import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
 import java.util.function.UnaryOperator;
 
 import javaemul.internal.ArrayHelper;
@@ -129,15 +137,27 @@
    * Perform a binary search on a sorted byte array.
    *
    * @param sortedArray byte array to search
+   * @param fromIndex index of the first element to search
+   * @param toIndex index (exclusive) of the last element to search
    * @param key value to search for
    * @return the index of an element with a matching value, or a negative number
    *         which is the index of the next larger value (or just past the end
    *         of the array if the searched value is larger than all elements in
    *         the array) minus 1 (to ensure error returns are negative)
    */
-  public static int binarySearch(final byte[] sortedArray, final byte key) {
-    int low = 0;
-    int high = sortedArray.length - 1;
+  public static int binarySearch(byte[] sortedArray, int fromIndex, int toIndex, byte key) {
+    checkCriticalArrayBounds(fromIndex, toIndex, sortedArray.length);
+    return binarySearch0(sortedArray, fromIndex, toIndex, key);
+  }
+
+  public static int binarySearch(byte[] sortedArray, byte key) {
+    return binarySearch0(sortedArray, 0, sortedArray.length, key);
+  }
+
+  private static int binarySearch0(final byte[] sortedArray, int fromIndex, int toIndex,
+      final byte key) {
+    int low = fromIndex;
+    int high = toIndex - 1;
 
     while (low <= high) {
       final int mid = low + ((high - low) >> 1);
@@ -159,20 +179,32 @@
   /**
    * Perform a binary search on a sorted char array.
    *
-   * @param a char array to search
+   * @param sortedArray char array to search
+   * @param fromIndex index of the first element to search
+   * @param toIndex index (exclusive) of the last element to search
    * @param key value to search for
    * @return the index of an element with a matching value, or a negative number
    *         which is the index of the next larger value (or just past the end
    *         of the array if the searched value is larger than all elements in
    *         the array) minus 1 (to ensure error returns are negative)
    */
-  public static int binarySearch(final char[] a, final char key) {
-    int low = 0;
-    int high = a.length - 1;
+  public static int binarySearch(char[] sortedArray, int fromIndex, int toIndex, char key) {
+    checkCriticalArrayBounds(fromIndex, toIndex, sortedArray.length);
+    return binarySearch0(sortedArray, fromIndex, toIndex, key);
+  }
+
+  public static int binarySearch(char[] sortedArray, char key) {
+    return binarySearch0(sortedArray, 0, sortedArray.length, key);
+  }
+
+  private static int binarySearch0(final char[] sortedArray, int fromIndex, int toIndex,
+      final char key) {
+    int low = fromIndex;
+    int high = toIndex - 1;
 
     while (low <= high) {
       final int mid = low + ((high - low) >> 1);
-      final char midVal = a[mid];
+      final char midVal = sortedArray[mid];
 
       if (midVal < key) {
         low = mid + 1;
@@ -191,15 +223,27 @@
    * Perform a binary search on a sorted double array.
    *
    * @param sortedArray double array to search
+   * @param fromIndex index of the first element to search
+   * @param toIndex index (exclusive) of the last element to search
    * @param key value to search for
    * @return the index of an element with a matching value, or a negative number
    *         which is the index of the next larger value (or just past the end
    *         of the array if the searched value is larger than all elements in
    *         the array) minus 1 (to ensure error returns are negative)
    */
-  public static int binarySearch(final double[] sortedArray, final double key) {
-    int low = 0;
-    int high = sortedArray.length - 1;
+  public static int binarySearch(double[] sortedArray, int fromIndex, int toIndex, double key) {
+    checkCriticalArrayBounds(fromIndex, toIndex, sortedArray.length);
+    return binarySearch0(sortedArray, fromIndex, toIndex, key);
+  }
+
+  public static int binarySearch(double[] sortedArray, double key) {
+    return binarySearch0(sortedArray, 0, sortedArray.length, key);
+  }
+
+  private static int binarySearch0(final double[] sortedArray, int fromIndex, int toIndex,
+      final double key) {
+    int low = fromIndex;
+    int high = toIndex - 1;
 
     while (low <= high) {
       final int mid = low + ((high - low) >> 1);
@@ -227,15 +271,27 @@
    * to/from double may change the values slightly.
    *
    * @param sortedArray float array to search
+   * @param fromIndex index of the first element to search
+   * @param toIndex index (exclusive) of the last element to search
    * @param key value to search for
    * @return the index of an element with a matching value, or a negative number
    *         which is the index of the next larger value (or just past the end
    *         of the array if the searched value is larger than all elements in
    *         the array) minus 1 (to ensure error returns are negative)
    */
-  public static int binarySearch(final float[] sortedArray, final float key) {
-    int low = 0;
-    int high = sortedArray.length - 1;
+  public static int binarySearch(float[] sortedArray, int fromIndex, int toIndex, float key) {
+    checkCriticalArrayBounds(fromIndex, toIndex, sortedArray.length);
+    return binarySearch0(sortedArray, fromIndex, toIndex, key);
+  }
+
+  public static int binarySearch(float[] sortedArray, float key) {
+    return binarySearch0(sortedArray, 0, sortedArray.length, key);
+  }
+
+  private static int binarySearch0(final float[] sortedArray, int fromIndex, int toIndex,
+      final float key) {
+    int low = fromIndex;
+    int high = toIndex - 1;
 
     while (low <= high) {
       final int mid = low + ((high - low) >> 1);
@@ -258,15 +314,27 @@
    * Perform a binary search on a sorted int array.
    *
    * @param sortedArray int array to search
+   * @param fromIndex index of the first element to search
+   * @param toIndex index (exclusive) of the last element to search
    * @param key value to search for
    * @return the index of an element with a matching value, or a negative number
    *         which is the index of the next larger value (or just past the end
    *         of the array if the searched value is larger than all elements in
    *         the array) minus 1 (to ensure error returns are negative)
    */
-  public static int binarySearch(final int[] sortedArray, final int key) {
-    int low = 0;
-    int high = sortedArray.length - 1;
+  public static int binarySearch(int[] sortedArray, int fromIndex, int toIndex, int key) {
+    checkCriticalArrayBounds(fromIndex, toIndex, sortedArray.length);
+    return binarySearch0(sortedArray, fromIndex, toIndex, key);
+  }
+
+  public static int binarySearch(int[] sortedArray, int key) {
+    return binarySearch0(sortedArray, 0, sortedArray.length, key);
+  }
+
+  private static int binarySearch0(final int[] sortedArray, int fromIndex, int toIndex,
+      final int key) {
+    int low = fromIndex;
+    int high = toIndex - 1;
 
     while (low <= high) {
       final int mid = low + ((high - low) >> 1);
@@ -295,15 +363,27 @@
    * representable as doubles.
    *
    * @param sortedArray long array to search
+   * @param fromIndex index of the first element to search
+   * @param toIndex index (exclusive) of the last element to search
    * @param key value to search for
    * @return the index of an element with a matching value, or a negative number
    *         which is the index of the next larger value (or just past the end
    *         of the array if the searched value is larger than all elements in
    *         the array) minus 1 (to ensure error returns are negative)
    */
-  public static int binarySearch(final long[] sortedArray, final long key) {
-    int low = 0;
-    int high = sortedArray.length - 1;
+  public static int binarySearch(long[] sortedArray, int fromIndex, int toIndex, long key) {
+    checkCriticalArrayBounds(fromIndex, toIndex, sortedArray.length);
+    return binarySearch0(sortedArray, fromIndex, toIndex, key);
+  }
+
+  public static int binarySearch(long[] sortedArray, long key) {
+    return binarySearch0(sortedArray, 0, sortedArray.length, key);
+  }
+
+  private static int binarySearch0(final long[] sortedArray, int fromIndex, int toIndex,
+      final long key) {
+    int low = fromIndex;
+    int high = toIndex - 1;
 
     while (low <= high) {
       final int mid = low + ((high - low) >> 1);
@@ -326,6 +406,8 @@
    * Perform a binary search on a sorted object array, using natural ordering.
    *
    * @param sortedArray object array to search
+   * @param fromIndex index of the first element to search
+   * @param toIndex index (exclusive) of the last element to search
    * @param key value to search for
    * @return the index of an element with a matching value, or a negative number
    *         which is the index of the next larger value (or just past the end
@@ -334,23 +416,39 @@
    * @throws ClassCastException if <code>key</code> is not comparable to
    *           <code>sortedArray</code>'s elements.
    */
-  public static int binarySearch(final Object[] sortedArray, final Object key) {
-    return binarySearch(sortedArray, key, Comparators.natural());
+  public static int binarySearch(Object[] sortedArray, int fromIndex, int toIndex, Object key) {
+    return binarySearch(sortedArray, fromIndex, toIndex, key, null);
+  }
+
+  public static int binarySearch(Object[] sortedArray, Object key) {
+    return binarySearch(sortedArray, key, null);
   }
 
   /**
    * Perform a binary search on a sorted short array.
    *
    * @param sortedArray short array to search
+   * @param fromIndex index of the first element to search
+   * @param toIndex index (exclusive) of the last element to search
    * @param key value to search for
    * @return the index of an element with a matching value, or a negative number
    *         which is the index of the next larger value (or just past the end
    *         of the array if the searched value is larger than all elements in
    *         the array) minus 1 (to ensure error returns are negative)
    */
-  public static int binarySearch(final short[] sortedArray, final short key) {
-    int low = 0;
-    int high = sortedArray.length - 1;
+  public static int binarySearch(short[] sortedArray, int fromIndex, int toIndex, short key) {
+    checkCriticalArrayBounds(fromIndex, toIndex, sortedArray.length);
+    return binarySearch0(sortedArray, fromIndex, toIndex, key);
+  }
+
+  public static int binarySearch(short[] sortedArray, short key) {
+    return binarySearch0(sortedArray, 0, sortedArray.length, key);
+  }
+
+  private static int binarySearch0(final short[] sortedArray, int fromIndex, int toIndex,
+      final short key) {
+    int low = fromIndex;
+    int high = toIndex - 1;
 
     while (low <= high) {
       final int mid = low + ((high - low) >> 1);
@@ -374,6 +472,8 @@
    * comparison function.
    *
    * @param sortedArray object array to search
+   * @param fromIndex index of the first element to search
+   * @param toIndex index (exclusive) of the last element to search
    * @param key value to search for
    * @param comparator comparision function, <code>null</code> indicates
    *          <i>natural ordering</i> should be used.
@@ -385,13 +485,23 @@
    *           <code>sortedArray</code>'s elements cannot be compared by
    *           <code>comparator</code>.
    */
-  public static <T> int binarySearch(final T[] sortedArray, final T key,
+  public static <T> int binarySearch(T[] sortedArray, int fromIndex, int toIndex, T key,
       Comparator<? super T> comparator) {
+    checkCriticalArrayBounds(fromIndex, toIndex, sortedArray.length);
+    return binarySearch0(sortedArray, fromIndex, toIndex, key, comparator);
+  }
+
+  public static <T> int binarySearch(T[] sortedArray, T key, Comparator<? super T> c) {
+    return binarySearch0(sortedArray, 0, sortedArray.length, key, c);
+  }
+
+  private static <T> int binarySearch0(final T[] sortedArray, int fromIndex, int toIndex,
+      final T key, Comparator<? super T> comparator) {
     if (comparator == null) {
       comparator = Comparators.natural();
     }
-    int low = 0;
-    int high = sortedArray.length - 1;
+    int low = fromIndex;
+    int high = toIndex - 1;
 
     while (low <= high) {
       final int mid = low + ((high - low) >> 1);
@@ -788,93 +898,138 @@
   }
 
   public static void fill(boolean[] a, boolean val) {
-    fill(a, 0, a.length, val);
+    fill0(a, 0, a.length, val);
   }
 
   public static void fill(boolean[] a, int fromIndex, int toIndex, boolean val) {
+    checkCriticalArrayBounds(fromIndex, toIndex, a.length);
+    fill0(a, fromIndex, toIndex, val);
+  }
+
+  private static void fill0(boolean[] a, int fromIndex, int toIndex, boolean val) {
     for (int i = fromIndex; i < toIndex; ++i) {
       a[i] = val;
     }
   }
 
   public static void fill(byte[] a, byte val) {
-    fill(a, 0, a.length, val);
+    fill0(a, 0, a.length, val);
   }
 
   public static void fill(byte[] a, int fromIndex, int toIndex, byte val) {
+    checkCriticalArrayBounds(fromIndex, toIndex, a.length);
+    fill0(a, fromIndex, toIndex, val);
+  }
+
+  private static void fill0(byte[] a, int fromIndex, int toIndex, byte val) {
     for (int i = fromIndex; i < toIndex; ++i) {
       a[i] = val;
     }
   }
 
   public static void fill(char[] a, char val) {
-    fill(a, 0, a.length, val);
+    fill0(a, 0, a.length, val);
   }
 
   public static void fill(char[] a, int fromIndex, int toIndex, char val) {
+    checkCriticalArrayBounds(fromIndex, toIndex, a.length);
+    fill0(a, fromIndex, toIndex, val);
+  }
+
+  private static void fill0(char[] a, int fromIndex, int toIndex, char val) {
     for (int i = fromIndex; i < toIndex; ++i) {
       a[i] = val;
     }
   }
 
   public static void fill(double[] a, double val) {
-    fill(a, 0, a.length, val);
+    fill0(a, 0, a.length, val);
   }
 
   public static void fill(double[] a, int fromIndex, int toIndex, double val) {
+    checkCriticalArrayBounds(fromIndex, toIndex, a.length);
+    fill0(a, fromIndex, toIndex, val);
+  }
+
+  private static void fill0(double[] a, int fromIndex, int toIndex, double val) {
     for (int i = fromIndex; i < toIndex; ++i) {
       a[i] = val;
     }
   }
 
   public static void fill(float[] a, float val) {
-    fill(a, 0, a.length, val);
+    fill0(a, 0, a.length, val);
   }
 
   public static void fill(float[] a, int fromIndex, int toIndex, float val) {
+    checkCriticalArrayBounds(fromIndex, toIndex, a.length);
+    fill0(a, fromIndex, toIndex, val);
+  }
+
+  private static void fill0(float[] a, int fromIndex, int toIndex, float val) {
     for (int i = fromIndex; i < toIndex; ++i) {
       a[i] = val;
     }
   }
 
   public static void fill(int[] a, int val) {
-    fill(a, 0, a.length, val);
+    fill0(a, 0, a.length, val);
   }
 
   public static void fill(int[] a, int fromIndex, int toIndex, int val) {
+    checkCriticalArrayBounds(fromIndex, toIndex, a.length);
+    fill0(a, fromIndex, toIndex, val);
+  }
+
+  private static void fill0(int[] a, int fromIndex, int toIndex, int val) {
     for (int i = fromIndex; i < toIndex; ++i) {
       a[i] = val;
     }
   }
 
   public static void fill(long[] a, int fromIndex, int toIndex, long val) {
+    checkCriticalArrayBounds(fromIndex, toIndex, a.length);
+    fill0(a, fromIndex, toIndex, val);
+  }
+
+  private static void fill0(long[] a, int fromIndex, int toIndex, long val) {
     for (int i = fromIndex; i < toIndex; ++i) {
       a[i] = val;
     }
   }
 
   public static void fill(long[] a, long val) {
-    fill(a, 0, a.length, val);
+    fill0(a, 0, a.length, val);
   }
 
   public static void fill(Object[] a, int fromIndex, int toIndex, Object val) {
+    checkCriticalArrayBounds(fromIndex, toIndex, a.length);
+    fill0(a, fromIndex, toIndex, val);
+  }
+
+  private static void fill0(Object[] a, int fromIndex, int toIndex, Object val) {
     for (int i = fromIndex; i < toIndex; ++i) {
       a[i] = val;
     }
   }
 
   public static void fill(Object[] a, Object val) {
-    fill(a, 0, a.length, val);
+    fill0(a, 0, a.length, val);
   }
 
   public static void fill(short[] a, int fromIndex, int toIndex, short val) {
+    checkCriticalArrayBounds(fromIndex, toIndex, a.length);
+    fill0(a, fromIndex, toIndex, val);
+  }
+
+  private static void fill0(short[] a, int fromIndex, int toIndex, short val) {
     for (int i = fromIndex; i < toIndex; ++i) {
       a[i] = val;
     }
   }
 
   public static void fill(short[] a, short val) {
-    fill(a, 0, a.length, val);
+    fill0(a, 0, a.length, val);
   }
 
   public static int hashCode(boolean[] a) {
@@ -985,12 +1140,132 @@
     return hashCode;
   }
 
+  public static void parallelPrefix(double[] array, DoubleBinaryOperator op) {
+    parallelPrefix0(array, 0, array.length, op);
+  }
+
+  public static void parallelPrefix(double[] array, int fromIndex, int toIndex,
+      DoubleBinaryOperator op) {
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
+    parallelPrefix0(array, fromIndex, toIndex, op);
+  }
+
+  private static void parallelPrefix0(double[] array, int fromIndex, int toIndex,
+      DoubleBinaryOperator op) {
+    checkNotNull(op);
+    double acc = array[fromIndex];
+    for (int i = fromIndex + 1; i < toIndex; i++) {
+      array[i] = acc = op.applyAsDouble(acc, array[i]);
+    }
+  }
+
+  public static void parallelPrefix(int[] array, IntBinaryOperator op) {
+    parallelPrefix0(array, 0, array.length, op);
+  }
+
+  public static void parallelPrefix(int[] array, int fromIndex, int toIndex,
+      IntBinaryOperator op) {
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
+    parallelPrefix0(array, fromIndex, toIndex, op);
+  }
+
+  private static void parallelPrefix0(int[] array, int fromIndex, int toIndex,
+      IntBinaryOperator op) {
+    checkNotNull(op);
+    int acc = array[fromIndex];
+    for (int i = fromIndex + 1; i < toIndex; i++) {
+      array[i] = acc = op.applyAsInt(acc, array[i]);
+    }
+  }
+
+  public static void parallelPrefix(long[] array, LongBinaryOperator op) {
+    parallelPrefix0(array, 0, array.length, op);
+  }
+
+  public static void parallelPrefix(long[] array, int fromIndex, int toIndex,
+      LongBinaryOperator op) {
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
+    parallelPrefix0(array, fromIndex, toIndex, op);
+  }
+
+  private static void parallelPrefix0(long[] array, int fromIndex, int toIndex,
+      LongBinaryOperator op) {
+    checkNotNull(op);
+    long acc = array[fromIndex];
+    for (int i = fromIndex + 1; i < toIndex; i++) {
+      array[i] = acc = op.applyAsLong(acc, array[i]);
+    }
+  }
+
+  public static <T> void parallelPrefix(T[] array, BinaryOperator<T> op) {
+    parallelPrefix0(array, 0, array.length, op);
+  }
+
+  public static <T> void parallelPrefix(T[] array, int fromIndex, int toIndex,
+      BinaryOperator<T> op) {
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
+    parallelPrefix0(array, fromIndex, toIndex, op);
+  }
+
+  private static <T> void parallelPrefix0(T[] array, int fromIndex, int toIndex,
+      BinaryOperator<T> op) {
+    checkNotNull(op);
+    T acc = array[fromIndex];
+    for (int i = fromIndex + 1; i < toIndex; i++) {
+      array[i] = acc = op.apply(acc, array[i]);
+    }
+  }
+
+  public static <T> void setAll(T[] array, IntFunction<? extends T> generator) {
+    checkNotNull(generator);
+    for (int i = 0; i < array.length; i++) {
+      array[i] = generator.apply(i);
+    }
+  }
+
+  public static void setAll(double[] array, IntToDoubleFunction generator) {
+    checkNotNull(generator);
+    for (int i = 0; i < array.length; i++) {
+      array[i] = generator.applyAsDouble(i);
+    }
+  }
+
+  public static void setAll(int[] array, IntUnaryOperator generator) {
+    checkNotNull(generator);
+    for (int i = 0; i < array.length; i++) {
+      array[i] = generator.applyAsInt(i);
+    }
+  }
+
+  public static void setAll(long[] array, IntToLongFunction generator) {
+    checkNotNull(generator);
+    for (int i = 0; i < array.length; i++) {
+      array[i] = generator.applyAsLong(i);
+    }
+  }
+
+  public static <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator) {
+    setAll(array, generator);
+  }
+
+  public static void parallelSetAll(double[] array, IntToDoubleFunction generator) {
+    setAll(array, generator);
+  }
+
+  public static void parallelSetAll(int[] array, IntUnaryOperator generator) {
+    setAll(array, generator);
+  }
+
+  public static void parallelSetAll(long[] array, IntToLongFunction generator) {
+    setAll(array, generator);
+  }
+
   public static void sort(byte[] array) {
     nativeNumberSort(array);
   }
 
   public static void sort(byte[] array, int fromIndex, int toIndex) {
-    checkPositionIndexes(fromIndex, toIndex, array.length);
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
     nativeNumberSort(array, fromIndex, toIndex);
   }
 
@@ -999,7 +1274,7 @@
   }
 
   public static void sort(char[] array, int fromIndex, int toIndex) {
-    checkPositionIndexes(fromIndex, toIndex, array.length);
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
     nativeNumberSort(array, fromIndex, toIndex);
   }
 
@@ -1008,7 +1283,7 @@
   }
 
   public static void sort(double[] array, int fromIndex, int toIndex) {
-    checkPositionIndexes(fromIndex, toIndex, array.length);
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
     nativeNumberSort(array, fromIndex, toIndex);
   }
 
@@ -1017,7 +1292,7 @@
   }
 
   public static void sort(float[] array, int fromIndex, int toIndex) {
-    checkPositionIndexes(fromIndex, toIndex, array.length);
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
     nativeNumberSort(array, fromIndex, toIndex);
   }
 
@@ -1026,7 +1301,7 @@
   }
 
   public static void sort(int[] array, int fromIndex, int toIndex) {
-    checkPositionIndexes(fromIndex, toIndex, array.length);
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
     nativeNumberSort(array, fromIndex, toIndex);
   }
 
@@ -1035,16 +1310,16 @@
   }
 
   public static void sort(long[] array, int fromIndex, int toIndex) {
-    checkPositionIndexes(fromIndex, toIndex, array.length);
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
     nativeLongSort(array, fromIndex, toIndex);
   }
 
   public static void sort(Object[] array) {
-    mergeSort(array, 0, array.length, Comparators.natural());
+    sort(array, null);
   }
 
-  public static void sort(Object[] x, int fromIndex, int toIndex) {
-    mergeSort(x, fromIndex, toIndex, Comparators.natural());
+  public static void sort(Object[] array, int fromIndex, int toIndex) {
+    sort(array, fromIndex, toIndex, null);
   }
 
   public static void sort(short[] array) {
@@ -1052,7 +1327,7 @@
   }
 
   public static void sort(short[] array, int fromIndex, int toIndex) {
-    checkPositionIndexes(fromIndex, toIndex, array.length);
+    checkCriticalArrayBounds(fromIndex, toIndex, array.length);
     nativeNumberSort(array, fromIndex, toIndex);
   }
 
@@ -1062,10 +1337,84 @@
 
   public static <T> void sort(T[] x, int fromIndex, int toIndex,
       Comparator<? super T> c) {
-    checkPositionIndexes(fromIndex, toIndex, x.length);
+    checkCriticalArrayBounds(fromIndex, toIndex, x.length);
     mergeSort(x, fromIndex, toIndex, c);
   }
 
+  public static void parallelSort(byte[] array) {
+    sort(array);
+  }
+
+  public static void parallelSort(byte[] array, int fromIndex, int toIndex) {
+    sort(array, fromIndex, toIndex);
+  }
+
+  public static void parallelSort(char[] array) {
+    sort(array);
+  }
+
+  public static void parallelSort(char[] array, int fromIndex, int toIndex) {
+    sort(array, fromIndex, toIndex);
+  }
+
+  public static void parallelSort(double[] array) {
+    sort(array);
+  }
+
+  public static void parallelSort(double[] array, int fromIndex, int toIndex) {
+    sort(array, fromIndex, toIndex);
+  }
+
+  public static void parallelSort(float[] array) {
+    sort(array);
+  }
+
+  public static void parallelSort(float[] array, int fromIndex, int toIndex) {
+    sort(array, fromIndex, toIndex);
+  }
+
+  public static void parallelSort(int[] array) {
+    sort(array);
+  }
+
+  public static void parallelSort(int[] array, int fromIndex, int toIndex) {
+    sort(array, fromIndex, toIndex);
+  }
+
+  public static void parallelSort(long[] array) {
+    sort(array);
+  }
+
+  public static void parallelSort(long[] array, int fromIndex, int toIndex) {
+    sort(array, fromIndex, toIndex);
+  }
+
+  public static void parallelSort(short[] array) {
+    sort(array);
+  }
+
+  public static void parallelSort(short[] array, int fromIndex, int toIndex) {
+    sort(array, fromIndex, toIndex);
+  }
+
+  public static <T extends Comparable<? super T>> void parallelSort(T[] array) {
+    sort(array);
+  }
+
+  public static <T> void parallelSort(T[] array, Comparator<? super T> c) {
+    sort(array, c);
+  }
+
+  public static <T extends Comparable<? super T>> void parallelSort(T[] array,
+      int fromIndex, int toIndex) {
+    sort(array, fromIndex, toIndex);
+  }
+
+  public static <T> void parallelSort(T[] array, int fromIndex, int toIndex,
+      Comparator<? super T> c) {
+    sort(array, fromIndex, toIndex, c);
+  }
+
   public static Spliterator.OfDouble spliterator(double[] array) {
     return Spliterators.spliterator(array, Spliterator.IMMUTABLE | Spliterator.ORDERED);
   }
diff --git a/user/test/com/google/gwt/emultest/EmulJava8Suite.java b/user/test/com/google/gwt/emultest/EmulJava8Suite.java
index ae851bc..62c6526 100644
--- a/user/test/com/google/gwt/emultest/EmulJava8Suite.java
+++ b/user/test/com/google/gwt/emultest/EmulJava8Suite.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.emultest.java8.math.BigIntegerConvertTest;
 import com.google.gwt.emultest.java8.util.ArrayListTest;
+import com.google.gwt.emultest.java8.util.ArraysTest;
 import com.google.gwt.emultest.java8.util.ComparatorTest;
 import com.google.gwt.emultest.java8.util.DoubleSummaryStatisticsTest;
 import com.google.gwt.emultest.java8.util.HashMapTest;
@@ -53,6 +54,7 @@
     suite.addTestSuite(BigIntegerConvertTest.class);
 
     //-- java.util
+    suite.addTestSuite(ArraysTest.class);
     suite.addTestSuite(ArrayListTest.class);
     suite.addTestSuite(LinkedListTest.class);
     suite.addTestSuite(ListTest.class);
diff --git a/user/test/com/google/gwt/emultest/java/util/ArraysTest.java b/user/test/com/google/gwt/emultest/java/util/ArraysTest.java
index 20e095e..a9a79c7 100644
--- a/user/test/com/google/gwt/emultest/java/util/ArraysTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/ArraysTest.java
@@ -16,6 +16,7 @@
 package com.google.gwt.emultest.java.util;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
@@ -201,11 +202,13 @@
     byte[] a1 = {};
     int ret = Arrays.binarySearch(a1, (byte) 0);
     assertEquals(-1, ret);
+
     byte[] a2 = {1, 7, 31};
     ret = Arrays.binarySearch(a2, (byte) 3);
     assertEquals(-2, ret);
     ret = Arrays.binarySearch(a2, (byte) 31);
     assertEquals(2, ret);
+
     byte[] a3 = {-71, 0, 35, 36};
     ret = Arrays.binarySearch(a3, (byte) 42);
     assertEquals(-5, ret);
@@ -213,6 +216,10 @@
     assertEquals(-1, ret);
     ret = Arrays.binarySearch(a3, (byte) -71);
     assertEquals(0, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, (byte) 35);
+    assertEquals(2, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, (byte) -71);
+    assertEquals(-2, ret);
   }
 
   /**
@@ -231,11 +238,13 @@
     char[] a1 = {};
     int ret = Arrays.binarySearch(a1, (char) 0);
     assertEquals(-1, ret);
+
     char[] a2 = {1, 7, 31};
     ret = Arrays.binarySearch(a2, (char) 3);
     assertEquals(-2, ret);
     ret = Arrays.binarySearch(a2, (char) 31);
     assertEquals(2, ret);
+
     char[] a3 = {1, 2, 35, 36};
     ret = Arrays.binarySearch(a3, (char) 42);
     assertEquals(-5, ret);
@@ -243,6 +252,10 @@
     assertEquals(-1, ret);
     ret = Arrays.binarySearch(a3, (char) 1);
     assertEquals(0, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, (char) 35);
+    assertEquals(2, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, (char) 1);
+    assertEquals(-2, ret);
   }
 
   /**
@@ -262,11 +275,13 @@
     double[] a1 = {};
     int ret = Arrays.binarySearch(a1, 0);
     assertEquals(-1, ret);
+
     double[] a2 = {1, 7, 31};
     ret = Arrays.binarySearch(a2, 3);
     assertEquals(-2, ret);
     ret = Arrays.binarySearch(a2, 31);
     assertEquals(2, ret);
+
     double[] a3 = {-71, 0, 35, 36};
     ret = Arrays.binarySearch(a3, 42);
     assertEquals(-5, ret);
@@ -274,6 +289,10 @@
     assertEquals(-1, ret);
     ret = Arrays.binarySearch(a3, -71);
     assertEquals(0, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, 35);
+    assertEquals(2, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, -71);
+    assertEquals(-2, ret);
   }
 
   /**
@@ -293,11 +312,13 @@
     float[] a1 = {};
     int ret = Arrays.binarySearch(a1, 0);
     assertEquals(-1, ret);
+
     float[] a2 = {1, 7, 31};
     ret = Arrays.binarySearch(a2, 3);
     assertEquals(-2, ret);
     ret = Arrays.binarySearch(a2, 31);
     assertEquals(2, ret);
+
     float[] a3 = {-71, 0, 35, 36};
     ret = Arrays.binarySearch(a3, 42);
     assertEquals(-5, ret);
@@ -305,6 +326,10 @@
     assertEquals(-1, ret);
     ret = Arrays.binarySearch(a3, -71);
     assertEquals(0, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, 35);
+    assertEquals(2, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, -71);
+    assertEquals(-2, ret);
   }
 
   /**
@@ -324,11 +349,13 @@
     int[] a1 = {};
     int ret = Arrays.binarySearch(a1, 0);
     assertEquals(-1, ret);
+
     int[] a2 = {1, 7, 31};
     ret = Arrays.binarySearch(a2, 3);
     assertEquals(-2, ret);
     ret = Arrays.binarySearch(a2, 31);
     assertEquals(2, ret);
+
     int[] a3 = {-71, 0, 35, 36};
     ret = Arrays.binarySearch(a3, 42);
     assertEquals(-5, ret);
@@ -336,6 +363,10 @@
     assertEquals(-1, ret);
     ret = Arrays.binarySearch(a3, -71);
     assertEquals(0, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, 35);
+    assertEquals(2, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, -71);
+    assertEquals(-2, ret);
   }
 
   /**
@@ -355,11 +386,13 @@
     long[] a1 = {};
     int ret = Arrays.binarySearch(a1, 0L);
     assertEquals(-1, ret);
+
     long[] a2 = {1, 7, 31};
     ret = Arrays.binarySearch(a2, 3L);
     assertEquals(-2, ret);
     ret = Arrays.binarySearch(a2, 31L);
     assertEquals(2, ret);
+
     long[] a3 = {-71, 0, 35, 36};
     ret = Arrays.binarySearch(a3, 42L);
     assertEquals(-5, ret);
@@ -367,6 +400,10 @@
     assertEquals(-1, ret);
     ret = Arrays.binarySearch(a3, -71L);
     assertEquals(0, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, 35);
+    assertEquals(2, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, -71);
+    assertEquals(-2, ret);
   }
 
   /**
@@ -385,11 +422,13 @@
     Object[] a1 = {};
     int ret = Arrays.binarySearch(a1, "");
     assertEquals(-1, ret);
+
     Object[] a2 = {"a", "g", "y"};
     ret = Arrays.binarySearch(a2, "c");
     assertEquals(-2, ret);
     ret = Arrays.binarySearch(a2, "y");
     assertEquals(2, ret);
+
     Object[] a3 = {"b", "c", "x", "y"};
     ret = Arrays.binarySearch(a3, "z");
     assertEquals(-5, ret);
@@ -397,6 +436,10 @@
     assertEquals(-1, ret);
     ret = Arrays.binarySearch(a3, "b");
     assertEquals(0, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, "x");
+    assertEquals(2, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, "b");
+    assertEquals(-2, ret);
   }
 
   /**
@@ -414,20 +457,17 @@
    */
   @SuppressWarnings("unchecked")
   public void testBinarySearchObjectComparator() {
-    Comparator inverseSort = new Comparator() {
-      @Override
-      public int compare(Object o1, Object o2) {
-        return ((Comparable) o2).compareTo(o1);
-      }
-    };
+    final Comparator inverseSort = Collections.reverseOrder();
     Object[] a1 = {};
     int ret = Arrays.binarySearch(a1, "", inverseSort);
     assertEquals(-1, ret);
+
     Object[] a2 = {"y", "g", "a"};
     ret = Arrays.binarySearch(a2, "c", inverseSort);
     assertEquals(-3, ret);
     ret = Arrays.binarySearch(a2, "a", inverseSort);
     assertEquals(2, ret);
+
     Object[] a3 = {"y", "x", "c", "b"};
     ret = Arrays.binarySearch(a3, "a", inverseSort);
     assertEquals(-5, ret);
@@ -435,6 +475,10 @@
     assertEquals(-1, ret);
     ret = Arrays.binarySearch(a3, "y", inverseSort);
     assertEquals(0, ret);
+    ret = Arrays.binarySearch(a3, 1, 3, "x", inverseSort);
+    assertEquals(1, ret);
+    ret = Arrays.binarySearch(a3, 1, 3, "b", inverseSort);
+    assertEquals(-4, ret);
 
     Object[] a4 = {"a", "b", "c", "d", "e"};
     ret = Arrays.binarySearch(a4, "d", null); // should not NPE
@@ -458,11 +502,13 @@
     short[] a1 = {};
     int ret = Arrays.binarySearch(a1, (short) 0);
     assertEquals(-1, ret);
+
     short[] a2 = {1, 7, 31};
     ret = Arrays.binarySearch(a2, (short) 3);
     assertEquals(-2, ret);
     ret = Arrays.binarySearch(a2, (short) 31);
     assertEquals(2, ret);
+
     short[] a3 = {-71, 0, 35, 36};
     ret = Arrays.binarySearch(a3, (short) 42);
     assertEquals(-5, ret);
@@ -470,6 +516,10 @@
     assertEquals(-1, ret);
     ret = Arrays.binarySearch(a3, (short) -71);
     assertEquals(0, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, (short) 35);
+    assertEquals(2, ret);
+    ret = Arrays.binarySearch(a3, 1, 4, (short) -71);
+    assertEquals(-2, ret);
   }
 
   /**
@@ -1159,14 +1209,29 @@
    * Tests sorting of long primitives.
    */
   public void testLongSort() {
-    long[] x = {3, 11, 2, 1, 22, 3};
-    Arrays.sort(x);
-    assertEquals(1, x[0]);
-    assertEquals(2, x[1]);
-    assertEquals(3, x[2]);
-    assertEquals(3, x[3]);
-    assertEquals(11, x[4]);
-    assertEquals(22, x[5]);
+    long[] array = new long[0];
+    Arrays.sort(array);
+
+    array = new long[]{Long.MIN_VALUE, 1, 2, 3, Long.MAX_VALUE};
+    Arrays.sort(array);
+    assertTrue(Arrays.equals(new long[]{Long.MIN_VALUE, 1, 2, 3, Long.MAX_VALUE}, array));
+
+    array = new long[]{3, Long.MAX_VALUE, 3, 2, 1, Long.MIN_VALUE};
+    Arrays.sort(array);
+    assertTrue(Arrays.equals(new long[]{Long.MIN_VALUE, 1, 2, 3, 3, Long.MAX_VALUE}, array));
+  }
+
+  /**
+   * Tests sorting of long primitives sub-range.
+   */
+  public void testLongSubrangeSort() {
+    long[] array = new long[]{3, Long.MAX_VALUE, 3, 2, 1, Long.MIN_VALUE};
+    Arrays.sort(array, 2, 5);
+    assertTrue(Arrays.equals(new long[]{3, Long.MAX_VALUE, 1, 2, 3, Long.MIN_VALUE}, array));
+
+    array = new long[]{3, Long.MAX_VALUE, 3, 2, 1, Long.MIN_VALUE};
+    Arrays.sort(array, 0, 0);
+    assertTrue(Arrays.equals(new long[]{3, Long.MAX_VALUE, 3, 2, 1, Long.MIN_VALUE}, array));
   }
 
   /**
@@ -1183,28 +1248,29 @@
    * Tests sorting primitives.
    */
   public void testPrimitiveSort() {
-    int[] x = {3, 11, 2, 1, 22, 3};
-    Arrays.sort(x);
-    assertEquals(1, x[0]);
-    assertEquals(2, x[1]);
-    assertEquals(3, x[2]);
-    assertEquals(3, x[3]);
-    assertEquals(11, x[4]);
-    assertEquals(22, x[5]);
+    int[] array = new int[0];
+    Arrays.sort(array);
+
+    array = new int[]{Integer.MIN_VALUE, 1, 2, 3, Integer.MAX_VALUE};
+    Arrays.sort(array);
+    assertTrue(Arrays.equals(new int[]{Integer.MIN_VALUE, 1, 2, 3, Integer.MAX_VALUE}, array));
+
+    array = new int[]{3, Integer.MAX_VALUE, 3, 2, 1, Integer.MIN_VALUE};
+    Arrays.sort(array);
+    assertTrue(Arrays.equals(new int[]{Integer.MIN_VALUE, 1, 2, 3, 3, Integer.MAX_VALUE}, array));
   }
 
   /**
    * Tests sorting a subrange of a primitive array.
    */
   public void testPrimitiveSubrangeSort() {
-    int[] x = {3, 11, 2, 1, 22, 3};
-    Arrays.sort(x, 1, 5);
-    assertEquals(3, x[0]);
-    assertEquals(1, x[1]);
-    assertEquals(2, x[2]);
-    assertEquals(11, x[3]);
-    assertEquals(22, x[4]);
-    assertEquals(3, x[5]);
+    int[] array = new int[]{3, Integer.MAX_VALUE, 3, 2, 1, Integer.MIN_VALUE};
+    Arrays.sort(array, 2, 5);
+    assertTrue(Arrays.equals(new int[]{3, Integer.MAX_VALUE, 1, 2, 3, Integer.MIN_VALUE}, array));
+
+    array = new int[]{3, Integer.MAX_VALUE, 3, 2, 1, Integer.MIN_VALUE};
+    Arrays.sort(array, 0, 0);
+    assertTrue(Arrays.equals(new int[]{3, Integer.MAX_VALUE, 3, 2, 1, Integer.MIN_VALUE}, array));
   }
 
   /**
@@ -1231,25 +1297,48 @@
    * Tests {@link Arrays#sort(Object[], Comparator)}.
    */
   public void testSort() {
-    Object[] x = {"c", "b", "b", "a"};
-    int hash = x[1].hashCode();
-    Arrays.sort(x);
-    int hash2 = x[1].hashCode();
-    assertEquals(hash, hash2);
-    Object[] sorted = {"a", "b", "b", "c"};
-    assertEquals(x, sorted);
-    Comparator<Object> t = new Comparator<Object>() {
+    Object[] array = {"c", "b", "b", "a"};
+    Arrays.sort(array);
+    assertEquals(new Object[]{"a", "b", "b", "c"}, array);
+
+    array = new Object[]{"c", "b", "b", "a"};
+    Comparator<Object> natural = new Comparator<Object>() {
       @Override
       @SuppressWarnings("unchecked")
-      public int compare(Object o1, Object o2) {
-        return ((Comparable<Object>) o2).compareTo(o1);
+      public int compare(Object a, Object b) {
+        return ((Comparable<Object>) a).compareTo(b);
       }
     };
-    Arrays.sort(x, t);
-    int hash3 = x[1].hashCode();
-    assertEquals(hash, hash3);
-    Object[] reverseSorted = {"c", "b", "b", "a"};
-    assertEquals(x, reverseSorted);
+    Arrays.sort(array, natural);
+    assertEquals(new Object[]{"a", "b", "b", "c"}, array);
+
+    array = new Object[]{"c", "b", "b", "a"};
+    Arrays.sort(array, Collections.reverseOrder());
+    assertEquals(new Object[]{"c", "b", "b", "a"}, array);
+
+    array = new Object[]{"c", "b", "b", "a"};
+    Arrays.sort(array, null);
+    assertEquals(new Object[]{"a", "b", "b", "c"}, array);
+  }
+
+  /**
+   * Tests sorting of Object array sub-range.
+   */
+  public void testSortSubRange() {
+    Object[] array = {"c", "b", "b", "a"};
+    Arrays.sort(array, 0, 0);
+    assertEquals(new Object[]{"c", "b", "b", "a"}, array);
+
+    array = new Object[]{"c", "b", "b", "a"};
+    Arrays.sort(array, 1, 2);
+    assertEquals(new Object[]{"c", "b", "b", "a"}, array);
+
+    Arrays.sort(array, 1, 4);
+    assertEquals(new Object[]{"c", "a", "b", "b"}, array);
+
+    array = new Object[]{"c", "b", "b", "a"};
+    Arrays.sort(array, 1, 4, Collections.reverseOrder());
+    assertEquals(new Object[]{"c", "b", "b", "a"}, array);
   }
 
   /**
@@ -1261,6 +1350,17 @@
    * test.
    */
   public void testStableSort() {
+    Comparator<TestObject> comparator = new Comparator<TestObject>() {
+      @Override
+      public int compare(TestObject a, TestObject b) {
+        return a.getValue() - b.getValue();
+      }
+    };
+    testStableSort(comparator);
+    testStableSort(Collections.reverseOrder(comparator));
+  }
+
+  private void testStableSort(Comparator<TestObject> comparator) {
     TestObject[] origData = new TestObject[] {
         new TestObject(3), new TestObject(11), new TestObject(2),
         new TestObject(3), new TestObject(1), new TestObject(3),
@@ -1268,15 +1368,13 @@
     int[] permutation = new int[origData.length];
     while (validPermutation(permutation, origData.length)) {
       TestObject[] permutedArray = getPermutation(origData, permutation);
-      Arrays.sort(permutedArray, new Comparator<TestObject>() {
-        @Override
-        public int compare(TestObject a, TestObject b) {
-          return a.getValue() - b.getValue();
-        }
-      });
+      Arrays.sort(permutedArray, comparator);
       for (int i = 1; i < permutedArray.length; ++i) {
-        if (permutedArray[i - 1].getValue() > permutedArray[i].getValue()
-            || (permutedArray[i - 1].getValue() == permutedArray[i].getValue() && permutedArray[i - 1].getIndex() > permutedArray[i].getIndex())) {
+        TestObject prev = permutedArray[i - 1];
+        TestObject cur = permutedArray[i];
+        int cmp = comparator.compare(prev, cur);
+        if (cmp > 0
+            || (cmp == 0 && prev.getIndex() > cur.getIndex())) {
           String msg = "Permutation " + Arrays.toString(permutation) + ": "
               + Arrays.toString(permutedArray);
           permutedArray = getPermutation(origData, permutation);
@@ -1380,5 +1478,4 @@
     }
     return true;
   }
-
 }
diff --git a/user/test/com/google/gwt/emultest/java8/util/ArraysTest.java b/user/test/com/google/gwt/emultest/java8/util/ArraysTest.java
new file mode 100644
index 0000000..3a4d42b
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java8/util/ArraysTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.emultest.java8.util;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.util.Arrays;
+
+/**
+ * Java 8 methods to test in java.util.Arrays.
+ */
+public class ArraysTest extends EmulTestBase {
+
+  public void testParallelPrefix_double() {
+    double[] array = {1};
+    Arrays.parallelPrefix(array, Double::sum);
+    assertTrue(Arrays.equals(new double[]{1}, array));
+
+    array = new double[]{1, 2, 3};
+    Arrays.parallelPrefix(array, Double::sum);
+    assertTrue(Arrays.equals(new double[]{1, 3, 6}, array));
+
+    array = new double[]{1, 2, 3};
+    Arrays.parallelPrefix(array, 0, 0, Double::sum);
+    assertTrue(Arrays.equals(new double[]{1, 2, 3}, array));
+
+    array = new double[]{1, 2, 3, 4, 5};
+    Arrays.parallelPrefix(array, 1, 4, Double::sum);
+    assertTrue(Arrays.equals(new double[]{1, 2, 5, 9, 5}, array));
+  }
+
+  public void testParallelPrefix_int() {
+    int[] array = {1};
+    Arrays.parallelPrefix(array, Integer::sum);
+    assertTrue(Arrays.equals(new int[]{1}, array));
+
+    array = new int[]{1, 2, 3};
+    Arrays.parallelPrefix(array, Integer::sum);
+    assertTrue(Arrays.equals(new int[]{1, 3, 6}, array));
+
+    array = new int[]{1, 2, 3};
+    Arrays.parallelPrefix(array, 0, 0, Integer::sum);
+    assertTrue(Arrays.equals(new int[]{1, 2, 3}, array));
+
+    array = new int[]{1, 2, 3, 4, 5};
+    Arrays.parallelPrefix(array, 1, 4, Integer::sum);
+    assertTrue(Arrays.equals(new int[]{1, 2, 5, 9, 5}, array));
+  }
+
+  public void testParallelPrefix_long() {
+    long[] array = {1};
+    Arrays.parallelPrefix(array, Long::sum);
+    assertTrue(Arrays.equals(new long[]{1}, array));
+
+    array = new long[]{1, 2, 3};
+    Arrays.parallelPrefix(array, Long::sum);
+    assertTrue(Arrays.equals(new long[]{1, 3, 6}, array));
+
+    array = new long[]{1, 2, 3};
+    Arrays.parallelPrefix(array, 0, 0, Long::sum);
+    assertTrue(Arrays.equals(new long[]{1, 2, 3}, array));
+
+    array = new long[]{1, 2, 3, 4, 5};
+    Arrays.parallelPrefix(array, 1, 4, Long::sum);
+    assertTrue(Arrays.equals(new long[]{1, 2, 5, 9, 5}, array));
+  }
+
+  public void testParallelPrefix_Object() {
+    String[] array = {"a"};
+    Arrays.parallelPrefix(array, String::concat);
+    assertEquals(new String[]{"a"}, array);
+
+    array = new String[]{"a", "b", "c"};
+    Arrays.parallelPrefix(array, String::concat);
+    assertEquals(new String[]{"a", "ab", "abc"}, array);
+
+    array = new String[]{"a", "b", "c"};
+    Arrays.parallelPrefix(array, 0, 0, String::concat);
+    assertEquals(new String[]{"a", "b", "c"}, array);
+
+    array = new String[]{"a", "b", "c", "d", "e"};
+    Arrays.parallelPrefix(array, 1, 4, String::concat);
+    assertEquals(new String[]{"a", "b", "bc", "bcd", "e"}, array);
+  }
+
+  public void testSetAll_double() {
+    double[] array = {};
+    Arrays.setAll(array, i -> (double) i);
+    assertTrue(Arrays.equals(new double[0], array));
+
+    array = new double[]{0, 0, 0};
+    Arrays.setAll(array, i -> (double) i + 1);
+    assertTrue(Arrays.equals(new double[]{1, 2, 3}, array));
+  }
+
+  public void testSetAll_int() {
+    int[] array = {};
+    Arrays.setAll(array, i -> i);
+    assertTrue(Arrays.equals(new int[0], array));
+
+    array = new int[]{0, 0, 0};
+    Arrays.setAll(array, i -> i + 1);
+    assertTrue(Arrays.equals(new int[]{1, 2, 3}, array));
+  }
+
+  public void testSetAll_long() {
+    long[] array = {};
+    Arrays.setAll(array, i -> (long) i);
+    assertTrue(Arrays.equals(new long[0], array));
+
+    array = new long[]{0, 0, 0};
+    Arrays.setAll(array, i -> (long) i + 1);
+    assertTrue(Arrays.equals(new long[]{1, 2, 3}, array));
+  }
+
+  public void testSetAll_Object() {
+    String[] array = {};
+    Arrays.setAll(array, i -> "" + i);
+    assertEquals(new String[0], array);
+
+    array = new String[]{"a", "b", "c"};
+    Arrays.setAll(array, i -> "" + (i + 1));
+    assertEquals(new String[]{"1", "2", "3"}, array);
+  }
+}