blob: 9160d267e4d49b39b0648c6b147e3021e87112d3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.internal.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.geode.internal.offheap.annotations.Unretained;
/**
*
* 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).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;
// 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;
}
/**
* Use this instead of Arrays.asList(T... array) when you need a modifiable List.
*
* Returns a modifiable list containing the elements of the specified array.
*
* <p>
* Example usage:
*
* <pre>
* List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
* stooges.remove("Curly");
* </pre>
*
* @param <T> the class of the objects in the array
* @param array the array of elements to be added to the list
* @return a list containing the elements of the specified array
*/
public static <T> List<T> asList(T... array) {
return new ArrayList<>(Arrays.asList(array));
}
}