1 /* 2 * $Id$ 3 * 4 * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 package com.sun.javatest.util; 28 29 import java.lang.reflect.Array; 30 31 /** 32 * A class that manipulates arrays of Objects (no primitives). 33 * Currently, you can remove any element and have the array shrink itself, 34 * and you can append an element and have it expand. 35 * <em>Note: You should either initialize array variables to a zero length array 36 * or use the append method that accepts the Class argument to prevent array 37 * storage exceptions. This is an issue when this class is forced to create a 38 * new array of unknown type and determine the type from the item being appended.</em> 39 */ 40 41 public final class DynamicArray { 42 /** 43 * Append an object to the end of the array. 44 * 45 * @param oldArr The original array which we are appending to. May be zero length or null. 46 * @param newObj The new value to append to the oldArr. Null is not a legal value. 47 * @return A new array with the object appended to it. 48 * @throws IllegalArgumentException If newObj is null. 49 * @throws ArrayStoreException If there is a type mismatch between oldArr and newObj. 50 */ 51 public static <T> T[] append(T[] oldArr, T newObj) { 52 T[] newArr; 53 54 if (oldArr == null) { 55 if (newObj != null) { 56 newArr = (T[])(Array.newInstance(newObj.getClass(), 1)); 57 newArr[0] = newObj; 58 } 59 else { 60 throw new IllegalArgumentException("Cannot add null item to null array."); 61 } 62 } 63 else { 64 newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length+1)); 65 System.arraycopy(oldArr, 0, newArr, 0, oldArr.length); 66 newArr[newArr.length-1] = newObj; 67 } 68 69 return newArr; 70 } 71 72 /** 73 * Append an object to the end of the array. 74 * 75 * @param oldArr The original array which we are appending to. May be zero length or null. 76 * @param newObj The new value to append to the oldArr. 77 * @param arrayClass If the oldArr is null, a new array of arrayClass will be created. 78 * If arrayClass is null, the type of newObj will be used to create the array. 79 * @return A new array with the object appended to it. 80 * @throws IllegalArgumentException If newObj is null. 81 * @throws ArrayStoreException If there is a type mismatch between oldArr and newObj. 82 */ 83 public static <T> T[] append(T[] oldArr, T newObj, Class<? extends T> arrayClass) { 84 T[] localArr; 85 86 if (oldArr == null && arrayClass != null) 87 localArr = (T[])(Array.newInstance(arrayClass, 0)); 88 else 89 localArr = oldArr; 90 91 return append(localArr, newObj); 92 } 93 94 /** 95 * Join two arrays. 96 * @param array1 The first array to be joined. 97 * @param array2 The second array to be joined. 98 * @return If either argument is null, the result is the other argument; 99 * otherwise, the result is a new array, whose element type is taken from 100 * the first array, containing the elements of the first array, followed 101 * by the elements of the second array. 102 */ 103 public static <T> T[] join(T[] array1, T[] array2) { 104 if (array1 == null) 105 return array2; 106 107 if (array2 == null) 108 return array1; 109 110 Class type = array1.getClass().getComponentType(); 111 int size = array1.length + array2.length; 112 T[] newArray = (T[]) Array.newInstance(type, size); 113 System.arraycopy(array1, 0, newArray, 0, array1.length); 114 System.arraycopy(array2, 0, newArray, array1.length, array2.length); 115 return newArray; 116 } 117 118 /** 119 * Insert an object into the array at the specified index. 120 * 121 * @param oldArr The array to insert into. May be null, in which case a new array 122 * will be created using the type of <code>newObj</code>. 123 * @param newObj The object to insert. 124 * @param location The index at which to insert the item. An exception will occur 125 * if the location in out of range. This location can be equal to 126 * <code>oldArr.length</code>, in which case this becomes an append 127 * operation. 128 * @return A new array with the object inserted into it at the specified location. 129 */ 130 public static <T> T[] insert(T[] oldArr, T newObj, int location) { 131 T[] newArr; 132 133 if (oldArr == null) { 134 if (newObj != null) { 135 newArr = (T[])(Array.newInstance(newObj.getClass(), 1)); 136 newArr[0] = newObj; 137 } 138 else { 139 throw new IllegalArgumentException("Cannot add null item to null array."); 140 } 141 } 142 else { 143 if (location > oldArr.length) 144 throw new IllegalArgumentException("Index location too large (" + location + 145 ")."); 146 newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length+1)); 147 148 if (location == 0) { 149 newArr[0] = newObj; 150 System.arraycopy(oldArr, 0, newArr, 1, oldArr.length); 151 } else { 152 System.arraycopy(oldArr, 0, newArr, 0, location); 153 newArr[location] = newObj; 154 System.arraycopy(oldArr, location, newArr, location + 1, 155 oldArr.length - location); 156 } 157 } 158 159 return newArr; 160 } 161 162 /** 163 * Remove the object at the specified index. 164 * The new array type is determined by the type of element 0 in the 165 * original array. 166 * 167 * @param oldArr The original array which we are removing from. May not be 168 * null or zero length. 169 * @param index The index to remove from <code>oldArr</code>. Exception 170 * will be thrown if it is out of range. 171 * @return An array of the same type as the original array (element 0), without the 172 * given index. Zero length array if the last element is removed. 173 * @exception IllegalArgumentException Will occur if the given index is out of range, 174 * or the given array is null. 175 * @exception NullPointerException May occur if the source array has null 176 * values, particularly in the first array position. 177 * @exception ArrayStoreException May occur if all the objects in the 178 * array do not match. 179 */ 180 public static <T> T[] remove(T[] oldArr, int index) { 181 T[] newArr; 182 183 if (oldArr == null) 184 throw new IllegalArgumentException("Cannot remove from null array."); 185 else if (index > oldArr.length-1 || index < 0) { 186 // invalid index 187 throw new IllegalArgumentException("Index to remove from array is invalid (too small/large)."); 188 } 189 else if (index == 0) { 190 // chop the head 191 newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length-1)); 192 System.arraycopy(oldArr, 1, newArr, 0, oldArr.length-1); 193 } 194 else if (index == oldArr.length-1) { 195 // chop the tail 196 newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length-1)); 197 System.arraycopy(oldArr, 0, newArr, 0, oldArr.length-1); 198 } 199 else { 200 // chop the middle 201 newArr = (T[])(Array.newInstance(getArrayClass(oldArr), oldArr.length-1)); 202 System.arraycopy(oldArr, 0, newArr, 0, index); 203 System.arraycopy(oldArr, index+1, newArr, index, 204 oldArr.length-index-1); 205 } 206 207 return newArr; 208 } 209 210 /** 211 * Remove the object from the array. 212 * If the object is not found, the original array is returned unchanged. 213 * The first instance of the target is removed. 214 * 215 * @param oldArr The array to remove from. 216 * @param victim The object to remove from the array. May be null. 217 * @return Zero length array if the last element is removed. 218 */ 219 public static <T> T[] remove(T[] oldArr, T victim) { 220 T[] newArr; 221 222 if (oldArr == null) { 223 newArr = oldArr; 224 } else { 225 int location = find(oldArr, victim); 226 if(location != -1) { 227 newArr = remove(oldArr, location); 228 } else { 229 // not found, return the original array 230 newArr = oldArr; 231 } 232 } 233 234 return newArr; 235 } 236 237 /** 238 * Find the first index of the object that is equal (reference) to the 239 * target. 240 * 241 * @param arr The data to search; should not be null. 242 * @param target The reference to search for; can be null. 243 * @return The array index of the target. 244 */ 245 public static <T> int find(T[] arr, T target) { 246 int index = -1; 247 248 for(int i = 0; i < arr.length; i++) { 249 if(arr[i] == target) { 250 index = i; 251 break; 252 } 253 } 254 255 return index; 256 } 257 258 /** 259 * Get the type of objects that the array is declared to hold. 260 * 261 * @param arr The array to examine. 262 * @return The class of objects that the given array can hold. 263 */ 264 protected static Class getArrayClass(Object[] arr) { 265 if(arr != null) { 266 return arr.getClass().getComponentType(); 267 } else { 268 return null; 269 } 270 } 271 272 } 273