1 // Member of the utility package.
\r
2 // Modified July 20, 2009 to handle very large arrays
\r
4 package nom.tam.util;
\r
6 /* Copyright: Thomas McGlynn 1997-1998.
\r
7 * This code may be used for any purpose, non-commercial
\r
8 * or commercial so long as this copyright notice is retained
\r
9 * in the source code or included in or referred to in any
\r
12 import java.lang.reflect.*;
\r
13 import java.util.Arrays;
\r
15 /** This is a package of static functions which perform
\r
16 * computations on arrays. Generally these routines attempt
\r
17 * to complete without throwing errors by ignoring data
\r
18 * they cannot understand.
\r
20 public class ArrayFuncs implements PrimitiveInfo {
\r
22 /** Compute the size of an object. Note that this only handles
\r
23 * arrays or scalars of the primitive objects and Strings. It
\r
24 * returns 0 for any object array element it does not understand.
\r
26 * @param o The object whose size is desired.
\r
27 * @deprecated May silently underestimate the size
\r
28 * if the size > 2 GB.
\r
30 public static int computeSize(Object o) {
\r
31 return (int) computeLSize(o);
\r
34 public static long computeLSize(Object o) {
\r
41 String classname = o.getClass().getName();
\r
42 if (classname.substring(0, 2).equals("[[")) {
\r
44 for (int i = 0; i < ((Object[]) o).length; i += 1) {
\r
45 size += computeLSize(((Object[]) o)[i]);
\r
50 if (classname.charAt(0) == '[' && classname.charAt(1) != 'L') {
\r
51 char c = classname.charAt(1);
\r
53 for (int i = 0; i < PrimitiveInfo.suffixes.length; i += 1) {
\r
54 if (c == PrimitiveInfo.suffixes[i]) {
\r
55 return (long) (Array.getLength(o)) * PrimitiveInfo.sizes[i];
\r
61 // Do we have a non-primitive array?
\r
62 if (classname.charAt(0) == '[') {
\r
64 for (int i = 0; i < Array.getLength(o); i += 1) {
\r
65 len += computeLSize(Array.get(o, i));
\r
70 // Now a few special scalar objects.
\r
71 if (classname.substring(0, 10).equals("java.lang.")) {
\r
72 classname = classname.substring(10, classname.length());
\r
73 if (classname.equals("Integer") || classname.equals("Float")) {
\r
75 } else if (classname.equals("Double") || classname.equals("Long")) {
\r
77 } else if (classname.equals("Short") || classname.equals("Char")) {
\r
79 } else if (classname.equals("Byte") || classname.equals("Boolean")) {
\r
81 } else if (classname.equals("String")) {
\r
82 return ((String) o).length();
\r
90 /** Count the number of elements in an array.
\r
91 * @deprecated May silently underestimate
\r
92 * size if number is > 2 G.
\r
94 public static int nElements(Object o) {
\r
95 return (int) nLElements(o);
\r
98 /** Count the number of elements in an array.
\r
99 * @deprecated May silently underestimate
\r
100 * size if number is > 2 G.
\r
102 public static long nLElements(Object o) {
\r
108 String classname = o.getClass().getName();
\r
109 if (classname.charAt(1) == '[') {
\r
111 for (int i = 0; i < ((Object[]) o).length; i += 1) {
\r
112 count += nLElements(((Object[]) o)[i]);
\r
116 } else if (classname.charAt(0) == '[') {
\r
117 return Array.getLength(o);
\r
124 /** Try to create a deep clone of an Array or a standard clone of a scalar.
\r
125 * The object may comprise arrays of
\r
126 * any primitive type or any Object type which implements Cloneable.
\r
127 * However, if the Object is some kind of collection, e.g., a Vector
\r
128 * then only a shallow copy of that object is made. I.e., deep refers
\r
131 * @param o The object to be copied.
\r
133 public static Object deepClone(Object o) {
\r
139 String classname = o.getClass().getName();
\r
141 // Is this an array?
\r
142 if (classname.charAt(0) != '[') {
\r
143 return genericClone(o);
\r
146 // Check if this is a 1D primitive array.
\r
147 if (classname.charAt(1) != '[' && classname.charAt(1) != 'L') {
\r
149 // Some compilers (SuperCede, e.g.) still
\r
150 // think you have to catch this...
\r
152 throw new CloneNotSupportedException();
\r
154 switch (classname.charAt(1)) {
\r
156 return ((byte[]) o).clone();
\r
158 return ((boolean[]) o).clone();
\r
160 return ((char[]) o).clone();
\r
162 return ((short[]) o).clone();
\r
164 return ((int[]) o).clone();
\r
166 return ((long[]) o).clone();
\r
168 return ((float[]) o).clone();
\r
170 return ((double[]) o).clone();
\r
172 System.err.println("Unknown primtive array class:" + classname);
\r
176 } catch (CloneNotSupportedException e) {
\r
180 // Get the base type.
\r
182 while (classname.charAt(ndim) == '[') {
\r
186 if (classname.charAt(ndim) != 'L') {
\r
187 baseClass = getBaseClass(o);
\r
190 baseClass = Class.forName(classname.substring(ndim + 1, classname.length() - 1));
\r
191 } catch (ClassNotFoundException e) {
\r
192 System.err.println("Internal error: class definition inconsistency: " + classname);
\r
197 // Allocate the array but make all but the first dimension 0.
\r
198 int[] dims = new int[ndim];
\r
199 dims[0] = Array.getLength(o);
\r
200 for (int i = 1; i < ndim; i += 1) {
\r
204 Object copy = ArrayFuncs.newInstance(baseClass, dims);
\r
206 // Now fill in the next level down by recursion.
\r
207 for (int i = 0; i < dims[0]; i += 1) {
\r
208 Array.set(copy, i, deepClone(Array.get(o, i)));
\r
214 /** Clone an Object if possible.
\r
216 * This method returns an Object which is a clone of the
\r
217 * input object. It checks if the method implements the
\r
218 * Cloneable interface and then uses reflection to invoke
\r
219 * the clone method. This can't be done directly since
\r
220 * as far as the compiler is concerned the clone method for
\r
221 * Object is protected and someone could implement Cloneable but
\r
222 * leave the clone method protected. The cloning can fail in a
\r
223 * variety of ways which are trapped so that it returns null instead.
\r
224 * This method will generally create a shallow clone. If you
\r
225 * wish a deep copy of an array the method deepClone should be used.
\r
227 * @param o The object to be cloned.
\r
229 public static Object genericClone(Object o) {
\r
231 if (!(o instanceof Cloneable)) {
\r
235 Class[] argTypes = new Class[0];
\r
236 Object[] args = new Object[0];
\r
237 Class type = o.getClass();
\r
240 return type.getMethod("clone", argTypes).invoke(o, args);
\r
241 } catch (Exception e) {
\r
242 if (type.isArray()) {
\r
243 return deepClone(o);
\r
245 // Implements cloneable, but does not
\r
246 // apparently make clone public.
\r
251 /** Copy one array into another.
\r
252 * This function copies the contents of one array
\r
253 * into a previously allocated array.
\r
254 * The arrays must agree in type and size.
\r
255 * @param original The array to be copied.
\r
256 * @param copy The array to be copied into. This
\r
257 * array must already be fully allocated.
\r
259 public static void copyArray(Object original, Object copy) {
\r
260 String oname = original.getClass().getName();
\r
261 String cname = copy.getClass().getName();
\r
263 if (!oname.equals(cname)) {
\r
267 if (oname.charAt(0) != '[') {
\r
271 if (oname.charAt(1) == '[') {
\r
272 Object[] x = (Object[]) original;
\r
273 Object[] y = (Object[]) copy;
\r
274 if (x.length != y.length) {
\r
277 for (int i = 0; i < x.length; i += 1) {
\r
281 int len = Array.getLength(original);
\r
283 System.arraycopy(original, 0, copy, 0, len);
\r
286 /** Find the dimensions of an object.
\r
288 * This method returns an integer array with the dimensions
\r
289 * of the object o which should usually be an array.
\r
291 * It returns an array of dimension 0 for scalar objects
\r
292 * and it returns -1 for dimension which have not been allocated,
\r
293 * e.g., int[][][] x = new int[100][][]; should return [100,-1,-1].
\r
295 * @param o The object to get the dimensions of.
\r
297 public static int[] getDimensions(Object o) {
\r
303 String classname = o.getClass().getName();
\r
307 while (classname.charAt(ndim) == '[') {
\r
311 int[] dimens = new int[ndim];
\r
313 for (int i = 0; i < ndim; i += 1) {
\r
314 dimens[i] = -1; // So that we can distinguish a null from a 0 length.
\r
317 for (int i = 0; i < ndim; i += 1) {
\r
318 dimens[i] = java.lang.reflect.Array.getLength(o);
\r
319 if (dimens[i] == 0) {
\r
322 if (i != ndim - 1) {
\r
323 o = ((Object[]) o)[0];
\r
332 /** This routine returns the base array of a multi-dimensional
\r
333 * array. I.e., a one-d array of whatever the array is composed
\r
334 * of. Note that arrays are not guaranteed to be rectangular,
\r
335 * so this returns o[0][0]....
\r
337 public static Object getBaseArray(Object o) {
\r
338 String cname = o.getClass().getName();
\r
339 if (cname.charAt(1) == '[') {
\r
340 return getBaseArray(((Object[]) o)[0]);
\r
346 /** This routine returns the base class of an object. This is just
\r
347 * the class of the object for non-arrays.
\r
349 public static Class getBaseClass(Object o) {
\r
355 String className = o.getClass().getName();
\r
358 while (className.charAt(dims) == '[') {
\r
363 return o.getClass();
\r
366 char c = className.charAt(dims);
\r
367 for (int i = 0; i < PrimitiveInfo.suffixes.length; i += 1) {
\r
368 if (c == PrimitiveInfo.suffixes[i]) {
\r
369 return PrimitiveInfo.classes[i];
\r
375 return Class.forName(className.substring(dims + 1, className.length() - 1));
\r
376 } catch (ClassNotFoundException e) {
\r
383 /** This routine returns the size of the base element of an array.
\r
384 * @param o The array object whose base length is desired.
\r
385 * @return the size of the object in bytes, 0 if null, or
\r
386 * -1 if not a primitive array.
\r
388 public static int getBaseLength(Object o) {
\r
394 String className = o.getClass().getName();
\r
398 while (className.charAt(dims) == '[') {
\r
406 char c = className.charAt(dims);
\r
407 for (int i = 0; i < PrimitiveInfo.suffixes.length; i += 1) {
\r
408 if (c == PrimitiveInfo.suffixes[i]) {
\r
409 return PrimitiveInfo.sizes[i];
\r
415 /** Create an array and populate it with a test pattern.
\r
417 * @param baseType The base type of the array. This is expected to
\r
418 * be a numeric type, but this is not checked.
\r
419 * @param dims The desired dimensions.
\r
420 * @return An array object populated with a simple test pattern.
\r
422 public static Object generateArray(Class baseType, int[] dims) {
\r
424 // Generate an array and populate it with a test pattern of
\r
427 Object x = ArrayFuncs.newInstance(baseType, dims);
\r
428 testPattern(x, (byte) 0);
\r
432 /** Just create a simple pattern cycling through valid byte values.
\r
433 * We use bytes because they can be cast to any other numeric type.
\r
434 * @param o The array in which the test pattern is to be set.
\r
435 * @param start The value for the first element.
\r
437 public static byte testPattern(Object o, byte start) {
\r
439 int[] dims = getDimensions(o);
\r
440 if (dims.length > 1) {
\r
441 for (int i = 0; i < ((Object[]) o).length; i += 1) {
\r
442 start = testPattern(((Object[]) o)[i], start);
\r
445 } else if (dims.length == 1) {
\r
446 for (int i = 0; i < dims[0]; i += 1) {
\r
447 java.lang.reflect.Array.setByte(o, i, start);
\r
454 /** Generate a description of an array (presumed rectangular).
\r
455 * @param o The array to be described.
\r
457 public static String arrayDescription(Object o) {
\r
459 Class base = getBaseClass(o);
\r
460 if (base == Void.TYPE) {
\r
464 int[] dims = getDimensions(o);
\r
466 StringBuffer desc = new StringBuffer();
\r
468 // Note that all instances Class describing a given class are
\r
469 // the same so we can use == here.
\r
470 boolean found = false;
\r
472 for (int i = 0; i < PrimitiveInfo.classes.length; i += 1) {
\r
473 if (base == PrimitiveInfo.classes[i]) {
\r
475 desc.append(PrimitiveInfo.types[i]);
\r
481 desc.append(base.getName());
\r
484 if (dims != null) {
\r
486 for (int i = 0; i < dims.length; i += 1) {
\r
487 desc.append("" + dims[i]);
\r
488 if (i < dims.length - 1) {
\r
494 return new String(desc);
\r
497 /** Examine the structure of an array in detail.
\r
498 * @param o The array to be examined.
\r
500 public static void examinePrimitiveArray(Object o) {
\r
501 String className = o.getClass().getName();
\r
503 // If we have a two-d array, or if the array is a one-d array
\r
504 // of Objects, then recurse over the next dimension. We handle
\r
505 // Object specially because each element could itself be an array.
\r
506 if (className.substring(0, 2).equals("[[")
\r
507 || className.equals("[Ljava.lang.Object;")) {
\r
508 System.out.println("[");
\r
509 for (int i = 0; i < ((Object[]) o).length; i += 1) {
\r
510 examinePrimitiveArray(((Object[]) o)[i]);
\r
512 System.out.print("]");
\r
513 } else if (className.charAt(0) != '[') {
\r
514 System.out.println(className);
\r
516 System.out.println("[" + java.lang.reflect.Array.getLength(o) + "]"
\r
517 + className.substring(1));
\r
521 /** Given an array of arbitrary dimensionality return
\r
522 * the array flattened into a single dimension.
\r
523 * @param input The input array.
\r
525 public static Object flatten(Object input) {
\r
527 int[] dimens = getDimensions(input);
\r
528 if (dimens.length <= 1) {
\r
532 for (int i = 0; i < dimens.length; i += 1) {
\r
536 Object flat = ArrayFuncs.newInstance(getBaseClass(input), size);
\r
543 doFlatten(input, flat, offset);
\r
547 /** This routine does the actually flattening of multi-dimensional
\r
549 * @param input The input array to be flattened.
\r
550 * @param output The flattened array.
\r
551 * @param offset The current offset within the output array.
\r
552 * @return The number of elements within the array.
\r
554 protected static int doFlatten(Object input, Object output, int offset) {
\r
556 String classname = input.getClass().getName();
\r
557 if (classname.charAt(0) != '[') {
\r
558 throw new RuntimeException("Attempt to flatten non-array");
\r
560 int size = Array.getLength(input);
\r
562 if (classname.charAt(1) != '[') {
\r
563 System.arraycopy(input, 0, output, offset, size);
\r
567 Object[] xx = (Object[]) input;
\r
568 for (int i = 0; i < size; i += 1) {
\r
569 int len = doFlatten(xx[i], output, offset + total);
\r
575 /** Curl an input array up into a multi-dimensional array.
\r
577 * @param input The one dimensional array to be curled.
\r
578 * @param dimens The desired dimensions
\r
579 * @return The curled array.
\r
581 public static Object curl(Object input, int[] dimens) {
\r
583 if (input == null) {
\r
586 String classname = input.getClass().getName();
\r
587 if (classname.charAt(0) != '[' || classname.charAt(1) == '[') {
\r
588 throw new RuntimeException("Attempt to curl non-1D array");
\r
591 int size = Array.getLength(input);
\r
594 for (int i = 0; i < dimens.length; i += 1) {
\r
598 if (test != size) {
\r
599 throw new RuntimeException("Curled array does not fit desired dimensions");
\r
602 Class base = getBaseClass(input);
\r
604 Object newArray = ArrayFuncs.newInstance(base, dimens);
\r
608 doCurl(input, newArray, dimens, offset);
\r
613 /** Do the curling of the 1-d to multi-d array.
\r
614 * @param input The 1-d array to be curled.
\r
615 * @param output The multi-dimensional array to be filled.
\r
616 * @param dimens The desired output dimensions.
\r
617 * @param offset The current offset in the input array.
\r
618 * @return The number of elements curled.
\r
620 protected static int doCurl(Object input, Object output,
\r
621 int[] dimens, int offset) {
\r
623 if (dimens.length == 1) {
\r
624 System.arraycopy(input, offset, output, 0, dimens[0]);
\r
629 int[] xdimens = new int[dimens.length - 1];
\r
630 for (int i = 1; i < dimens.length; i += 1) {
\r
631 xdimens[i - 1] = dimens[i];
\r
634 for (int i = 0; i < dimens[0]; i += 1) {
\r
635 total += doCurl(input, ((Object[]) output)[i], xdimens, offset + total);
\r
640 /** Create an array of a type given by new type with
\r
641 * the dimensionality given in array.
\r
642 * @param array A possibly multidimensional array to be converted.
\r
643 * @param newType The desired output type. This should be one of the
\r
644 * class descriptors for primitive numeric data, e.g., double.type.
\r
646 public static Object mimicArray(Object array, Class newType) {
\r
648 String classname = array.getClass().getName();
\r
649 if (classname.charAt(0) != '[') {
\r
655 while (classname.charAt(dims) == '[') {
\r
663 Object[] xarray = (Object[]) array;
\r
664 int[] dimens = new int[dims];
\r
665 dimens[0] = xarray.length; // Leave other dimensions at 0.
\r
668 mimic = ArrayFuncs.newInstance(newType, dimens);
\r
670 for (int i = 0; i < xarray.length; i += 1) {
\r
671 Object temp = mimicArray(xarray[i], newType);
\r
672 ((Object[]) mimic)[i] = temp;
\r
676 mimic = ArrayFuncs.newInstance(newType, Array.getLength(array));
\r
682 /** Convert an array to a specified type. This method supports conversions
\r
683 * only among the primitive numeric types.
\r
684 * @param array A possibly multidimensional array to be converted.
\r
685 * @param newType The desired output type. This should be one of the
\r
686 * class descriptors for primitive numeric data, e.g., double.type.
\r
687 * @param preserve If set, and the requested type is the same as the
\r
688 * original, then the original is returned.
\r
690 public static Object convertArray(Object array, Class newType, boolean reuse) {
\r
692 if (getBaseClass(array) == newType && reuse) {
\r
695 return convertArray(array, newType);
\r
699 /** Convert an array to a specified type. This method supports conversions
\r
700 * only among the primitive numeric types.
\r
701 * @param array A possibly multidimensional array to be converted.
\r
702 * @param newType The desired output type. This should be one of the
\r
703 * class descriptors for primitive numeric data, e.g., double.type.
\r
705 public static Object convertArray(Object array, Class newType) {
\r
707 /* We break this up into two steps so that users
\r
708 * can reuse an array many times and only allocate a
\r
709 * new array when needed.
\r
712 /* First create the full new array. */
\r
713 Object mimic = mimicArray(array, newType);
\r
714 if (mimic == null) {
\r
718 /* Now copy the info into the new array */
\r
719 copyInto(array, mimic);
\r
724 /** Copy an array into an array of a different type.
\r
725 * The dimensions and dimensionalities of the two
\r
726 * arrays should be the same.
\r
727 * @param array The original array.
\r
728 * @param mimic The array mimicking the original.
\r
730 public static void copyInto(Object array, Object mimic) {
\r
732 String classname = array.getClass().getName();
\r
733 if (classname.charAt(0) != '[') {
\r
737 /* Do multidimensional arrays recursively */
\r
738 if (classname.charAt(1) == '[') {
\r
740 for (int i = 0; i < ((Object[]) array).length; i += 1) {
\r
741 copyInto(((Object[]) array)[i], ((Object[]) mimic)[i]);
\r
754 Class base = getBaseClass(array);
\r
755 Class newType = getBaseClass(mimic);
\r
757 if (base == byte.class) {
\r
758 byte[] barr = (byte[]) array;
\r
760 if (newType == byte.class) {
\r
761 System.arraycopy(array, 0, mimic, 0, barr.length);
\r
763 } else if (newType == short.class) {
\r
764 xsarr = (short[]) mimic;
\r
765 for (int i = 0; i < barr.length; i += 1) {
\r
766 xsarr[i] = barr[i];
\r
769 } else if (newType == char.class) {
\r
770 xcarr = (char[]) mimic;
\r
771 for (int i = 0; i < barr.length; i += 1) {
\r
772 xcarr[i] = (char) barr[i];
\r
775 } else if (newType == int.class) {
\r
776 xiarr = (int[]) mimic;
\r
777 for (int i = 0; i < barr.length; i += 1) {
\r
778 xiarr[i] = barr[i];
\r
781 } else if (newType == long.class) {
\r
782 xlarr = (long[]) mimic;
\r
783 for (int i = 0; i < barr.length; i += 1) {
\r
784 xlarr[i] = barr[i];
\r
787 } else if (newType == float.class) {
\r
788 xfarr = (float[]) mimic;
\r
789 for (int i = 0; i < barr.length; i += 1) {
\r
790 xfarr[i] = barr[i];
\r
793 } else if (newType == double.class) {
\r
794 xdarr = (double[]) mimic;
\r
795 for (int i = 0; i < barr.length; i += 1) {
\r
796 xdarr[i] = barr[i];
\r
800 } else if (base == short.class) {
\r
801 short[] sarr = (short[]) array;
\r
803 if (newType == byte.class) {
\r
804 xbarr = (byte[]) mimic;
\r
805 for (int i = 0; i < sarr.length; i += 1) {
\r
806 xbarr[i] = (byte) sarr[i];
\r
809 } else if (newType == short.class) {
\r
810 System.arraycopy(array, 0, mimic, 0, sarr.length);
\r
812 } else if (newType == char.class) {
\r
813 xcarr = (char[]) mimic;
\r
814 for (int i = 0; i < sarr.length; i += 1) {
\r
815 xcarr[i] = (char) sarr[i];
\r
818 } else if (newType == int.class) {
\r
819 xiarr = (int[]) mimic;
\r
820 for (int i = 0; i < sarr.length; i += 1) {
\r
821 xiarr[i] = sarr[i];
\r
824 } else if (newType == long.class) {
\r
825 xlarr = (long[]) mimic;
\r
826 for (int i = 0; i < sarr.length; i += 1) {
\r
827 xlarr[i] = sarr[i];
\r
830 } else if (newType == float.class) {
\r
831 xfarr = (float[]) mimic;
\r
832 for (int i = 0; i < sarr.length; i += 1) {
\r
833 xfarr[i] = sarr[i];
\r
836 } else if (newType == double.class) {
\r
837 xdarr = (double[]) mimic;
\r
838 for (int i = 0; i < sarr.length; i += 1) {
\r
839 xdarr[i] = sarr[i];
\r
843 } else if (base == char.class) {
\r
844 char[] carr = (char[]) array;
\r
846 if (newType == byte.class) {
\r
847 xbarr = (byte[]) mimic;
\r
848 for (int i = 0; i < carr.length; i += 1) {
\r
849 xbarr[i] = (byte) carr[i];
\r
852 } else if (newType == short.class) {
\r
853 xsarr = (short[]) mimic;
\r
854 for (int i = 0; i < carr.length; i += 1) {
\r
855 xsarr[i] = (short) carr[i];
\r
858 } else if (newType == char.class) {
\r
859 System.arraycopy(array, 0, mimic, 0, carr.length);
\r
861 } else if (newType == int.class) {
\r
862 xiarr = (int[]) mimic;
\r
863 for (int i = 0; i < carr.length; i += 1) {
\r
864 xiarr[i] = carr[i];
\r
867 } else if (newType == long.class) {
\r
868 xlarr = (long[]) mimic;
\r
869 for (int i = 0; i < carr.length; i += 1) {
\r
870 xlarr[i] = carr[i];
\r
873 } else if (newType == float.class) {
\r
874 xfarr = (float[]) mimic;
\r
875 for (int i = 0; i < carr.length; i += 1) {
\r
876 xfarr[i] = carr[i];
\r
879 } else if (newType == double.class) {
\r
880 xdarr = (double[]) mimic;
\r
881 for (int i = 0; i < carr.length; i += 1) {
\r
882 xdarr[i] = carr[i];
\r
886 } else if (base == int.class) {
\r
887 int[] iarr = (int[]) array;
\r
889 if (newType == byte.class) {
\r
890 xbarr = (byte[]) mimic;
\r
891 for (int i = 0; i < iarr.length; i += 1) {
\r
892 xbarr[i] = (byte) iarr[i];
\r
895 } else if (newType == short.class) {
\r
896 xsarr = (short[]) mimic;
\r
897 for (int i = 0; i < iarr.length; i += 1) {
\r
898 xsarr[i] = (short) iarr[i];
\r
901 } else if (newType == char.class) {
\r
902 xcarr = (char[]) mimic;
\r
903 for (int i = 0; i < iarr.length; i += 1) {
\r
904 xcarr[i] = (char) iarr[i];
\r
907 } else if (newType == int.class) {
\r
908 System.arraycopy(array, 0, mimic, 0, iarr.length);
\r
910 } else if (newType == long.class) {
\r
911 xlarr = (long[]) mimic;
\r
912 for (int i = 0; i < iarr.length; i += 1) {
\r
913 xlarr[i] = iarr[i];
\r
916 } else if (newType == float.class) {
\r
917 xfarr = (float[]) mimic;
\r
918 for (int i = 0; i < iarr.length; i += 1) {
\r
919 xfarr[i] = iarr[i];
\r
922 } else if (newType == double.class) {
\r
923 xdarr = (double[]) mimic;
\r
924 for (int i = 0; i < iarr.length; i += 1) {
\r
925 xdarr[i] = iarr[i];
\r
930 } else if (base == long.class) {
\r
931 long[] larr = (long[]) array;
\r
933 if (newType == byte.class) {
\r
934 xbarr = (byte[]) mimic;
\r
935 for (int i = 0; i < larr.length; i += 1) {
\r
936 xbarr[i] = (byte) larr[i];
\r
939 } else if (newType == short.class) {
\r
940 xsarr = (short[]) mimic;
\r
941 for (int i = 0; i < larr.length; i += 1) {
\r
942 xsarr[i] = (short) larr[i];
\r
945 } else if (newType == char.class) {
\r
946 xcarr = (char[]) mimic;
\r
947 for (int i = 0; i < larr.length; i += 1) {
\r
948 xcarr[i] = (char) larr[i];
\r
951 } else if (newType == int.class) {
\r
952 xiarr = (int[]) mimic;
\r
953 for (int i = 0; i < larr.length; i += 1) {
\r
954 xiarr[i] = (int) larr[i];
\r
957 } else if (newType == long.class) {
\r
958 System.arraycopy(array, 0, mimic, 0, larr.length);
\r
960 } else if (newType == float.class) {
\r
961 xfarr = (float[]) mimic;
\r
962 for (int i = 0; i < larr.length; i += 1) {
\r
963 xfarr[i] = (float) larr[i];
\r
966 } else if (newType == double.class) {
\r
967 xdarr = (double[]) mimic;
\r
968 for (int i = 0; i < larr.length; i += 1) {
\r
969 xdarr[i] = (double) larr[i];
\r
973 } else if (base == float.class) {
\r
974 float[] farr = (float[]) array;
\r
976 if (newType == byte.class) {
\r
977 xbarr = (byte[]) mimic;
\r
978 for (int i = 0; i < farr.length; i += 1) {
\r
979 xbarr[i] = (byte) farr[i];
\r
982 } else if (newType == short.class) {
\r
983 xsarr = (short[]) mimic;
\r
984 for (int i = 0; i < farr.length; i += 1) {
\r
985 xsarr[i] = (short) farr[i];
\r
988 } else if (newType == char.class) {
\r
989 xcarr = (char[]) mimic;
\r
990 for (int i = 0; i < farr.length; i += 1) {
\r
991 xcarr[i] = (char) farr[i];
\r
994 } else if (newType == int.class) {
\r
995 xiarr = (int[]) mimic;
\r
996 for (int i = 0; i < farr.length; i += 1) {
\r
997 xiarr[i] = (int) farr[i];
\r
1000 } else if (newType == long.class) {
\r
1001 xlarr = (long[]) mimic;
\r
1002 for (int i = 0; i < farr.length; i += 1) {
\r
1003 xlarr[i] = (long) farr[i];
\r
1006 } else if (newType == float.class) {
\r
1007 System.arraycopy(array, 0, mimic, 0, farr.length);
\r
1009 } else if (newType == double.class) {
\r
1010 xdarr = (double[]) mimic;
\r
1011 for (int i = 0; i < farr.length; i += 1) {
\r
1012 xdarr[i] = farr[i];
\r
1017 } else if (base == double.class) {
\r
1018 double[] darr = (double[]) array;
\r
1020 if (newType == byte.class) {
\r
1021 xbarr = (byte[]) mimic;
\r
1022 for (int i = 0; i < darr.length; i += 1) {
\r
1023 xbarr[i] = (byte) darr[i];
\r
1026 } else if (newType == short.class) {
\r
1027 xsarr = (short[]) mimic;
\r
1028 for (int i = 0; i < darr.length; i += 1) {
\r
1029 xsarr[i] = (short) darr[i];
\r
1032 } else if (newType == char.class) {
\r
1033 xcarr = (char[]) mimic;
\r
1034 for (int i = 0; i < darr.length; i += 1) {
\r
1035 xcarr[i] = (char) darr[i];
\r
1038 } else if (newType == int.class) {
\r
1039 xiarr = (int[]) mimic;
\r
1040 for (int i = 0; i < darr.length; i += 1) {
\r
1041 xiarr[i] = (int) darr[i];
\r
1044 } else if (newType == long.class) {
\r
1045 xlarr = (long[]) mimic;
\r
1046 for (int i = 0; i < darr.length; i += 1) {
\r
1047 xlarr[i] = (long) darr[i];
\r
1050 } else if (newType == float.class) {
\r
1051 xfarr = (float[]) mimic;
\r
1052 for (int i = 0; i < darr.length; i += 1) {
\r
1053 xfarr[i] = (float) darr[i];
\r
1056 } else if (newType == double.class) {
\r
1057 System.arraycopy(array, 0, mimic, 0, darr.length);
\r
1066 /** Allocate an array dynamically. The Array.newInstance method
\r
1067 * does not throw an error when there is insufficient memory
\r
1068 * and silently returns a null.
\r
1069 * @param cl The class of the array.
\r
1070 * @param dim The dimension of the array.
\r
1071 * @return The allocated array.
\r
1072 * @throws An OutOfMemoryError if insufficient space is available.
\r
1074 public static Object newInstance(Class cl, int dim) {
\r
1076 Object o = Array.newInstance(cl, dim);
\r
1078 String desc = cl + "[" + dim + "]";
\r
1079 throw new OutOfMemoryError("Unable to allocate array: " + desc);
\r
1084 /** Allocate an array dynamically. The Array.newInstance method
\r
1085 * does not throw an error and silently returns a null.
\r
1087 * @param cl The class of the array.
\r
1088 * @param dims The dimensions of the array.
\r
1089 * @return The allocated array.
\r
1090 * @throws An OutOfMemoryError if insufficient space is available.
\r
1092 public static Object newInstance(Class cl, int[] dims) {
\r
1094 if (dims.length == 0) {
\r
1095 // Treat a scalar as a 1-d array of length 1
\r
1096 dims = new int[]{1};
\r
1099 Object o = Array.newInstance(cl, dims);
\r
1101 String desc = cl + "[";
\r
1102 String comma = "";
\r
1103 for (int i = 0; i < dims.length; i += 1) {
\r
1104 desc += comma + dims[i];
\r
1108 throw new OutOfMemoryError("Unable to allocate array: " + desc);
\r
1113 /** Are two objects equal? Arrays have the standard object equals
\r
1114 * method which only returns true if the two object are the same.
\r
1115 * This method returns true if every element of the arrays match.
\r
1116 * The inputs may be of any dimensionality. The dimensionality
\r
1117 * and dimensions of the arrays must match as well as any elements.
\r
1118 * If the elements are non-primitive. non-array objects, then the
\r
1119 * equals method is called for each element.
\r
1120 * If both elements are multi-dimensional arrays, then
\r
1121 * the method recurses.
\r
1123 public static boolean arrayEquals(Object x, Object y) {
\r
1124 return arrayEquals(x, y, 0, 0);
\r
1127 /** Are two objects equal? Arrays have the standard object equals
\r
1128 * method which only returns true if the two object are the same.
\r
1129 * This method returns true if every element of the arrays match.
\r
1130 * The inputs may be of any dimensionality. The dimensionality
\r
1131 * and dimensions of the arrays must match as well as any elements.
\r
1132 * If the elements are non-primitive. non-array objects, then the
\r
1133 * equals method is called for each element.
\r
1134 * If both elements are multi-dimensional arrays, then
\r
1135 * the method recurses.
\r
1137 public static boolean arrayEquals(Object x, Object y, double tolf, double told) {
\r
1139 // Handle the special cases first.
\r
1140 // We treat null == null so that two object arrays
\r
1141 // can match if they have matching null elements.
\r
1142 if (x == null && y == null) {
\r
1146 if (x == null || y == null) {
\r
1150 Class xClass = x.getClass();
\r
1151 Class yClass = y.getClass();
\r
1153 if (xClass != yClass) {
\r
1157 if (!xClass.isArray()) {
\r
1158 return x.equals(y);
\r
1161 if (xClass.equals(int[].class)) {
\r
1162 return Arrays.equals((int[]) x, (int[]) y);
\r
1164 } else if (xClass.equals(double[].class)) {
\r
1166 return Arrays.equals((double[]) x, (double[]) y);
\r
1168 return doubleArrayEquals((double[]) x, (double[]) y, told);
\r
1171 } else if (xClass.equals(long[].class)) {
\r
1172 return Arrays.equals((long[]) x, (long[]) y);
\r
1174 } else if (xClass.equals(float[].class)) {
\r
1176 return Arrays.equals((float[]) x, (float[]) y);
\r
1178 return floatArrayEquals((float[]) x, (float[]) y, (float) tolf);
\r
1181 } else if (xClass.equals(byte[].class)) {
\r
1182 return Arrays.equals((byte[]) x, (byte[]) y);
\r
1184 } else if (xClass.equals(short[].class)) {
\r
1185 return Arrays.equals((short[]) x, (short[]) y);
\r
1187 } else if (xClass.equals(char[].class)) {
\r
1188 return Arrays.equals((char[]) x, (char[]) y);
\r
1190 } else if (xClass.equals(boolean[].class)) {
\r
1191 return Arrays.equals((boolean[]) x, (boolean[]) y);
\r
1194 // Non-primitive and multidimensional arrays can be
\r
1195 // cast to Object[]
\r
1196 Object[] xo = (Object[]) x;
\r
1197 Object[] yo = (Object[]) y;
\r
1198 if (xo.length != yo.length) {
\r
1201 for (int i = 0; i < xo.length; i += 1) {
\r
1202 if (!arrayEquals(xo[i], yo[i], tolf, told)) {
\r
1213 /** Compare two double arrays using a given tolerance */
\r
1214 public static boolean doubleArrayEquals(double[] x, double[] y, double tol) {
\r
1216 for (int i = 0; i < x.length; i += 1) {
\r
1220 if (Math.abs((y[i] - x[i]) / x[i]) > tol) {
\r
1227 /** Compare two float arrays using a given tolerance */
\r
1228 public static boolean floatArrayEquals(float[] x, float[] y, float tol) {
\r
1230 for (int i = 0; i < x.length; i += 1) {
\r
1234 if (Math.abs((y[i] - x[i]) / x[i]) > tol) {
\r
1241 /** Dump an array on the given print steam */
\r
1242 public static void dumpArray(java.io.PrintStream p, Object arr) {
\r
1243 // Get the dimensionality and then dump.
\r
1244 if (arr == null) {
\r
1247 Class nm = arr.getClass();
\r
1248 if (nm.isArray()) {
\r
1250 for (int i = 0; i < java.lang.reflect.Array.getLength(arr); i += 1) {
\r
1251 dumpArray(p, java.lang.reflect.Array.get(arr, i));
\r
1255 p.print(" " + arr.toString() + " ");
\r