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