/*
* $Id$
*
* Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.javatest.util;
import java.lang.reflect.Array;
/**
* A class that manipulates arrays of Objects (no primitives).
* Currently, you can remove any element and have the array shrink itself,
* and you can append an element and have it expand.
* Note: You should either initialize array variables to a zero length array
* or use the append method that accepts the Class argument to prevent array
* storage exceptions. This is an issue when this class is forced to create a
* new array of unknown type and determine the type from the item being appended.
*/
public final class DynamicArray {
/**
* Append an object to the end of the array.
*
* @param oldArr The original array which we are appending to. May be zero length or null.
* @param newObj The new value to append to the oldArr. Null is not a legal value.
* @return A new array with the object appended to it.
* @throws IllegalArgumentException If newObj is null.
* @throws ArrayStoreException If there is a type mismatch between oldArr and newObj.
*/
public static T[] append(T[] oldArr, T newObj) {
T[] newArr;
if (oldArr == null) {
if (newObj != null) {
newArr = (T[])(Array.newInstance(newObj.getClass(), 1));
newArr[0] = newObj;
}
else {
throw new IllegalArgumentException("Cannot add null item to null array.");
}
}
else {
newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length+1));
System.arraycopy(oldArr, 0, newArr, 0, oldArr.length);
newArr[newArr.length-1] = newObj;
}
return newArr;
}
/**
* Append an object to the end of the array.
*
* @param oldArr The original array which we are appending to. May be zero length or null.
* @param newObj The new value to append to the oldArr.
* @param arrayClass If the oldArr is null, a new array of arrayClass will be created.
* If arrayClass is null, the type of newObj will be used to create the array.
* @return A new array with the object appended to it.
* @throws IllegalArgumentException If newObj is null.
* @throws ArrayStoreException If there is a type mismatch between oldArr and newObj.
*/
public static T[] append(T[] oldArr, T newObj, Class extends T> arrayClass) {
T[] localArr;
if (oldArr == null && arrayClass != null)
localArr = (T[])(Array.newInstance(arrayClass, 0));
else
localArr = oldArr;
return append(localArr, newObj);
}
/**
* Join two arrays.
* @param array1 The first array to be joined.
* @param array2 The second array to be joined.
* @return If either argument is null, the result is the other argument;
* otherwise, the result is a new array, whose element type is taken from
* the first array, containing the elements of the first array, followed
* by the elements of the second array.
*/
public static T[] join(T[] array1, T[] array2) {
if (array1 == null)
return array2;
if (array2 == null)
return array1;
Class> type = array1.getClass().getComponentType();
int size = array1.length + array2.length;
T[] newArray = (T[]) Array.newInstance(type, size);
System.arraycopy(array1, 0, newArray, 0, array1.length);
System.arraycopy(array2, 0, newArray, array1.length, array2.length);
return newArray;
}
/**
* Insert an object into the array at the specified index.
*
* @param oldArr The array to insert into. May be null, in which case a new array
* will be created using the type of newObj
.
* @param newObj The object to insert.
* @param location The index at which to insert the item. An exception will occur
* if the location in out of range. This location can be equal to
* oldArr.length
, in which case this becomes an append
* operation.
* @return A new array with the object inserted into it at the specified location.
*/
public static T[] insert(T[] oldArr, T newObj, int location) {
T[] newArr;
if (oldArr == null) {
if (newObj != null) {
newArr = (T[])(Array.newInstance(newObj.getClass(), 1));
newArr[0] = newObj;
}
else {
throw new IllegalArgumentException("Cannot add null item to null array.");
}
}
else {
if (location > oldArr.length)
throw new IllegalArgumentException("Index location too large (" + location +
").");
newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length+1));
if (location == 0) {
newArr[0] = newObj;
System.arraycopy(oldArr, 0, newArr, 1, oldArr.length);
} else {
System.arraycopy(oldArr, 0, newArr, 0, location);
newArr[location] = newObj;
System.arraycopy(oldArr, location, newArr, location + 1,
oldArr.length - location);
}
}
return newArr;
}
/**
* Remove the object at the specified index.
* The new array type is determined by the type of element 0 in the
* original array.
*
* @param oldArr The original array which we are removing from. May not be
* null or zero length.
* @param index The index to remove from oldArr
. Exception
* will be thrown if it is out of range.
* @return An array of the same type as the original array (element 0), without the
* given index. Zero length array if the last element is removed.
* @exception IllegalArgumentException Will occur if the given index is out of range,
* or the given array is null.
* @exception NullPointerException May occur if the source array has null
* values, particularly in the first array position.
* @exception ArrayStoreException May occur if all the objects in the
* array do not match.
*/
public static T[] remove(T[] oldArr, int index) {
T[] newArr;
if (oldArr == null)
throw new IllegalArgumentException("Cannot remove from null array.");
else if (index > oldArr.length-1 || index < 0) {
// invalid index
throw new IllegalArgumentException("Index to remove from array is invalid (too small/large).");
}
else if (index == 0) {
// chop the head
newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length-1));
System.arraycopy(oldArr, 1, newArr, 0, oldArr.length-1);
}
else if (index == oldArr.length-1) {
// chop the tail
newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length-1));
System.arraycopy(oldArr, 0, newArr, 0, oldArr.length-1);
}
else {
// chop the middle
newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length-1));
System.arraycopy(oldArr, 0, newArr, 0, index);
System.arraycopy(oldArr, index+1, newArr, index,
oldArr.length-index-1);
}
return newArr;
}
/**
* Remove the object from the array.
* If the object is not found, the original array is returned unchanged.
* The first instance of the target is removed.
*
* @param oldArr The array to remove from.
* @param victim The object to remove from the array. May be null.
* @return Zero length array if the last element is removed.
*/
public static T[] remove(T[] oldArr, T victim) {
T[] newArr;
if (oldArr == null) {
newArr = oldArr;
} else {
int location = find(oldArr, victim);
if(location != -1) {
newArr = remove(oldArr, location);
} else {
// not found, return the original array
newArr = oldArr;
}
}
return newArr;
}
/**
* Find the first index of the object that is equal (reference) to the
* target.
*
* @param arr The data to search; should not be null.
* @param target The reference to search for; can be null.
* @return The array index of the target.
*/
public static int find(T[] arr, T target) {
int index = -1;
for(int i = 0; i < arr.length; i++) {
if(arr[i] == target) {
index = i;
break;
}
}
return index;
}
/**
* Get the type of objects that the array is declared to hold.
*
* @param arr The array to examine.
* @return The class of objects that the given array can hold.
*/
protected static Class> getArrayClass(Object[] arr) {
if(arr != null) {
return arr.getClass().getComponentType();
} else {
return null;
}
}
}