1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4 // ------------------------------------------------------------------------ 5 // All rights reserved. This program and the accompanying materials 6 // are made available under the terms of the Eclipse Public License v1.0 7 // and Apache License v2.0 which accompanies this distribution. 8 // 9 // The Eclipse Public License is available at 10 // http://www.eclipse.org/legal/epl-v10.html 11 // 12 // The Apache License v2.0 is available at 13 // http://www.opensource.org/licenses/apache2.0.php 14 // 15 // You may elect to redistribute this code under either of these licenses. 16 // ======================================================================== 17 // 18 19 package org.eclipse.jetty.util; 20 21 import java.io.Serializable; 22 import java.lang.reflect.Array; 23 import java.util.ArrayList; 24 import java.util.Arrays; 25 import java.util.Collection; 26 import java.util.Collections; 27 import java.util.Iterator; 28 import java.util.List; 29 import java.util.ListIterator; 30 31 /* ------------------------------------------------------------ */ 32 /** Lazy List creation. 33 * A List helper class that attempts to avoid unnecessary List 34 * creation. If a method needs to create a List to return, but it is 35 * expected that this will either be empty or frequently contain a 36 * single item, then using LazyList will avoid additional object 37 * creations by using {@link Collections#EMPTY_LIST} or 38 * {@link Collections#singletonList(Object)} where possible. 39 * <p> 40 * LazyList works by passing an opaque representation of the list in 41 * and out of all the LazyList methods. This opaque object is either 42 * null for an empty list, an Object for a list with a single entry 43 * or an {@link ArrayList} for a list of items. 44 * 45 * <p><h4>Usage</h4> 46 * <pre> 47 * Object lazylist =null; 48 * while(loopCondition) 49 * { 50 * Object item = getItem(); 51 * if (item.isToBeAdded()) 52 * lazylist = LazyList.add(lazylist,item); 53 * } 54 * return LazyList.getList(lazylist); 55 * </pre> 56 * 57 * An ArrayList of default size is used as the initial LazyList. 58 * 59 * @see java.util.List 60 */ 61 public class LazyList 62 implements Cloneable, Serializable 63 { 64 private static final String[] __EMTPY_STRING_ARRAY = new String[0]; 65 66 /* ------------------------------------------------------------ */ LazyList()67 private LazyList() 68 {} 69 70 /* ------------------------------------------------------------ */ 71 /** Add an item to a LazyList 72 * @param list The list to add to or null if none yet created. 73 * @param item The item to add. 74 * @return The lazylist created or added to. 75 */ 76 @SuppressWarnings("unchecked") add(Object list, Object item)77 public static Object add(Object list, Object item) 78 { 79 if (list==null) 80 { 81 if (item instanceof List || item==null) 82 { 83 List<Object> l = new ArrayList<Object>(); 84 l.add(item); 85 return l; 86 } 87 88 return item; 89 } 90 91 if (list instanceof List) 92 { 93 ((List<Object>)list).add(item); 94 return list; 95 } 96 97 List<Object> l=new ArrayList<Object>(); 98 l.add(list); 99 l.add(item); 100 return l; 101 } 102 103 /* ------------------------------------------------------------ */ 104 /** Add an item to a LazyList 105 * @param list The list to add to or null if none yet created. 106 * @param index The index to add the item at. 107 * @param item The item to add. 108 * @return The lazylist created or added to. 109 */ 110 @SuppressWarnings("unchecked") add(Object list, int index, Object item)111 public static Object add(Object list, int index, Object item) 112 { 113 if (list==null) 114 { 115 if (index>0 || item instanceof List || item==null) 116 { 117 List<Object> l = new ArrayList<Object>(); 118 l.add(index,item); 119 return l; 120 } 121 return item; 122 } 123 124 if (list instanceof List) 125 { 126 ((List<Object>)list).add(index,item); 127 return list; 128 } 129 130 List<Object> l=new ArrayList<Object>(); 131 l.add(list); 132 l.add(index,item); 133 return l; 134 } 135 136 /* ------------------------------------------------------------ */ 137 /** Add the contents of a Collection to a LazyList 138 * @param list The list to add to or null if none yet created. 139 * @param collection The Collection whose contents should be added. 140 * @return The lazylist created or added to. 141 */ addCollection(Object list, Collection<?> collection)142 public static Object addCollection(Object list, Collection<?> collection) 143 { 144 Iterator<?> i=collection.iterator(); 145 while(i.hasNext()) 146 list=LazyList.add(list,i.next()); 147 return list; 148 } 149 150 /* ------------------------------------------------------------ */ 151 /** Add the contents of an array to a LazyList 152 * @param list The list to add to or null if none yet created. 153 * @param array The array whose contents should be added. 154 * @return The lazylist created or added to. 155 */ addArray(Object list, Object[] array)156 public static Object addArray(Object list, Object[] array) 157 { 158 for(int i=0;array!=null && i<array.length;i++) 159 list=LazyList.add(list,array[i]); 160 return list; 161 } 162 163 /* ------------------------------------------------------------ */ 164 /** Ensure the capacity of the underlying list. 165 * 166 */ ensureSize(Object list, int initialSize)167 public static Object ensureSize(Object list, int initialSize) 168 { 169 if (list==null) 170 return new ArrayList<Object>(initialSize); 171 if (list instanceof ArrayList) 172 { 173 ArrayList<?> ol=(ArrayList<?>)list; 174 if (ol.size()>initialSize) 175 return ol; 176 ArrayList<Object> nl = new ArrayList<Object>(initialSize); 177 nl.addAll(ol); 178 return nl; 179 } 180 List<Object> l= new ArrayList<Object>(initialSize); 181 l.add(list); 182 return l; 183 } 184 185 /* ------------------------------------------------------------ */ remove(Object list, Object o)186 public static Object remove(Object list, Object o) 187 { 188 if (list==null) 189 return null; 190 191 if (list instanceof List) 192 { 193 List<?> l = (List<?>)list; 194 l.remove(o); 195 if (l.size()==0) 196 return null; 197 return list; 198 } 199 200 if (list.equals(o)) 201 return null; 202 return list; 203 } 204 205 /* ------------------------------------------------------------ */ remove(Object list, int i)206 public static Object remove(Object list, int i) 207 { 208 if (list==null) 209 return null; 210 211 if (list instanceof List) 212 { 213 List<?> l = (List<?>)list; 214 l.remove(i); 215 if (l.size()==0) 216 return null; 217 return list; 218 } 219 220 if (i==0) 221 return null; 222 return list; 223 } 224 225 226 227 /* ------------------------------------------------------------ */ 228 /** Get the real List from a LazyList. 229 * 230 * @param list A LazyList returned from LazyList.add(Object) 231 * @return The List of added items, which may be an EMPTY_LIST 232 * or a SingletonList. 233 */ getList(Object list)234 public static<E> List<E> getList(Object list) 235 { 236 return getList(list,false); 237 } 238 239 240 /* ------------------------------------------------------------ */ 241 /** Get the real List from a LazyList. 242 * 243 * @param list A LazyList returned from LazyList.add(Object) or null 244 * @param nullForEmpty If true, null is returned instead of an 245 * empty list. 246 * @return The List of added items, which may be null, an EMPTY_LIST 247 * or a SingletonList. 248 */ 249 @SuppressWarnings("unchecked") getList(Object list, boolean nullForEmpty)250 public static<E> List<E> getList(Object list, boolean nullForEmpty) 251 { 252 if (list==null) 253 { 254 if (nullForEmpty) 255 return null; 256 return Collections.emptyList(); 257 } 258 if (list instanceof List) 259 return (List<E>)list; 260 261 return (List<E>)Collections.singletonList(list); 262 } 263 264 265 /* ------------------------------------------------------------ */ toStringArray(Object list)266 public static String[] toStringArray(Object list) 267 { 268 if (list==null) 269 return __EMTPY_STRING_ARRAY; 270 271 if (list instanceof List) 272 { 273 List<?> l = (List<?>)list; 274 String[] a = new String[l.size()]; 275 for (int i=l.size();i-->0;) 276 { 277 Object o=l.get(i); 278 if (o!=null) 279 a[i]=o.toString(); 280 } 281 return a; 282 } 283 284 return new String[] {list.toString()}; 285 } 286 287 /* ------------------------------------------------------------ */ 288 /** Convert a lazylist to an array 289 * @param list The list to convert 290 * @param clazz The class of the array, which may be a primitive type 291 * @return array of the lazylist entries passed in 292 */ toArray(Object list,Class<?> clazz)293 public static Object toArray(Object list,Class<?> clazz) 294 { 295 if (list==null) 296 return Array.newInstance(clazz,0); 297 298 if (list instanceof List) 299 { 300 List<?> l = (List<?>)list; 301 if (clazz.isPrimitive()) 302 { 303 Object a = Array.newInstance(clazz,l.size()); 304 for (int i=0;i<l.size();i++) 305 Array.set(a,i,l.get(i)); 306 return a; 307 } 308 return l.toArray((Object[])Array.newInstance(clazz,l.size())); 309 310 } 311 312 Object a = Array.newInstance(clazz,1); 313 Array.set(a,0,list); 314 return a; 315 } 316 317 /* ------------------------------------------------------------ */ 318 /** The size of a lazy List 319 * @param list A LazyList returned from LazyList.add(Object) or null 320 * @return the size of the list. 321 */ size(Object list)322 public static int size(Object list) 323 { 324 if (list==null) 325 return 0; 326 if (list instanceof List) 327 return ((List<?>)list).size(); 328 return 1; 329 } 330 331 /* ------------------------------------------------------------ */ 332 /** Get item from the list 333 * @param list A LazyList returned from LazyList.add(Object) or null 334 * @param i int index 335 * @return the item from the list. 336 */ 337 @SuppressWarnings("unchecked") get(Object list, int i)338 public static <E> E get(Object list, int i) 339 { 340 if (list==null) 341 throw new IndexOutOfBoundsException(); 342 343 if (list instanceof List) 344 return (E)((List<?>)list).get(i); 345 346 if (i==0) 347 return (E)list; 348 349 throw new IndexOutOfBoundsException(); 350 } 351 352 /* ------------------------------------------------------------ */ contains(Object list,Object item)353 public static boolean contains(Object list,Object item) 354 { 355 if (list==null) 356 return false; 357 358 if (list instanceof List) 359 return ((List<?>)list).contains(item); 360 361 return list.equals(item); 362 } 363 364 365 /* ------------------------------------------------------------ */ clone(Object list)366 public static Object clone(Object list) 367 { 368 if (list==null) 369 return null; 370 if (list instanceof List) 371 return new ArrayList<Object>((List<?>)list); 372 return list; 373 } 374 375 /* ------------------------------------------------------------ */ toString(Object list)376 public static String toString(Object list) 377 { 378 if (list==null) 379 return "[]"; 380 if (list instanceof List) 381 return list.toString(); 382 return "["+list+"]"; 383 } 384 385 /* ------------------------------------------------------------ */ 386 @SuppressWarnings("unchecked") iterator(Object list)387 public static<E> Iterator<E> iterator(Object list) 388 { 389 if (list==null) 390 { 391 List<E> empty=Collections.emptyList(); 392 return empty.iterator(); 393 } 394 if (list instanceof List) 395 { 396 return ((List<E>)list).iterator(); 397 } 398 List<E> l=getList(list); 399 return l.iterator(); 400 } 401 402 /* ------------------------------------------------------------ */ 403 @SuppressWarnings("unchecked") listIterator(Object list)404 public static<E> ListIterator<E> listIterator(Object list) 405 { 406 if (list==null) 407 { 408 List<E> empty=Collections.emptyList(); 409 return empty.listIterator(); 410 } 411 if (list instanceof List) 412 return ((List<E>)list).listIterator(); 413 414 List<E> l=getList(list); 415 return l.listIterator(); 416 } 417 418 /* ------------------------------------------------------------ */ 419 /** 420 * @param array Any array of object 421 * @return A new <i>modifiable</i> list initialised with the elements from <code>array</code>. 422 */ array2List(E[] array)423 public static<E> List<E> array2List(E[] array) 424 { 425 if (array==null || array.length==0) 426 return new ArrayList<E>(); 427 return new ArrayList<E>(Arrays.asList(array)); 428 } 429 430 /* ------------------------------------------------------------ */ 431 /** Add element to an array 432 * @param array The array to add to (or null) 433 * @param item The item to add 434 * @param type The type of the array (in case of null array) 435 * @return new array with contents of array plus item 436 */ addToArray(T[] array, T item, Class<?> type)437 public static<T> T[] addToArray(T[] array, T item, Class<?> type) 438 { 439 if (array==null) 440 { 441 if (type==null && item!=null) 442 type= item.getClass(); 443 @SuppressWarnings("unchecked") 444 T[] na = (T[])Array.newInstance(type, 1); 445 na[0]=item; 446 return na; 447 } 448 else 449 { 450 // TODO: Replace with Arrays.copyOf(T[] original, int newLength) from Java 1.6+ 451 Class<?> c = array.getClass().getComponentType(); 452 @SuppressWarnings("unchecked") 453 T[] na = (T[])Array.newInstance(c, Array.getLength(array)+1); 454 System.arraycopy(array, 0, na, 0, array.length); 455 na[array.length]=item; 456 return na; 457 } 458 } 459 460 /* ------------------------------------------------------------ */ removeFromArray(T[] array, Object item)461 public static<T> T[] removeFromArray(T[] array, Object item) 462 { 463 if (item==null || array==null) 464 return array; 465 for (int i=array.length;i-->0;) 466 { 467 if (item.equals(array[i])) 468 { 469 Class<?> c = array==null?item.getClass():array.getClass().getComponentType(); 470 @SuppressWarnings("unchecked") 471 T[] na = (T[])Array.newInstance(c, Array.getLength(array)-1); 472 if (i>0) 473 System.arraycopy(array, 0, na, 0, i); 474 if (i+1<array.length) 475 System.arraycopy(array, i+1, na, i, array.length-(i+1)); 476 return na; 477 } 478 } 479 return array; 480 } 481 482 } 483 484