/* Arrays.java -- Utility class with methods to operate on arrays
   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath 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 for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.

As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public License. */


// TO DO:
// ~ Fix the behaviour of sort and binarySearch as applied to float and double
//   arrays containing NaN values. See the JDC, bug ID 4143272.

package java.util;

/**
 * This class contains various static utility methods performing operations on
 * arrays, and a method to provide a List "view" of an array to facilitate
 * using arrays with Collection-based APIs.
 */
public class Arrays
{
  /**
   * This class is non-instantiable.
   */
  private Arrays()
  {
  }

  private static Comparator defaultComparator = new Comparator()
  {
    public int compare(Object o1, Object o2)
    {
      return ((Comparable) o1).compareTo(o2);
    }
  };

  /**
   * Perform a binary search of a byte array for a key. The array must be
   * sorted (as by the sort() method) - if it is not, the behaviour of this
   * method is undefined, and may be an infinite loop. If the array contains
   * the key more than once, any one of them may be found. Note: although the
   * specification allows for an infinite loop if the array is unsorted, it
   * will not happen in this implementation.
   *
   * @param a the array to search (must be sorted)
   * @param key the value to search for
   * @returns the index at which the key was found, or -n-1 if it was not
   *   found, where n is the index of the first value higher than key or
   *   a.length if there is no such value.
   */
  public static int binarySearch(byte[]a, byte key)
  {
    int low = 0;
    int hi = a.length - 1;
    int mid = 0;
    while (low <= hi)
      {
	mid = (low + hi) >> 1;
	final byte d = a[mid];
	if (d == key)
	  {
	    return mid;
	  }
	else if (d > key)
	  {
	    hi = mid - 1;
	  }
	else
	  {
	    // This gets the insertion point right on the last loop
	    low = ++mid;
	  }
      }
    return -mid - 1;
  }

  /**
   * Perform a binary search of a char array for a key. The array must be
   * sorted (as by the sort() method) - if it is not, the behaviour of this
   * method is undefined, and may be an infinite loop. If the array contains
   * the key more than once, any one of them may be found. Note: although the
   * specification allows for an infinite loop if the array is unsorted, it
   * will not happen in this implementation.
   *
   * @param a the array to search (must be sorted)
   * @param key the value to search for
   * @returns the index at which the key was found, or -n-1 if it was not
   *   found, where n is the index of the first value higher than key or
   *   a.length if there is no such value.
   */
  public static int binarySearch(char[]a, char key)
  {
    int low = 0;
    int hi = a.length - 1;
    int mid = 0;
    while (low <= hi)
      {
	mid = (low + hi) >> 1;
	final char d = a[mid];
	if (d == key)
	  {
	    return mid;
	  }
	else if (d > key)
	  {
	    hi = mid - 1;
	  }
	else
	  {
	    // This gets the insertion point right on the last loop
	    low = ++mid;
	  }
      }
    return -mid - 1;
  }

  /**
   * Perform a binary search of a double array for a key. The array must be
   * sorted (as by the sort() method) - if it is not, the behaviour of this
   * method is undefined, and may be an infinite loop. If the array contains
   * the key more than once, any one of them may be found. Note: although the
   * specification allows for an infinite loop if the array is unsorted, it
   * will not happen in this implementation.
   *
   * @param a the array to search (must be sorted)
   * @param key the value to search for
   * @returns the index at which the key was found, or -n-1 if it was not
   *   found, where n is the index of the first value higher than key or
   *   a.length if there is no such value.
   */
  public static int binarySearch(double[]a, double key)
  {
    int low = 0;
    int hi = a.length - 1;
    int mid = 0;
    while (low <= hi)
      {
	mid = (low + hi) >> 1;
	final double d = a[mid];
	if (d == key)
	  {
	    return mid;
	  }
	else if (d > key)
	  {
	    hi = mid - 1;
	  }
	else
	  {
	    // This gets the insertion point right on the last loop
	    low = ++mid;
	  }
      }
    return -mid - 1;
  }

  /**
   * Perform a binary search of a float array for a key. The array must be
   * sorted (as by the sort() method) - if it is not, the behaviour of this
   * method is undefined, and may be an infinite loop. If the array contains
   * the key more than once, any one of them may be found. Note: although the
   * specification allows for an infinite loop if the array is unsorted, it
   * will not happen in this implementation.
   *
   * @param a the array to search (must be sorted)
   * @param key the value to search for
   * @returns the index at which the key was found, or -n-1 if it was not
   *   found, where n is the index of the first value higher than key or
   *   a.length if there is no such value.
   */
  public static int binarySearch(float[]a, float key)
  {
    int low = 0;
    int hi = a.length - 1;
    int mid = 0;
    while (low <= hi)
      {
	mid = (low + hi) >> 1;
	final float d = a[mid];
	if (d == key)
	  {
	    return mid;
	  }
	else if (d > key)
	  {
	    hi = mid - 1;
	  }
	else
	  {
	    // This gets the insertion point right on the last loop
	    low = ++mid;
	  }
      }
    return -mid - 1;
  }

  /**
   * Perform a binary search of an int array for a key. The array must be
   * sorted (as by the sort() method) - if it is not, the behaviour of this
   * method is undefined, and may be an infinite loop. If the array contains
   * the key more than once, any one of them may be found. Note: although the
   * specification allows for an infinite loop if the array is unsorted, it
   * will not happen in this implementation.
   *
   * @param a the array to search (must be sorted)
   * @param key the value to search for
   * @returns the index at which the key was found, or -n-1 if it was not
   *   found, where n is the index of the first value higher than key or
   *   a.length if there is no such value.
   */
  public static int binarySearch(int[]a, int key)
  {
    int low = 0;
    int hi = a.length - 1;
    int mid = 0;
    while (low <= hi)
      {
	mid = (low + hi) >> 1;
	final int d = a[mid];
	if (d == key)
	  {
	    return mid;
	  }
	else if (d > key)
	  {
	    hi = mid - 1;
	  }
	else
	  {
	    // This gets the insertion point right on the last loop
	    low = ++mid;
	  }
      }
    return -mid - 1;
  }

  /**
   * Perform a binary search of a long array for a key. The array must be
   * sorted (as by the sort() method) - if it is not, the behaviour of this
   * method is undefined, and may be an infinite loop. If the array contains
   * the key more than once, any one of them may be found. Note: although the
   * specification allows for an infinite loop if the array is unsorted, it
   * will not happen in this implementation.
   *
   * @param a the array to search (must be sorted)
   * @param key the value to search for
   * @returns the index at which the key was found, or -n-1 if it was not
   *   found, where n is the index of the first value higher than key or
   *   a.length if there is no such value.
   */
  public static int binarySearch(long[]a, long key)
  {
    int low = 0;
    int hi = a.length - 1;
    int mid = 0;
    while (low <= hi)
      {
	mid = (low + hi) >> 1;
	final long d = a[mid];
	if (d == key)
	  {
	    return mid;
	  }
	else if (d > key)
	  {
	    hi = mid - 1;
	  }
	else
	  {
	    // This gets the insertion point right on the last loop
	    low = ++mid;
	  }
      }
    return -mid - 1;
  }

  /**
   * Perform a binary search of a short array for a key. The array must be
   * sorted (as by the sort() method) - if it is not, the behaviour of this
   * method is undefined, and may be an infinite loop. If the array contains
   * the key more than once, any one of them may be found. Note: although the
   * specification allows for an infinite loop if the array is unsorted, it
   * will not happen in this implementation.
   *
   * @param a the array to search (must be sorted)
   * @param key the value to search for
   * @returns the index at which the key was found, or -n-1 if it was not
   *   found, where n is the index of the first value higher than key or
   *   a.length if there is no such value.
   */
  public static int binarySearch(short[]a, short key)
  {
    int low = 0;
    int hi = a.length - 1;
    int mid = 0;
    while (low <= hi)
      {
	mid = (low + hi) >> 1;
	final short d = a[mid];
	if (d == key)
	  {
	    return mid;
	  }
	else if (d > key)
	  {
	    hi = mid - 1;
	  }
	else
	  {
	    // This gets the insertion point right on the last loop
	    low = ++mid;
	  }
      }
    return -mid - 1;
  }

  /**
   * This method does the work for the Object binary search methods. 
   * @exception NullPointerException if the specified comparator is null.
   * @exception ClassCastException if the objects are not comparable by c.
   */
  private static int objectSearch(Object[]a, Object key, final Comparator c)
  {
    int low = 0;
    int hi = a.length - 1;
    int mid = 0;
    while (low <= hi)
      {
	mid = (low + hi) >> 1;
	final int d = c.compare(key, a[mid]);
	if (d == 0)
	  {
	    return mid;
	  }
	else if (d < 0)
	  {
	    hi = mid - 1;
	  }
	else
	  {
	    // This gets the insertion point right on the last loop
	    low = ++mid;
	  }	    
      }
    return -mid - 1;
  }

  /**
   * Perform a binary search of an Object array for a key, using the natural
   * ordering of the elements. The array must be sorted (as by the sort()
   * method) - if it is not, the behaviour of this method is undefined, and may
   * be an infinite loop. Further, the key must be comparable with every item
   * in the array. If the array contains the key more than once, any one of
   * them may be found. Note: although the specification allows for an infinite
   * loop if the array is unsorted, it will not happen in this (JCL)
   * implementation.
   *
   * @param a the array to search (must be sorted)
   * @param key the value to search for
   * @returns the index at which the key was found, or -n-1 if it was not
   *   found, where n is the index of the first value higher than key or
   *   a.length if there is no such value.
   * @exception ClassCastException if key could not be compared with one of the
   *   elements of a
   * @exception NullPointerException if a null element has compareTo called
   */
  public static int binarySearch(Object[]a, Object key)
  {
    return objectSearch(a, key, defaultComparator);
  }

  /**
   * Perform a binary search of an Object array for a key, using a supplied
   * Comparator. The array must be sorted (as by the sort() method with the
   * same Comparator) - if it is not, the behaviour of this method is
   * undefined, and may be an infinite loop. Further, the key must be
   * comparable with every item in the array. If the array contains the key
   * more than once, any one of them may be found. Note: although the
   * specification allows for an infinite loop if the array is unsorted, it
   * will not happen in this (JCL) implementation.
   *
   * @param a the array to search (must be sorted)
   * @param key the value to search for
   * @param c the comparator by which the array is sorted
   * @returns the index at which the key was found, or -n-1 if it was not
   *   found, where n is the index of the first value higher than key or
   *   a.length if there is no such value.
   * @exception ClassCastException if key could not be compared with one of the
   *   elements of a
   */
  public static int binarySearch(Object[]a, Object key, Comparator c)
  {
    return objectSearch(a, key, c);
  }

  /**
   * Compare two byte arrays for equality.
   *
   * @param a1 the first array to compare
   * @param a2 the second array to compare
   * @returns true if a1 and a2 are both null, or if a2 is of the same length
   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
   */
  public static boolean equals(byte[]a1, byte[]a2)
  {
    // Quick test which saves comparing elements of the same array, and also
    // catches the case that both are null.
    if (a1 == a2)
      {
	return true;
      }
      
    try
      {
	// If they're the same length, test each element
	if (a1.length == a2.length)
	  {
	    for (int i = 0; i < a1.length; i++)
	      {
		if (a1[i] != a2[i])
		  {
		    return false;
		  }
	      }
	    return true;
	  }

	// If a1 == null or a2 == null but not both then we will get a NullPointer
      }
    catch (NullPointerException e)
      {
      }

    return false;
  }

  /**
   * Compare two char arrays for equality.
   *
   * @param a1 the first array to compare
   * @param a2 the second array to compare
   * @returns true if a1 and a2 are both null, or if a2 is of the same length
   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
   */
  public static boolean equals(char[]a1, char[]a2)
  {
    // Quick test which saves comparing elements of the same array, and also
    // catches the case that both are null.
    if (a1 == a2)
      {
	return true;
      }
      
    try
      {
	// If they're the same length, test each element
	if (a1.length == a2.length)
	  {
	    for (int i = 0; i < a1.length; i++)
	      {
		if (a1[i] != a2[i])
		  {
		    return false;
		  }
	      }
	    return true;
	  }

	// If a1 == null or a2 == null but not both then we will get a NullPointer
      }
    catch (NullPointerException e)
      {
      }

    return false;
  }

  /**
   * Compare two double arrays for equality.
   *
   * @param a1 the first array to compare
   * @param a2 the second array to compare
   * @returns true if a1 and a2 are both null, or if a2 is of the same length
   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
   */
  public static boolean equals(double[]a1, double[]a2)
  {
    // Quick test which saves comparing elements of the same array, and also
    // catches the case that both are null.
    if (a1 == a2)
      {
	return true;
      }
      
    try
      {
	// If they're the same length, test each element
	if (a1.length == a2.length)
	  {
	    for (int i = 0; i < a1.length; i++)
	      {
		if (a1[i] != a2[i])
		  {
		    return false;
		  }
	      }
	    return true;
	  }

	// If a1 == null or a2 == null but not both then we will get a NullPointer
      }
    catch (NullPointerException e)
      {
      }

    return false;
  }

  /**
   * Compare two float arrays for equality.
   *
   * @param a1 the first array to compare
   * @param a2 the second array to compare
   * @returns true if a1 and a2 are both null, or if a2 is of the same length
   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
   */
  public static boolean equals(float[]a1, float[]a2)
  {
    // Quick test which saves comparing elements of the same array, and also
    // catches the case that both are null.
    if (a1 == a2)
      {
	return true;
      }
      
    try
      {
	// If they're the same length, test each element
	if (a1.length == a2.length)
	  {
	    for (int i = 0; i < a1.length; i++)
	      {
		if (a1[i] != a2[i])
		  {
		    return false;
		  }
	      }
	    return true;
	  }

	// If a1 == null or a2 == null but not both then we will get a NullPointer
      }
    catch (NullPointerException e)
      {
      }

    return false;
  }

  /**
   * Compare two long arrays for equality.
   *
   * @param a1 the first array to compare
   * @param a2 the second array to compare
   * @returns true if a1 and a2 are both null, or if a2 is of the same length
   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
   */
  public static boolean equals(long[]a1, long[]a2)
  {
    // Quick test which saves comparing elements of the same array, and also
    // catches the case that both are null.
    if (a1 == a2)
      {
	return true;
      }
      
    try
      {
	// If they're the same length, test each element
	if (a1.length == a2.length)
	  {
	    for (int i = 0; i < a1.length; i++)
	      {
		if (a1[i] != a2[i])
		  {
		    return false;
		  }
	      }
	    return true;
	  }

	// If a1 == null or a2 == null but not both then we will get a NullPointer
      }
    catch (NullPointerException e)
      {
      }

    return false;
  }

  /**
   * Compare two short arrays for equality.
   *
   * @param a1 the first array to compare
   * @param a2 the second array to compare
   * @returns true if a1 and a2 are both null, or if a2 is of the same length
   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
   */
  public static boolean equals(short[]a1, short[]a2)
  {
    // Quick test which saves comparing elements of the same array, and also
    // catches the case that both are null.
    if (a1 == a2)
      {
	return true;
      }
      
    try
      {
	// If they're the same length, test each element
	if (a1.length == a2.length)
	  {
	    for (int i = 0; i < a1.length; i++)
	      {
		if (a1[i] != a2[i])
		  {
		    return false;
		  }
	      }
	    return true;
	  }

	// If a1 == null or a2 == null but not both then we will get a NullPointer
      }
    catch (NullPointerException e)
      {
      }

    return false;
  }

  /**
   * Compare two boolean arrays for equality.
   *
   * @param a1 the first array to compare
   * @param a2 the second array to compare
   * @returns true if a1 and a2 are both null, or if a2 is of the same length
   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
   */
  public static boolean equals(boolean[]a1, boolean[]a2)
  {
    // Quick test which saves comparing elements of the same array, and also
    // catches the case that both are null.
    if (a1 == a2)
      {
	return true;
      }
      
    try
      {
	// If they're the same length, test each element
	if (a1.length == a2.length)
	  {
	    for (int i = 0; i < a1.length; i++)
	      {
		if (a1[i] != a2[i])
		  {
		    return false;
		  }
	      }
	    return true;
	  }

	// If a1 == null or a2 == null but not both then we will get a NullPointer
      }
    catch (NullPointerException e)
      {
      }

    return false;
  }

  /**
   * Compare two int arrays for equality.
   *
   * @param a1 the first array to compare
   * @param a2 the second array to compare
   * @returns true if a1 and a2 are both null, or if a2 is of the same length
   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
   */
  public static boolean equals(int[]a1, int[]a2)
  {
    // Quick test which saves comparing elements of the same array, and also
    // catches the case that both are null.
    if (a1 == a2)
      {
	return true;
      }
      
    try
      {
	// If they're the same length, test each element
	if (a1.length == a2.length)
	  {
	    for (int i = 0; i < a1.length; i++)
	      {
		if (a1[i] != a2[i])
		  {
		    return false;
		  }
	      }
	    return true;
	  }

	// If a1 == null or a2 == null but not both then we will get a NullPointer
      }
    catch (NullPointerException e)
      {
      }

    return false;
  }

  /**
   * Compare two Object arrays for equality.
   *
   * @param a1 the first array to compare
   * @param a2 the second array to compare
   * @returns true if a1 and a2 are both null, or if a1 is of the same length
   *   as a2, and for each 0 <= i < a.length, a1[i] == null ? a2[i] == null :
   *   a1[i].equals(a2[i]).
   */
  public static boolean equals(Object[]a1, Object[]a2)
  {
    // Quick test which saves comparing elements of the same array, and also
    // catches the case that both are null.
    if (a1 == a2)
      {
	return true;
      }
      
    try
      {
	// If they're the same length, test each element
	if (a1.length == a2.length)
	  {
	    for (int i = 0; i < a1.length; i++)
	      {
		if (!(a1[i] == null ? a2[i] == null : a1[i].equals(a2[i])))
		  {
		    return false;
		  }
	      }
	    return true;
	  }

	// If a1 == null or a2 == null but not both then we will get a NullPointer
      }
    catch (NullPointerException e)
      {
      }

    return false;
  }

  /**
   * Fill an array with a boolean value.
   *
   * @param a the array to fill
   * @param val the value to fill it with
   */
  public static void fill(boolean[]a, boolean val)
  {
    // This implementation is slightly inefficient timewise, but the extra
    // effort over inlining it is O(1) and small, and I refuse to repeat code
    // if it can be helped.
    fill(a, 0, a.length, val);
  }

  /**
   * Fill a range of an array with a boolean value.
   *
   * @param a the array to fill
   * @param fromIndex the index to fill from, inclusive
   * @param toIndex the index to fill to, exclusive
   * @param val the value to fill with
   */
  public static void fill(boolean[]a, int fromIndex, int toIndex, boolean val)
  {
    for (int i = fromIndex; i < toIndex; i++)
      {
	a[i] = val;
      }
  }

  /**
   * Fill an array with a byte value.
   *
   * @param a the array to fill
   * @param val the value to fill it with
   */
  public static void fill(byte[]a, byte val)
  {
    // This implementation is slightly inefficient timewise, but the extra
    // effort over inlining it is O(1) and small, and I refuse to repeat code
    // if it can be helped.
    fill(a, 0, a.length, val);
  }

  /**
   * Fill a range of an array with a byte value.
   *
   * @param a the array to fill
   * @param fromIndex the index to fill from, inclusive
   * @param toIndex the index to fill to, exclusive
   * @param val the value to fill with
   */
  public static void fill(byte[]a, int fromIndex, int toIndex, byte val)
  {
    for (int i = fromIndex; i < toIndex; i++)
      {
	a[i] = val;
      }
  }

  /**
   * Fill an array with a char value.
   *
   * @param a the array to fill
   * @param val the value to fill it with
   */
  public static void fill(char[]a, char val)
  {
    // This implementation is slightly inefficient timewise, but the extra
    // effort over inlining it is O(1) and small, and I refuse to repeat code
    // if it can be helped.
    fill(a, 0, a.length, val);
  }

  /**
   * Fill a range of an array with a char value.
   *
   * @param a the array to fill
   * @param fromIndex the index to fill from, inclusive
   * @param toIndex the index to fill to, exclusive
   * @param val the value to fill with
   */
  public static void fill(char[]a, int fromIndex, int toIndex, char val)
  {
    for (int i = fromIndex; i < toIndex; i++)
      {
	a[i] = val;
      }
  }

  /**
   * Fill an array with a double value.
   *
   * @param a the array to fill
   * @param val the value to fill it with
   */
  public static void fill(double[]a, double val)
  {
    // This implementation is slightly inefficient timewise, but the extra
    // effort over inlining it is O(1) and small, and I refuse to repeat code
    // if it can be helped.
    fill(a, 0, a.length, val);
  }

  /**
   * Fill a range of an array with a double value.
   *
   * @param a the array to fill
   * @param fromIndex the index to fill from, inclusive
   * @param toIndex the index to fill to, exclusive
   * @param val the value to fill with
   */
  public static void fill(double[]a, int fromIndex, int toIndex, double val)
  {
    for (int i = fromIndex; i < toIndex; i++)
      {
	a[i] = val;
      }
  }

  /**
   * Fill an array with a float value.
   *
   * @param a the array to fill
   * @param val the value to fill it with
   */
  public static void fill(float[]a, float val)
  {
    // This implementation is slightly inefficient timewise, but the extra
    // effort over inlining it is O(1) and small, and I refuse to repeat code
    // if it can be helped.
    fill(a, 0, a.length, val);
  }

  /**
   * Fill a range of an array with a float value.
   *
   * @param a the array to fill
   * @param fromIndex the index to fill from, inclusive
   * @param toIndex the index to fill to, exclusive
   * @param val the value to fill with
   */
  public static void fill(float[]a, int fromIndex, int toIndex, float val)
  {
    for (int i = fromIndex; i < toIndex; i++)
      {
	a[i] = val;
      }
  }

  /**
   * Fill an array with an int value.
   *
   * @param a the array to fill
   * @param val the value to fill it with
   */
  public static void fill(int[]a, int val)
  {
    // This implementation is slightly inefficient timewise, but the extra
    // effort over inlining it is O(1) and small, and I refuse to repeat code
    // if it can be helped.
    fill(a, 0, a.length, val);
  }

  /**
   * Fill a range of an array with an int value.
   *
   * @param a the array to fill
   * @param fromIndex the index to fill from, inclusive
   * @param toIndex the index to fill to, exclusive
   * @param val the value to fill with
   */
  public static void fill(int[]a, int fromIndex, int toIndex, int val)
  {
    for (int i = fromIndex; i < toIndex; i++)
      {
	a[i] = val;
      }
  }

  /**
   * Fill an array with a long value.
   *
   * @param a the array to fill
   * @param val the value to fill it with
   */
  public static void fill(long[]a, long val)
  {
    // This implementation is slightly inefficient timewise, but the extra
    // effort over inlining it is O(1) and small, and I refuse to repeat code
    // if it can be helped.
    fill(a, 0, a.length, val);
  }

  /**
   * Fill a range of an array with a long value.
   *
   * @param a the array to fill
   * @param fromIndex the index to fill from, inclusive
   * @param toIndex the index to fill to, exclusive
   * @param val the value to fill with
   */
  public static void fill(long[]a, int fromIndex, int toIndex, long val)
  {
    for (int i = fromIndex; i < toIndex; i++)
      {
	a[i] = val;
      }
  }

  /**
   * Fill an array with a short value.
   *
   * @param a the array to fill
   * @param val the value to fill it with
   */
  public static void fill(short[]a, short val)
  {
    // This implementation is slightly inefficient timewise, but the extra
    // effort over inlining it is O(1) and small, and I refuse to repeat code
    // if it can be helped.
    fill(a, 0, a.length, val);
  }

  /**
   * Fill a range of an array with a short value.
   *
   * @param a the array to fill
   * @param fromIndex the index to fill from, inclusive
   * @param toIndex the index to fill to, exclusive
   * @param val the value to fill with
   */
  public static void fill(short[]a, int fromIndex, int toIndex, short val)
  {
    for (int i = fromIndex; i < toIndex; i++)
      {
	a[i] = val;
      }
  }

  /**
   * Fill an array with an Object value.
   *
   * @param a the array to fill
   * @param val the value to fill it with
   * @exception ClassCastException if val is not an instance of the element
   *   type of a.
   */
  public static void fill(Object[]a, Object val)
  {
    // This implementation is slightly inefficient timewise, but the extra
    // effort over inlining it is O(1) and small, and I refuse to repeat code
    // if it can be helped.
    fill(a, 0, a.length, val);
  }

  /**
   * Fill a range of an array with an Object value.
   *
   * @param a the array to fill
   * @param fromIndex the index to fill from, inclusive
   * @param toIndex the index to fill to, exclusive
   * @param val the value to fill with
   * @exception ClassCastException if val is not an instance of the element
   *   type of a.
   */
  public static void fill(Object[]a, int fromIndex, int toIndex, Object val)
  {
    for (int i = fromIndex; i < toIndex; i++)
      {
	a[i] = val;
      }
  }

  // Thanks to Paul Fisher <rao@gnu.org> for finding this quicksort algorithm
  // as specified by Sun and porting it to Java.

  /**
   * Sort a byte array into ascending order. The sort algorithm is an optimised
   * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
   * "Engineering a Sort Function", Software-Practice and Experience, Vol.
   * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
   * performance on many arrays that would take quadratic time with a standard
   * quicksort.
   *
   * @param a the array to sort
   */
  public static void sort(byte[]a)
  {
    qsort(a, 0, a.length);
  }

  public static void sort(byte[] a, int fromIndex, int toIndex)
  {
    qsort(a, fromIndex, toIndex);
  }

  private static short cmp(byte i, byte j)
  {
    return (short) (i - j);
  }

  private static int med3(int a, int b, int c, byte[]d)
  {
    return cmp(d[a], d[b]) < 0 ?
      (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a)
      : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a);
  }

  private static void swap(int i, int j, byte[]a)
  {
    byte c = a[i];
    a[i] = a[j];
    a[j] = c;
  }

  private static void qsort(byte[]a, int start, int n)
  {
    // use an insertion sort on small arrays
    if (n < 7)
      {
	for (int i = start + 1; i < start + n; i++)
	  for (int j = i; j > 0 && cmp(a[j - 1], a[j]) > 0; j--)
	    swap(j, j - 1, a);
	return;
      }

    int pm = n / 2;		// small arrays, middle element
    if (n > 7)
      {
	int pl = start;
	int pn = start + n - 1;

	if (n > 40)
	  {			// big arrays, pseudomedian of 9
	    int s = n / 8;
	    pl = med3(pl, pl + s, pl + 2 * s, a);
	    pm = med3(pm - s, pm, pm + s, a);
	    pn = med3(pn - 2 * s, pn - s, pn, a);
	  }
	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
      }

    int pa, pb, pc, pd, pv;
    short r;

    pv = start;
    swap(pv, pm, a);
    pa = pb = start;
    pc = pd = start + n - 1;

    for (;;)
      {
	while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0)
	  {
	    if (r == 0)
	      {
		swap(pa, pb, a);
		pa++;
	      }
	    pb++;
	  }
	while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0)
	  {
	    if (r == 0)
	      {
		swap(pc, pd, a);
		pd--;
	      }
	    pc--;
	  }
	if (pb > pc)
	  break;
	swap(pb, pc, a);
	pb++;
	pc--;
      }
    int pn = start + n;
    int s;
    s = Math.min(pa - start, pb - pa);
    vecswap(start, pb - s, s, a);
    s = Math.min(pd - pc, pn - pd - 1);
    vecswap(pb, pn - s, s, a);
    if ((s = pb - pa) > 1)
      qsort(a, start, s);
    if ((s = pd - pc) > 1)
      qsort(a, pn - s, s);
  }

  private static void vecswap(int i, int j, int n, byte[]a)
  {
    for (; n > 0; i++, j++, n--)
      swap(i, j, a);
  }

  /**
   * Sort a char array into ascending order. The sort algorithm is an optimised
   * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
   * "Engineering a Sort Function", Software-Practice and Experience, Vol.
   * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
   * performance on many arrays that would take quadratic time with a standard
   * quicksort.
   *
   * @param a the array to sort
   */
  public static void sort(char[]a)
  {
    qsort(a, 0, a.length);
  }

  public static void sort(char[] a, int fromIndex, int toIndex)
  {
    qsort(a, fromIndex, toIndex);
  }

  private static int cmp(char i, char j)
  {
    return i - j;
  }

  private static int med3(int a, int b, int c, char[]d)
  {
    return cmp(d[a], d[b]) < 0 ?
      (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a)
      : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a);
  }

  private static void swap(int i, int j, char[]a)
  {
    char c = a[i];
    a[i] = a[j];
    a[j] = c;
  }

  private static void qsort(char[]a, int start, int n)
  {
    // use an insertion sort on small arrays
    if (n < 7)
      {
	for (int i = start + 1; i < start + n; i++)
	  for (int j = i; j > 0 && cmp(a[j - 1], a[j]) > 0; j--)
	    swap(j, j - 1, a);
	return;
      }

    int pm = n / 2;		// small arrays, middle element
    if (n > 7)
      {
	int pl = start;
	int pn = start + n - 1;

	if (n > 40)
	  {			// big arrays, pseudomedian of 9
	    int s = n / 8;
	    pl = med3(pl, pl + s, pl + 2 * s, a);
	    pm = med3(pm - s, pm, pm + s, a);
	    pn = med3(pn - 2 * s, pn - s, pn, a);
	  }
	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
      }

    int pa, pb, pc, pd, pv;
    int r;

    pv = start;
    swap(pv, pm, a);
    pa = pb = start;
    pc = pd = start + n - 1;

    for (;;)
      {
	while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0)
	  {
	    if (r == 0)
	      {
		swap(pa, pb, a);
		pa++;
	      }
	    pb++;
	  }
	while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0)
	  {
	    if (r == 0)
	      {
		swap(pc, pd, a);
		pd--;
	      }
	    pc--;
	  }
	if (pb > pc)
	  break;
	swap(pb, pc, a);
	pb++;
	pc--;
      }
    int pn = start + n;
    int s;
    s = Math.min(pa - start, pb - pa);
    vecswap(start, pb - s, s, a);
    s = Math.min(pd - pc, pn - pd - 1);
    vecswap(pb, pn - s, s, a);
    if ((s = pb - pa) > 1)
      qsort(a, start, s);
    if ((s = pd - pc) > 1)
      qsort(a, pn - s, s);
  }

  private static void vecswap(int i, int j, int n, char[]a)
  {
    for (; n > 0; i++, j++, n--)
      swap(i, j, a);
  }

  /**
   * Sort a double array into ascending order. The sort algorithm is an
   * optimised quicksort, as described in Jon L. Bentley and M. Douglas
   * McIlroy's "Engineering a Sort Function", Software-Practice and Experience,
   * Vol. 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
   * performance on many arrays that would take quadratic time with a standard
   * quicksort. Note that this implementation, like Sun's, has undefined
   * behaviour if the array contains any NaN values.
   *
   * @param a the array to sort
   */
  public static void sort(double[]a)
  {
    qsort(a, 0, a.length);
  }

  public static void sort(double[] a, int fromIndex, int toIndex)
  {
    qsort(a, fromIndex, toIndex);
  }

  private static double cmp(double i, double j)
  {
    return i - j;
  }

  private static int med3(int a, int b, int c, double[]d)
  {
    return cmp(d[a], d[b]) < 0 ?
      (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a)
      : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a);
  }

  private static void swap(int i, int j, double[]a)
  {
    double c = a[i];
    a[i] = a[j];
    a[j] = c;
  }

  private static void qsort(double[]a, int start, int n)
  {
    // use an insertion sort on small arrays
    if (n < 7)
      {
	for (int i = start + 1; i < start + n; i++)
	  for (int j = i; j > 0 && cmp(a[j - 1], a[j]) > 0; j--)
	    swap(j, j - 1, a);
	return;
      }

    int pm = n / 2;		// small arrays, middle element
    if (n > 7)
      {
	int pl = start;
	int pn = start + n - 1;

	if (n > 40)
	  {			// big arrays, pseudomedian of 9
	    int s = n / 8;
	    pl = med3(pl, pl + s, pl + 2 * s, a);
	    pm = med3(pm - s, pm, pm + s, a);
	    pn = med3(pn - 2 * s, pn - s, pn, a);
	  }
	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
      }

    int pa, pb, pc, pd, pv;
    double r;

    pv = start;
    swap(pv, pm, a);
    pa = pb = start;
    pc = pd = start + n - 1;

    for (;;)
      {
	while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0)
	  {
	    if (r == 0)
	      {
		swap(pa, pb, a);
		pa++;
	      }
	    pb++;
	  }
	while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0)
	  {
	    if (r == 0)
	      {
		swap(pc, pd, a);
		pd--;
	      }
	    pc--;
	  }
	if (pb > pc)
	  break;
	swap(pb, pc, a);
	pb++;
	pc--;
      }
    int pn = start + n;
    int s;
    s = Math.min(pa - start, pb - pa);
    vecswap(start, pb - s, s, a);
    s = Math.min(pd - pc, pn - pd - 1);
    vecswap(pb, pn - s, s, a);
    if ((s = pb - pa) > 1)
      qsort(a, start, s);
    if ((s = pd - pc) > 1)
      qsort(a, pn - s, s);
  }

  private static void vecswap(int i, int j, int n, double[]a)
  {
    for (; n > 0; i++, j++, n--)
      swap(i, j, a);
  }

  /**
   * Sort a float array into ascending order. The sort algorithm is an
   * optimised quicksort, as described in Jon L. Bentley and M. Douglas
   * McIlroy's "Engineering a Sort Function", Software-Practice and Experience,
   * Vol. 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
   * performance on many arrays that would take quadratic time with a standard
   * quicksort. Note that this implementation, like Sun's, has undefined
   * behaviour if the array contains any NaN values.
   *
   * @param a the array to sort
   */
  public static void sort(float[]a)
  {
    qsort(a, 0, a.length);
  }

  public static void sort(float[] a, int fromIndex, int toIndex)
  {
    qsort(a, fromIndex, toIndex);
  }

  private static float cmp(float i, float j)
  {
    return i - j;
  }

  private static int med3(int a, int b, int c, float[]d)
  {
    return cmp(d[a], d[b]) < 0 ?
      (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a)
      : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a);
  }

  private static void swap(int i, int j, float[]a)
  {
    float c = a[i];
    a[i] = a[j];
    a[j] = c;
  }

  private static void qsort(float[]a, int start, int n)
  {
    // use an insertion sort on small arrays
    if (n < 7)
      {
	for (int i = start + 1; i < start + n; i++)
	  for (int j = i; j > 0 && cmp(a[j - 1], a[j]) > 0; j--)
	    swap(j, j - 1, a);
	return;
      }

    int pm = n / 2;		// small arrays, middle element
    if (n > 7)
      {
	int pl = start;
	int pn = start + n - 1;

	if (n > 40)
	  {			// big arrays, pseudomedian of 9
	    int s = n / 8;
	    pl = med3(pl, pl + s, pl + 2 * s, a);
	    pm = med3(pm - s, pm, pm + s, a);
	    pn = med3(pn - 2 * s, pn - s, pn, a);
	  }
	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
      }

    int pa, pb, pc, pd, pv;
    float r;

    pv = start;
    swap(pv, pm, a);
    pa = pb = start;
    pc = pd = start + n - 1;

    for (;;)
      {
	while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0)
	  {
	    if (r == 0)
	      {
		swap(pa, pb, a);
		pa++;
	      }
	    pb++;
	  }
	while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0)
	  {
	    if (r == 0)
	      {
		swap(pc, pd, a);
		pd--;
	      }
	    pc--;
	  }
	if (pb > pc)
	  break;
	swap(pb, pc, a);
	pb++;
	pc--;
      }
    int pn = start + n;
    int s;
    s = Math.min(pa - start, pb - pa);
    vecswap(start, pb - s, s, a);
    s = Math.min(pd - pc, pn - pd - 1);
    vecswap(pb, pn - s, s, a);
    if ((s = pb - pa) > 1)
      qsort(a, start, s);
    if ((s = pd - pc) > 1)
      qsort(a, pn - s, s);
  }

  private static void vecswap(int i, int j, int n, float[]a)
  {
    for (; n > 0; i++, j++, n--)
      swap(i, j, a);
  }

  /**
   * Sort an int array into ascending order. The sort algorithm is an optimised
   * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
   * "Engineering a Sort Function", Software-Practice and Experience, Vol.
   * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
   * performance on many arrays that would take quadratic time with a standard
   * quicksort.
   *
   * @param a the array to sort
   */
  public static void sort(int[]a)
  {
    qsort(a, 0, a.length);
  }

  public static void sort(int[] a, int fromIndex, int toIndex)
  {
    qsort(a, fromIndex, toIndex);
  }

  private static long cmp(int i, int j)
  {
    return (long) i - (long) j;
  }

  private static int med3(int a, int b, int c, int[]d)
  {
    return cmp(d[a], d[b]) < 0 ?
      (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a)
      : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a);
  }

  private static void swap(int i, int j, int[]a)
  {
    int c = a[i];
    a[i] = a[j];
    a[j] = c;
  }

  private static void qsort(int[]a, int start, int n)
  {
    // use an insertion sort on small arrays
    if (n < 7)
      {
	for (int i = start + 1; i < start + n; i++)
	  for (int j = i; j > 0 && cmp(a[j - 1], a[j]) > 0; j--)
	    swap(j, j - 1, a);
	return;
      }

    int pm = n / 2;		// small arrays, middle element
    if (n > 7)
      {
	int pl = start;
	int pn = start + n - 1;

	if (n > 40)
	  {			// big arrays, pseudomedian of 9
	    int s = n / 8;
	    pl = med3(pl, pl + s, pl + 2 * s, a);
	    pm = med3(pm - s, pm, pm + s, a);
	    pn = med3(pn - 2 * s, pn - s, pn, a);
	  }
	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
      }

    int pa, pb, pc, pd, pv;
    long r;

    pv = start;
    swap(pv, pm, a);
    pa = pb = start;
    pc = pd = start + n - 1;

    for (;;)
      {
	while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0)
	  {
	    if (r == 0)
	      {
		swap(pa, pb, a);
		pa++;
	      }
	    pb++;
	  }
	while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0)
	  {
	    if (r == 0)
	      {
		swap(pc, pd, a);
		pd--;
	      }
	    pc--;
	  }
	if (pb > pc)
	  break;
	swap(pb, pc, a);
	pb++;
	pc--;
      }
    int pn = start + n;
    int s;
    s = Math.min(pa - start, pb - pa);
    vecswap(start, pb - s, s, a);
    s = Math.min(pd - pc, pn - pd - 1);
    vecswap(pb, pn - s, s, a);
    if ((s = pb - pa) > 1)
      qsort(a, start, s);
    if ((s = pd - pc) > 1)
      qsort(a, pn - s, s);
  }

  private static void vecswap(int i, int j, int n, int[]a)
  {
    for (; n > 0; i++, j++, n--)
      swap(i, j, a);
  }

  /**
   * Sort a long array into ascending order. The sort algorithm is an optimised
   * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
   * "Engineering a Sort Function", Software-Practice and Experience, Vol.
   * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
   * performance on many arrays that would take quadratic time with a standard
   * quicksort.
   *
   * @param a the array to sort
   */
  public static void sort(long[]a)
  {
    qsort(a, 0, a.length);
  }

  public static void sort(long[] a, int fromIndex, int toIndex)
  {
    qsort(a, fromIndex, toIndex);
  }

  // The "cmp" method has been removed from here and replaced with direct
  // compares in situ, to avoid problems with overflow if the difference
  // between two numbers is bigger than a long will hold.
  // One particular change as a result is the use of r1 and r2 in qsort

  private static int med3(int a, int b, int c, long[]d)
  {
    return d[a] < d[b] ?
      (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
      : (d[b] > d[c] ? b : d[a] > d[c] ? c : a);
  }

  private static void swap(int i, int j, long[]a)
  {
    long c = a[i];
    a[i] = a[j];
    a[j] = c;
  }

  private static void qsort(long[]a, int start, int n)
  {
    // use an insertion sort on small arrays
    if (n < 7)
      {
	for (int i = start + 1; i < start + n; i++)
	  for (int j = i; j > 0 && a[j - 1] > a[j]; j--)
	    swap(j, j - 1, a);
	return;
      }

    int pm = n / 2;		// small arrays, middle element
    if (n > 7)
      {
	int pl = start;
	int pn = start + n - 1;

	if (n > 40)
	  {			// big arrays, pseudomedian of 9
	    int s = n / 8;
	    pl = med3(pl, pl + s, pl + 2 * s, a);
	    pm = med3(pm - s, pm, pm + s, a);
	    pn = med3(pn - 2 * s, pn - s, pn, a);
	  }
	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
      }

    int pa, pb, pc, pd, pv;
    long r1, r2;

    pv = start;
    swap(pv, pm, a);
    pa = pb = start;
    pc = pd = start + n - 1;

    for (;;)
      {
	while (pb <= pc && (r1 = a[pb]) <= (r2 = a[pv]))
	  {
	    if (r1 == r2)
	      {
		swap(pa, pb, a);
		pa++;
	      }
	    pb++;
	  }
	while (pc >= pb && (r1 = a[pc]) >= (r2 = a[pv]))
	  {
	    if (r1 == r2)
	      {
		swap(pc, pd, a);
		pd--;
	      }
	    pc--;
	  }
	if (pb > pc)
	  break;
	swap(pb, pc, a);
	pb++;
	pc--;
      }
    int pn = start + n;
    int s;
    s = Math.min(pa - start, pb - pa);
    vecswap(start, pb - s, s, a);
    s = Math.min(pd - pc, pn - pd - 1);
    vecswap(pb, pn - s, s, a);
    if ((s = pb - pa) > 1)
      qsort(a, start, s);
    if ((s = pd - pc) > 1)
      qsort(a, pn - s, s);
  }

  private static void vecswap(int i, int j, int n, long[]a)
  {
    for (; n > 0; i++, j++, n--)
      swap(i, j, a);
  }

  /**
   * Sort a short array into ascending order. The sort algorithm is an
   * optimised quicksort, as described in Jon L. Bentley and M. Douglas
   * McIlroy's "Engineering a Sort Function", Software-Practice and Experience,
   * Vol. 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
   * performance on many arrays that would take quadratic time with a standard
   * quicksort.
   *
   * @param a the array to sort
   */
  public static void sort(short[]a)
  {
    qsort(a, 0, a.length);
  }

  public static void sort(short[] a, int fromIndex, int toIndex)
  {
    qsort(a, fromIndex, toIndex);
  }

  private static int cmp(short i, short j)
  {
    return i - j;
  }

  private static int med3(int a, int b, int c, short[]d)
  {
    return cmp(d[a], d[b]) < 0 ?
      (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a)
      : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a);
  }

  private static void swap(int i, int j, short[]a)
  {
    short c = a[i];
    a[i] = a[j];
    a[j] = c;
  }

  private static void qsort(short[]a, int start, int n)
  {
    // use an insertion sort on small arrays
    if (n < 7)
      {
	for (int i = start + 1; i < start + n; i++)
	  for (int j = i; j > 0 && cmp(a[j - 1], a[j]) > 0; j--)
	    swap(j, j - 1, a);
	return;
      }

    int pm = n / 2;		// small arrays, middle element
    if (n > 7)
      {
	int pl = start;
	int pn = start + n - 1;

	if (n > 40)
	  {			// big arrays, pseudomedian of 9
	    int s = n / 8;
	    pl = med3(pl, pl + s, pl + 2 * s, a);
	    pm = med3(pm - s, pm, pm + s, a);
	    pn = med3(pn - 2 * s, pn - s, pn, a);
	  }
	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
      }

    int pa, pb, pc, pd, pv;
    int r;

    pv = start;
    swap(pv, pm, a);
    pa = pb = start;
    pc = pd = start + n - 1;

    for (;;)
      {
	while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0)
	  {
	    if (r == 0)
	      {
		swap(pa, pb, a);
		pa++;
	      }
	    pb++;
	  }
	while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0)
	  {
	    if (r == 0)
	      {
		swap(pc, pd, a);
		pd--;
	      }
	    pc--;
	  }
	if (pb > pc)
	  break;
	swap(pb, pc, a);
	pb++;
	pc--;
      }
    int pn = start + n;
    int s;
    s = Math.min(pa - start, pb - pa);
    vecswap(start, pb - s, s, a);
    s = Math.min(pd - pc, pn - pd - 1);
    vecswap(pb, pn - s, s, a);
    if ((s = pb - pa) > 1)
      qsort(a, start, s);
    if ((s = pd - pc) > 1)
      qsort(a, pn - s, s);
  }

  private static void vecswap(int i, int j, int n, short[]a)
  {
    for (; n > 0; i++, j++, n--)
      swap(i, j, a);
  }

  /**
   * The bulk of the work for the object sort routines.  In general,
   * the code attempts to be simple rather than fast, the idea being
   * that a good optimising JIT will be able to optimise it better
   * than I can, and if I try it will make it more confusing for the
   * JIT.  
   */
  private static void mergeSort(Object[]a, int from, int to, Comparator c)
  {
    // First presort the array in chunks of length 6 with insertion sort. 
    // mergesort would give too much overhead for this length.
    for (int chunk = from; chunk < to; chunk += 6)
      {
	int end = Math.min(chunk + 6, to);
	for (int i = chunk + 1; i < end; i++)
	  {
	    if (c.compare(a[i - 1], a[i]) > 0)
	      {
		// not already sorted
		int j = i;
		Object elem = a[j];
		do
		  {
		    a[j] = a[j - 1];
		    j--;
		  }
		while (j > chunk && c.compare(a[j - 1], elem) > 0);
		a[j] = elem;
	      }
	  }
      }

    int len = to - from;
    // If length is smaller or equal 6 we are done.
    if (len <= 6)
      return;

    Object[]src = a;
    Object[]dest = new Object[len];
    Object[]t = null;		// t is used for swapping src and dest

    // The difference of the fromIndex of the src and dest array.
    int srcDestDiff = -from;

    // The merges are done in this loop
    for (int size = 6; size < len; size <<= 1)
      {
	for (int start = from; start < to; start += size << 1)
	  {
	    // mid ist the start of the second sublist;
	    // end the start of the next sublist (or end of array).
	    int mid = start + size;
	    int end = Math.min(to, mid + size);

	    // The second list is empty or the elements are already in
	    // order - no need to merge
	    if (mid >= end || c.compare(src[mid - 1], src[mid]) <= 0)
	      {
		System.arraycopy(src, start,
				 dest, start + srcDestDiff, end - start);

		// The two halves just need swapping - no need to merge
	      }
	    else if (c.compare(src[start], src[end - 1]) > 0)
	      {
		System.arraycopy(src, start,
				 dest, end - size + srcDestDiff, size);
		System.arraycopy(src, mid,
				 dest, start + srcDestDiff, end - mid);

	      }
	    else
	      {
		// Declare a lot of variables to save repeating
		// calculations.  Hopefully a decent JIT will put these
		// in registers and make this fast
		int p1 = start;
		int p2 = mid;
		int i = start + srcDestDiff;

		// The main merge loop; terminates as soon as either
		// half is ended
		while (p1 < mid && p2 < end)
		  {
		    dest[i++] =
		      src[c.compare(src[p1], src[p2]) <= 0 ? p1++ : p2++];
		  }

		// Finish up by copying the remainder of whichever half
		// wasn't finished.
		if (p1 < mid)
		  System.arraycopy(src, p1, dest, i, mid - p1);
		else
		  System.arraycopy(src, p2, dest, i, end - p2);
	      }
	  }
	// swap src and dest ready for the next merge
	t = src;
	src = dest;
	dest = t;
	from += srcDestDiff;
	to += srcDestDiff;
	srcDestDiff = -srcDestDiff;
      }

    // make sure the result ends up back in the right place.  Note
    // that src and dest may have been swapped above, so src 
    // contains the sorted array.
    if (src != a)
      {
	// Note that from == 0.
	System.arraycopy(src, 0, a, srcDestDiff, to);
      }
  }

  /**
   * Sort an array of Objects according to their natural ordering. The sort is
   * guaranteed to be stable, that is, equal elements will not be reordered.
   * The sort algorithm is a mergesort with the merge omitted if the last
   * element of one half comes before the first element of the other half. This
   * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a
   * copy of the array.
   *
   * @param a the array to be sorted
   * @exception ClassCastException if any two elements are not mutually
   *   comparable
   * @exception NullPointerException if an element is null (since
   *   null.compareTo cannot work)
   */
  public static void sort(Object[]a)
  {
    mergeSort(a, 0, a.length, defaultComparator);
  }

  /**
   * Sort an array of Objects according to a Comparator. The sort is
   * guaranteed to be stable, that is, equal elements will not be reordered.
   * The sort algorithm is a mergesort with the merge omitted if the last
   * element of one half comes before the first element of the other half. This
   * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a
   * copy of the array.
   *
   * @param a the array to be sorted
   * @param c a Comparator to use in sorting the array
   * @exception ClassCastException if any two elements are not mutually
   *   comparable by the Comparator provided
   */
  public static void sort(Object[]a, Comparator c)
  {
    mergeSort(a, 0, a.length, c);
  }

  /**
   * Sort an array of Objects according to their natural ordering. The sort is
   * guaranteed to be stable, that is, equal elements will not be reordered.
   * The sort algorithm is a mergesort with the merge omitted if the last
   * element of one half comes before the first element of the other half. This
   * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a
   * copy of the array.
   *
   * @param a the array to be sorted
   * @param fromIndex the index of the first element to be sorted.
   * @param toIndex the index of the last element to be sorted plus one.
   * @exception ClassCastException if any two elements are not mutually
   *   comparable by the Comparator provided
   * @exception ArrayIndexOutOfBoundsException, if fromIndex and toIndex
   *   are not in range.
   * @exception IllegalArgumentException if fromIndex > toIndex
   */
  public static void sort(Object[]a, int fromIndex, int toIndex)
  {
    if (fromIndex > toIndex)
      throw new IllegalArgumentException("fromIndex " + fromIndex
					 + " > toIndex " + toIndex);
    mergeSort(a, fromIndex, toIndex, defaultComparator);
  }

  /**
   * Sort an array of Objects according to a Comparator. The sort is
   * guaranteed to be stable, that is, equal elements will not be reordered.
   * The sort algorithm is a mergesort with the merge omitted if the last
   * element of one half comes before the first element of the other half. This
   * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a
   * copy of the array.
   *
   * @param a the array to be sorted
   * @param fromIndex the index of the first element to be sorted.
   * @param toIndex the index of the last element to be sorted plus one.
   * @param c a Comparator to use in sorting the array
   * @exception ClassCastException if any two elements are not mutually
   *   comparable by the Comparator provided
   * @exception ArrayIndexOutOfBoundsException, if fromIndex and toIndex
   *   are not in range.
   * @exception IllegalArgumentException if fromIndex > toIndex
   */
  public static void sort(Object[]a, int fromIndex, int toIndex, Comparator c)
  {
    if (fromIndex > toIndex)
      throw new IllegalArgumentException("fromIndex " + fromIndex
					 + " > toIndex " + toIndex);
    mergeSort(a, fromIndex, toIndex, c);
  }

  /**
   * Returns a list "view" of the specified array. This method is intended to
   * make it easy to use the Collections API with existing array-based APIs and
   * programs.
   *
   * @param a the array to return a view of
   * @returns a fixed-size list, changes to which "write through" to the array
   */
  public static List asList(final Object[]a)
  {
    if (a == null)
      {
	throw new NullPointerException();
      }

    return new ListImpl(a);
  }


  /**
   * Inner class used by asList(Object[]) to provide a list interface
   * to an array. The methods are all simple enough to be self documenting.
   * Note: When Sun fully specify serialized forms, this class will have to
   * be renamed.
   */
  private static class ListImpl extends AbstractList
  {
    ListImpl(Object[]a)
    {
      this.a = a;
    }

    public Object get(int index)
    {
      return a[index];
    }

    public int size()
    {
      return a.length;
    }

    public Object set(int index, Object element)
    {
      Object old = a[index];
      a[index] = element;
      return old;
    }

    private Object[] a;
  }
}
