/* ArraysX.java Purpose: Description: History: 2001/11/13, Henri Chen: Created. Copyright (C) 2001 Potix Corporation. All Rights Reserved. {{IS_RIGHT This program is distributed under LGPL Version 2.1 in the hope that it will be useful, but WITHOUT ANY WARRANTY. }}IS_RIGHT */ package org.zkoss.util; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Utilities for handling arrays. * * @author henrichen */ public class ArraysX { /** Converts an array to a readable string (for debugging purpose). */ public final static String toString(Object[] array) { if (array == null) return "null"; StringBuffer sb = new StringBuffer(128).append('['); for (int j = 0; j < array.length; ++j) { if (array[j] == array) sb.append("(this array)"); else sb.append(array[j]); if (j != array.length - 1) sb.append(", "); } return sb.append(']').toString(); } /** Converts an array of int to a readable string (for debugging purpose). */ public final static String toString(int[] array) { if (array == null) return "null"; StringBuffer sb = new StringBuffer(128).append('['); for (int j = 0; j < array.length; ++j) { sb.append(array[j]); if (j != array.length - 1) sb.append(", "); } return sb.append(']').toString(); } /** Converts an array of long to a readable string (for debugging purpose). */ public final static String toString(long[] array) { if (array == null) return "null"; StringBuffer sb = new StringBuffer(128).append('['); for (int j = 0; j < array.length; ++j) { sb.append(array[j]); if (j != array.length - 1) sb.append(", "); } return sb.append(']').toString(); } /** Converts an array of short to a readable string (for debugging purpose). */ public final static String toString(short[] array) { if (array == null) return "null"; StringBuffer sb = new StringBuffer(128).append('['); for (int j = 0; j < array.length; ++j) { sb.append(array[j]); if (j != array.length - 1) sb.append(", "); } return sb.append(']').toString(); } /** Converts an array of byte to a readable string (for debugging purpose). */ public final static String toString(byte[] array) { if (array == null) return "null"; StringBuffer sb = new StringBuffer(128).append('['); for (int j = 0; j < array.length; ++j) { sb.append(array[j]); if (j != array.length - 1) sb.append(", "); } return sb.append(']').toString(); } /** Converts an array of char to a readable string (for debugging purpose). */ public final static String toString(char[] array) { if (array == null) return "null"; StringBuffer sb = new StringBuffer(128).append('['); for (int j = 0; j < array.length; ++j) { sb.append(array[j]); if (j != array.length - 1) sb.append(", "); } return sb.append(']').toString(); } /** Converts an array of boolean to a readable string (for debugging purpose). */ public final static String toString(boolean[] array) { if (array == null) return "null"; StringBuffer sb = new StringBuffer(128).append('['); for (int j = 0; j < array.length; ++j) { sb.append(array[j]); if (j != array.length - 1) sb.append(", "); } return sb.append(']').toString(); } /** Converts an array of float to a readable string (for debugging purpose). */ public final static String toString(float[] array) { if (array == null) return "null"; StringBuffer sb = new StringBuffer(128).append('['); for (int j = 0; j < array.length; ++j) { sb.append(array[j]); if (j != array.length - 1) sb.append(", "); } return sb.append(']').toString(); } /** Converts an array of char to a readable string (for debugging purpose). */ public final static String toString(double[] array) { if (array == null) return "null"; StringBuffer sb = new StringBuffer(128).append('['); for (int j = 0; j < array.length; ++j) { sb.append(array[j]); if (j != array.length - 1) sb.append(", "); } return sb.append(']').toString(); } /** * Returns the hex String representation of a byte array without prefix 0x. * The String is formed by making value[0] the leftmost two digits and * value[value.length-1] the rightmost two digits. * * @param array the byte array */ public final static String toHexString(byte[] array) { StringBuffer sb = new StringBuffer(array.length*2 + 8); char ch; for (int i=0; i< array.length; i++) { // byte will be promote to integer first, mask with 0x0f is a must. ch = Character.forDigit(array[i] >>> 4 & 0x0f, 16); sb.append(ch); ch = Character.forDigit(array[i] & 0x0f, 16); sb.append(ch); } return sb.toString(); } /** * Returns the octal String representation of a byte array with optional * prefix. The String is formed by making value[0] the leftmost three digits * and value[value.length-1] the rightmost three digits. * * @param array the byte array */ public final static String toOctalString(byte[] array, String prefix) { StringBuffer sb = new StringBuffer(array.length* (3 + (prefix == null ? 0 : prefix.length())) + 8); if (prefix == null) { for (int i=0; i< array.length; i++) { appendOctalDigits(sb, array[i]); } } else { for (int i=0; i< array.length; i++) { sb.append(prefix); appendOctalDigits(sb, array[i]); } } return sb.toString(); } /** * Returns the octal digit String buffer representation of a byte. * @param byte the byte */ private final static StringBuffer appendOctalDigits(StringBuffer sb, byte b) { // b will be promote to integer first, mask with 0x07 is a must. return sb.append(Character.forDigit(b >>> 6 & 0x07, 8)) .append(Character.forDigit(b >>> 3 & 0x07, 8)) .append(Character.forDigit(b & 0x07, 8)); } /** * Duplicates the specified array. * * <p>The array could be an array of objects or primitives. * * @param ary the array * @param jb the beginning index (included) * @param je the ending index (excluded) * @return an array duplicated from ary * @exception IllegalArgumentException if ary is not any array * @exception IndexOutOfBoundsException if out of bounds */ public static final Object duplicate(Object ary, int jb, int je) { int len = Array.getLength(ary); if (jb<0 || je>len || jb>je) throw new IndexOutOfBoundsException(jb + " or " + je + " exceeds " + len); len = je - jb; Object dst = Array.newInstance(ary.getClass().getComponentType(), len); System.arraycopy(ary, jb, dst, 0, len); return dst; } /** * Duplicates the specified generic array. * * <p>The array could be an array of objects or primitives. * * @param ary the array * @param jb the beginning index (included) * @param je the ending index (excluded) * @return an array duplicated from ary * @exception IllegalArgumentException if ary is not any array * @exception IndexOutOfBoundsException if out of bounds * @since 6.0.0 */ @SuppressWarnings("unchecked") public static final <T> T[] duplicate(T[] ary, int jb, int je) { return (T[])duplicate((Object)ary, jb, je); } /** * Duplicates the specified array. * @param ary the array * @return an array duplicated from ary * @exception IllegalArgumentException if ary is not any array * @exception IndexOutOfBoundsException if out of bounds */ public static final Object duplicate(Object ary) { return duplicate(ary, 0, Array.getLength(ary)); } /** * Duplicates the specified generic array. * @param ary the array * @return an array duplicated from ary * @exception IllegalArgumentException if ary is not any array * @exception IndexOutOfBoundsException if out of bounds * @since 6.0.0 */ public static final <T> T[] duplicate(T[] ary) { return duplicate(ary, 0, ary.length); } /** * Concatenates the two specified array. * * <p>The array could be an array of objects or primitives. * * @param ary the array * @param ary1 the array * @return an array concatenating the ary and ary1 * @exception IllegalArgumentException if ary and ary1 component types are not compatible */ public static final Object concat(Object ary, Object ary1) { int len = Array.getLength(ary) + Array.getLength(ary1); if (!ary.getClass().getComponentType().isAssignableFrom(ary1.getClass().getComponentType())) throw new IllegalArgumentException("These concated array component types are not compatible."); Object dst = Array.newInstance(ary.getClass().getComponentType(), len); System.arraycopy(ary, 0, dst, 0, Array.getLength(ary)); System.arraycopy(ary1, 0, dst, Array.getLength(ary), Array.getLength(ary1)); return dst; } /** * Concatenates the two specified generic array. * * <p>The array could be an array of objects or primitives. * * @param ary the array * @param ary1 the array * @return an array concatenating the ary and ary1 * @exception IllegalArgumentException if ary and ary1 component types are not compatible * @since 6.0.0 */ @SuppressWarnings("unchecked") public static final <T> T[] concat(T[] ary, T[] ary1) { return (T[])concat((Object)ary, (Object)ary1); } /** * Shrink the specified array. It is similar to duplicate, except * it returns the previous instance if je==length && jb==0. * * @param ary the array * @param jb the beginning index (included) * @param je the ending index (excluded) * @return ary or an array duplicated from ary * @exception IllegalArgumentException if ary is not any array * @exception IndexOutOfBoundsException if out of bounds */ public static final Object shrink(Object ary, int jb, int je) { if (jb == 0 && je == Array.getLength(ary)) return ary; //nothing changed return duplicate(ary, jb, je); } /** * Shrink the specified array. It is similar to duplicate, except * it returns the previous instance if je==length && jb==0. * * @param ary the array * @param jb the beginning index (included) * @param je the ending index (excluded) * @return ary or an array duplicated from ary * @exception IllegalArgumentException if ary is not any array * @exception IndexOutOfBoundsException if out of bounds * @since 6.0.0 */ @SuppressWarnings("unchecked") public static final <T> T[] shrink(T[] ary, int jb, int je) { return (T[])shrink((Object)ary, jb, je); } /** * Returns a mutable list. * <p> Never be null. * @param ary the data array * @return a list view of the specified array * @since 6.0.1 */ @SuppressWarnings("unchecked") public static final <T> List<T> asList(T[] ary) { if (ary == null) return Collections.EMPTY_LIST; List<T> list = new ArrayList<T>(ary.length); for (T t : ary) list.add(t); return list; } /** * Returns a two dimensional mutable list. * <p> Never be null. * @param ary the two dimensional data array * @return a two dimensional list view of the specified array * @since 6.0.1 * @see #asList(Object[]) */ @SuppressWarnings("unchecked") public static final <T> List<List<T>> asList(T[][] ary) { if (ary == null) return Collections.EMPTY_LIST; List<List<T>> list = new ArrayList<List<T>>(ary.length); for (T[] t : ary) list.add(asList(t)); return list; } /** * Resizes the specified array. Similar to {@link #shrink}, but * it can enlarge and it keeps elements from the first. */ public static final Object resize(Object ary, int size) { final int oldsz = Array.getLength(ary); if (oldsz == size) return ary; final Object dst = Array.newInstance(ary.getClass().getComponentType(), size); System.arraycopy(ary, 0, dst, 0, oldsz > size ? size: oldsz); return dst; } /** * Resizes the specified generic array. * @since 6.0.0 */ @SuppressWarnings("unchecked") public static final <T> T[] resize(T[] ary, int size) { return (T[])resize((Object)ary, size); } /** * @deprecated As of release 6.0.0, replaced with {@link #duplicate(Object)}. */ public static final Object clone(Object ary) { return duplicate(ary); } //meaningless to provide this method since the caller's casting to Class<T> causes //an warning. But, if we use Class<?>, a compiler error is generated (T cannot be //determined...) // @SuppressWarnings("unchecked") // public static final <T> T[] newInstance(Class<T> cls, int size) { // return (T[])Array.newInstance(cls, size); // } }