blob: aded0ac49fca53a62fc301ee4e2b2ce160c0e837 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.internal.util;
import java.util.Arrays;
import com.gemstone.gemfire.internal.lang.StringUtils;
import com.gemstone.gemfire.internal.offheap.annotations.Unretained;
/**
* @author John Blum
* @author jpenney
*
* Handle some simple editing of fixed-length arrays.
*
* TODO use Java 1.5 template classes to simplify this interface
*
*/
public abstract class ArrayUtils {
/**
* Gets the element at index in the array in a bound-safe manner. If index is not a valid index in the given array,
* then the default value is returned.
* <p/>
* @param <T> the class type of the elements in the array.
* @param array the array from which the element at index is retrieved.
* @param index the index into the array to retrieve the element.
* @param defaultValue the default value of element type to return in the event that the array index is invalid.
* @return the element at index from the array or the default value if the index is invalid.
*/
public static <T> T getElementAtIndex(T[] array, int index, T defaultValue) {
try {
return array[index];
}
catch (ArrayIndexOutOfBoundsException ignore) {
return defaultValue;
}
}
/**
* Gets the first element from the given array or null if the array reference is null or the array length is 0.
* <p/>
* @param <T> the Class type of the elements in the array.
* @param array the array of elements from which to retrieve the first element.
* @return the first element from the array or null if either the array reference is null or the array length is 0.
*/
public static <T> T getFirst(final T... array) {
return (array != null && array.length > 0 ? array[0] : null);
}
/**
* Converts the specified Object array into a String representation.
* <p/>
* @param array the Object array of elements to convert to a String.
* @return a String representation of the Object array.
* @see java.lang.StringBuilder
*/
public static String toString(final Object... array) {
final StringBuilder buffer = new StringBuilder("[");
int count = 0;
if (array != null) {
for (final Object element : array) {
buffer.append(count++ > 0 ? ", " : StringUtils.EMPTY_STRING).append(element);
}
}
buffer.append("]");
return buffer.toString();
}
public static String toString(final String... array) {
return toString((Object[])array);
}
/**
* Insert an element into an array. The element is inserted at the
* given position, all elements afterwards are moved to the right.
*
* @param originalArray array to insert into
* @param pos position at which to insert the element
* @param element element to add
* @return the new array
*/
public static Object[] insert(Object[] originalArray, int pos, Object element) {
Object[] newArray = (Object[]) java.lang.reflect.Array.newInstance(
originalArray.getClass().getComponentType(), originalArray.length + 1);
// Test Cases (proof of correctness by examining corner cases)
// 1) A B C D insert at 0: expect X A B C D
// 2) A B C D insert at 2: expect A B X C D
// 3) A B C D insert at 4: expect A B C D X
// copy everything before the given position
if (pos > 0) {
System.arraycopy(originalArray, 0, newArray, 0, pos); // does not copy originalArray[pos], where we insert
}
// 1) A B C D insert at 0: no change, ". . . . ."
// 2) A B C D insert at 2: copy "A B", "A B . . ."
// 3) A B C D insert at 4: copy "A B C D", "A B C D ."
// insert
newArray[pos] = element;
// 1) A B C D insert at 0: "X . . . ."
// 2) A B C D insert at 2: "A B X . ."
// 3) A B C D insert at 4: "A B C D X" (all done)
// copy remaining elements
if (pos < originalArray.length) {
System.arraycopy(originalArray, pos, // originalArray[pos] first element copied
newArray, pos + 1, // newArray[pos + 1] first destination
originalArray.length - pos); // number of elements left
}
// 1) A B C D insert at 0: "A B C D" copied at 1: "X A B C D"
// 2) A B C D insert at 2: "C D" copied at 3: "A B X C D"
// 3) A B C D insert at 4: no change
return newArray;
}
/**
* Remove element from an array. The element is removed at the
* specified position, and all remaining elements are moved to the left.
*
* @param originalArray array to remove from
* @param pos position to remove
* @return the new array
*/
public static Object[] remove(Object[] originalArray, int pos) {
Object[] newArray = (Object[])java.lang.reflect.Array.newInstance(
originalArray.getClass().getComponentType(), originalArray.length - 1);
// Test cases: (proof of correctness)
// 1) A B C D E remove 0: expect "B C D E"
// 2) A B C D E remove 2: expect "A B D E"
// 3) A B C D E remove 4: expect "A B C D"
// Copy everything before
if (pos > 0) {
System.arraycopy(originalArray, 0, newArray, 0, pos); // originalArray[pos - 1] is last element copied
}
// 1) A B C D E remove 0: no change, ". . . ."
// 2) A B C D E remove 2: "A B" copied at beginning: "A B . ."
// 3) A B C D E remove 4: "A B C D" copied (all done)
// Copy everything after
if (pos < originalArray.length - 1) {
System.arraycopy(originalArray, pos + 1, // originalArray[pos + 1] is first element copied
newArray, pos, // first position to copy into
originalArray.length - 1 - pos);
}
// 1) A B C D E remove 0: "B C D E" copied into to position 0
// 2) A B C D E remove 2: "D E" copied into position 2: "A B D E"
// 3) A B C D E remove 4: no change
return newArray;
}
public static String objectRefString(Object obj) {
return obj != null ? obj.getClass().getSimpleName() + '@'
+ Integer.toHexString(System.identityHashCode(obj)) : "(null)";
}
public static void objectRefString(Object obj, StringBuilder sb) {
if (obj != null) {
sb.append(obj.getClass().getSimpleName()).append('@')
.append(Integer.toHexString(System.identityHashCode(obj)));
}
else {
sb.append("(null)");
}
}
/** Get proper string for an object including arrays. */
public static String objectString(Object obj) {
StringBuilder sb = new StringBuilder();
objectString(obj, sb);
return sb.toString();
}
/** Get proper string for an object including arrays. */
public static void objectString(Object obj, StringBuilder sb) {
if (obj instanceof Object[]) {
sb.append('(');
boolean first = true;
for (Object o : (Object[])obj) {
if (!first) {
sb.append(',');
}
else {
first = false;
}
objectString(o, sb);
}
sb.append(')');
}
else {
objectStringWithBytes(obj, sb);
}
}
/**
* Get proper string for an an object including arrays with upto one dimension
* of arrays.
*/
public static String objectStringNonRecursive(@Unretained Object obj) {
StringBuilder sb = new StringBuilder();
objectStringNonRecursive(obj, sb);
return sb.toString();
}
public static boolean areByteArrayArrayEquals(byte[][] v1, byte[][] v2) {
boolean areEqual = false;
if (v1.length == v2.length) {
areEqual = true;
for (int index = 0; index < v1.length; ++index) {
if (!Arrays.equals(v1[index], v2[index])) {
areEqual = false;
break;
}
}
}
return areEqual;
}
/**
* Get proper string for an an object including arrays with upto one dimension
* of arrays.
*/
public static void objectStringNonRecursive(@Unretained Object obj, StringBuilder sb) {
if (obj instanceof Object[]) {
sb.append('(');
boolean first = true;
for (Object o : (Object[])obj) {
if (!first) {
sb.append(',');
sb.append(o);
}
else {
first = false;
// for SQLFire show the first byte[] for byte[][] storage
objectStringWithBytes(o, sb);
}
}
sb.append(')');
}
else {
objectStringWithBytes(obj, sb);
}
}
private static void objectStringWithBytes(@Unretained Object obj, StringBuilder sb) {
if (obj instanceof byte[]) {
sb.append('(');
boolean first = true;
final byte[] bytes = (byte[])obj;
int numBytes = 0;
for (byte b : bytes) {
if (!first) {
sb.append(',');
}
else {
first = false;
}
sb.append(b);
// terminate with ... for large number of bytes
if (numBytes++ >= 5000 && numBytes < bytes.length) {
sb.append(" ...");
break;
}
}
sb.append(')');
}
else {
sb.append(obj);
}
}
/**
* Check if two objects, possibly null, are equal. Doesn't really belong to
* this class...
*/
public static boolean objectEquals(Object o1, Object o2) {
if (o1 == o2) {
return true;
}
if (o1 == null) {
return false;
}
return o1.equals(o2);
}
/**
* Converts the primitive int array into an Integer wrapper object array.
* </p>
* @param array the primitive int array to convert into an Integer wrapper object array.
* @return an Integer array containing the values from the elements in the primitive int array.
*/
public static Integer[] toIntegerArray(final int[] array) {
final Integer[] integerArray = new Integer[array == null ? 0 : array.length];
if (array != null) {
for (int index = 0; index < array.length; index++) {
integerArray[index] = array[index];
}
}
return integerArray;
}
/**
* Converts a double byte array into a double Byte array.
*
* @param array the double byte array to convert into double Byte array
* @return a double array of Byte objects containing values from the double byte array
*/
public static Byte[][] toByteArray(final byte[][] array) {
if (array == null) {
return null;
}
final Byte[][] byteArray = new Byte[array.length][];
for (int i = 0; i < array.length; i++) {
byteArray[i] = new Byte[array[i].length];
for (int j = 0; j < array[i].length; j++) {
byteArray[i][j] = array[i][j];
}
}
return byteArray;
}
/**
* Converts a double Byte array into a double byte array.
*
* @param byteArray the double Byte array to convert into a double byte array
* @return a double byte array containing byte values from the double Byte array
*/
public static byte[][] toBytes(final Byte[][] byteArray) {
if (byteArray == null) {
return null;
}
final byte[][] array = new byte[byteArray.length][];
for (int i = 0; i < byteArray.length; i++) {
array[i] = new byte[byteArray[i].length];
for (int j = 0; j < byteArray[i].length; j++) {
array[i][j] = byteArray[i][j];
}
}
return array;
}
}