1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.collection.ArrayList;
13 
14 import std.algorithm;
15 import std.array;
16 import std.conv;
17 import std.traits;
18 
19 import hunt.Exceptions;
20 import hunt.collection.Array;
21 import hunt.collection.AbstractList;
22 import hunt.collection.Collection;
23 import hunt.collection.List;
24 import hunt.util.Comparator;
25 
26 /**
27 */
28 class ArrayList(E) : AbstractList!E {
29 
30     // private enum long serialVersionUID = 8683452581122892189L;
31 
32     /**
33      * Default initial capacity.
34      */
35     private enum int DEFAULT_CAPACITY = 10;
36 
37     /**
38      * Shared empty array instance used for empty instances.
39      */
40     private enum Object[] EMPTY_ELEMENTDATA = [];
41 
42     /**
43      * Shared empty array instance used for default sized empty instances. We
44      * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
45      * first element is added.
46      */
47     private enum Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = [];
48 
49     
50     protected Array!(E) _array;
51 
52     /**
53      * Constructs an empty list with the specified initial capacity.
54      *
55      * @param  initialCapacity  the initial capacity of the list
56      * @throws Exception if the specified initial capacity
57      *         is negative
58      */
59     this(int initialCapacity) {
60         _array.reserve(initialCapacity);
61         super();
62         // if (initialCapacity > 0) {
63         //     this._array = new Object[initialCapacity];
64         // } else if (initialCapacity == 0) {
65         //     this._array = EMPTY_ELEMENTDATA;
66         // } else {
67         //     throw new Exception("Illegal Capacity: "+
68         //                                        initialCapacity);
69         // }
70     }
71 
72     /**
73      * Constructs an empty list with an initial capacity of ten.
74      */
75     this() {
76         // this._array = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
77         _array.reserve(16);
78         super();
79     }
80 
81     /**
82      * Constructs a list containing the elements of the specified
83      * collection, in the order they are returned by the collection's
84      * iterator.
85      *
86      * @param c the collection whose elements are to be placed into this list
87      * @throws NullPointerException if the specified collection is null
88      */
89      this(ref Array!E arr) {
90          _array = arr;
91      }
92 
93      this(E[] arr) {
94          _array.insertBack(arr);
95      }
96 
97     this(Collection!E c) {
98         foreach(E e; c) {
99             _array.insertBack(e);
100         }
101     }
102 
103     /**
104      * Trims the capacity of this <tt>ArrayList</tt> instance to be the
105      * list's current size.  An application can use this operation to minimize
106      * the storage of an <tt>ArrayList</tt> instance.
107      */
108     // void trimToSize() {
109     //     modCount++;
110     //     if (size < _array.length) {
111     //         _array = (size == 0)
112     //           ? EMPTY_ELEMENTDATA
113     //           : Arrays.copyOf(_array, size);
114     //     }
115     // }
116 
117     /**
118      * Increases the capacity of this <tt>ArrayList</tt> instance, if
119      * necessary, to ensure that it can hold at least the number of elements
120      * specified by the minimum capacity argument.
121      *
122      * @param   minCapacity   the desired minimum capacity
123      */
124     // void ensureCapacity(int minCapacity) {
125     //     int minExpand = (_array != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
126     //         // any size if not default element table
127     //         ? 0
128     //         // larger than default for default empty table. It's already
129     //         // supposed to be at default size.
130     //         : DEFAULT_CAPACITY;
131 
132     //     if (minCapacity > minExpand) {
133     //         ensureExplicitCapacity(minCapacity);
134     //     }
135     // }
136 
137     // private void ensureCapacityInternal(int minCapacity) {
138     //     if (_array == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
139     //         minCapacity = std.algorithm.max(DEFAULT_CAPACITY, minCapacity);
140     //     }
141 
142     //     ensureExplicitCapacity(minCapacity);
143     // }
144 
145     // private void ensureExplicitCapacity(int minCapacity) {
146     //     modCount++;
147 
148     //     // overflow-conscious code
149     //     if (minCapacity - _array.length > 0)
150     //         grow(minCapacity);
151     // }
152 
153     /**
154      * The maximum size of array to allocate.
155      * Some VMs reserve some header words in an array.
156      * Attempts to allocate larger arrays may result in
157      * OutOfMemoryError: Requested array size exceeds VM limit
158      */
159     private enum int MAX_ARRAY_SIZE = int.max - 8;
160 
161 
162 
163     /**
164      * Returns the number of elements in this list.
165      *
166      * @return the number of elements in this list
167      */
168     override int size() {
169         return cast(int)_array.length;
170     }
171 
172     /**
173      * Returns <tt>true</tt> if this list contains no elements.
174      *
175      * @return <tt>true</tt> if this list contains no elements
176      */
177     override bool isEmpty() {
178         return _array.empty;
179     }
180 
181     /**
182      * Returns <tt>true</tt> if this list contains the specified element.
183      * More formally, returns <tt>true</tt> if and only if this list contains
184      * at least one element <tt>e</tt> such that
185      * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
186      *
187      * @param o element whose presence in this list is to be tested
188      * @return <tt>true</tt> if this list contains the specified element
189      */
190     override bool contains(E o) const{
191         return _array[].canFind(o);
192     }
193 
194 
195     /**
196      * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
197      * elements themselves are not copied.)
198      *
199      * @return a clone of this <tt>ArrayList</tt> instance
200      */
201     // Object clone() {
202 
203     // }
204 
205     /**
206      * Returns an array containing all of the elements in this list
207      * in proper sequence (from first to last element).
208      *
209      * <p>The returned array will be "safe" in that no references to it are
210      * maintained by this list.  (In other words, this method must allocate
211      * a new array).  The caller is thus free to modify the returned array.
212      *
213      * <p>This method acts as bridge between array-based and collection-based
214      * APIs.
215      *
216      * @return an array containing all of the elements in this list in
217      *         proper sequence
218      */
219     override E[] toArray() {
220         return _array.array;
221     }
222 
223     
224 
225     // Positional Access Operations
226 
227     // 
228     E elementData(int index) {
229         return _array[index];
230     }
231 
232     /**
233      * Returns the element at the specified position in this list.
234      *
235      * @param  index index of the element to return
236      * @return the element at the specified position in this list
237      * @throws IndexOutOfBoundsException {@inheritDoc}
238      */
239     override E get(int index) {
240         rangeCheck(index);
241 
242         return cast(E)_array[index];
243     }
244 
245     /**
246      * Replaces the element at the specified position in this list with
247      * the specified element.
248      *
249      * @param index index of the element to replace
250      * @param element element to be stored at the specified position
251      * @return the element previously at the specified position
252      * @throws IndexOutOfBoundsException {@inheritDoc}
253      */
254     override E set(int index, E element) {
255         rangeCheck(index);
256 
257         E oldValue = _array[index];
258         _array[index] = element;
259         return oldValue;
260     }
261 
262     /**
263      * Appends the specified element to the end of this list.
264      *
265      * @param e element to be appended to this list
266      * @return <tt>true</tt> (as specified by {@link Collection#add})
267      */
268     // bool add(E e) {
269     //     ensureCapacityInternal(size + 1);  // Increments modCount!!
270     //     _array[size++] = e;
271     //     return true;
272     // }
273     override bool add(E e) {
274         return _array.insertBack(e) >=0;
275     }
276 
277     /**
278      * Inserts the specified element at the specified position in this
279      * list. Shifts the element currently at that position (if any) and
280      * any subsequent elements to the right (adds one to their indices).
281      *
282      * @param index index at which the specified element is to be inserted
283      * @param element element to be inserted
284      * @throws IndexOutOfBoundsException {@inheritDoc}
285      */
286     override void add(int index, E element) {
287         if(_array.length == 0)
288             _array.insertBack(element) ;
289         else {
290             if(index <= 0) 
291                 index = 1;
292             _array.insertAfter(_array[index-1 .. index], element);
293         }
294     }
295 
296     alias add = AbstractList!(E).add;
297 
298     /**
299      * Removes the element at the specified position in this list.
300      * Shifts any subsequent elements to the left (subtracts one from their
301      * indices).
302      *
303      * @param index the index of the element to be removed
304      * @return the element that was removed from the list
305      * @throws IndexOutOfBoundsException {@inheritDoc}
306      */
307     override E removeAt(int index) {
308         E oldValue = _array[index];
309         _array.linearRemove(_array[index .. index+1]);
310         return oldValue;
311     }
312 
313     /**
314      * Removes the first occurrence of the specified element from this list,
315      * if it is present.  If the list does not contain the element, it is
316      * unchanged.  More formally, removes the element with the lowest index
317      * <tt>i</tt> such that
318      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
319      * (if such an element exists).  Returns <tt>true</tt> if this list
320      * contained the specified element (or equivalently, if this list
321      * changed as a result of the call).
322      *
323      * @param o element to be removed from this list, if present
324      * @return <tt>true</tt> if this list contained the specified element
325      */
326     override bool remove(E o)
327     {
328         int index = indexOf(o);
329         if(index < 0)   return false;
330         _array.linearRemove(_array[index .. index+1]);
331         return true;
332     }
333 
334     override int indexOf(E o) {
335         for(size_t i=0; i<_array.length; i++)
336         {
337             static if(is(E == class))
338             {
339                 if(_array[i] is o) return cast(int)i;
340             }
341             else
342             {
343                 if(_array[i] == o) return cast(int)i;
344             }
345         }
346 
347         return -1;
348     }
349 
350     override int lastIndexOf(E o) {
351         for(size_t i=_array.length -1; i>=0; i--) {
352             if(_array[i] == o) return cast(int)i;
353         }
354 
355         return -1;
356     }
357 
358 
359     override int opApply(scope int delegate(ref E) dg) {
360         if(dg is null)
361             throw new NullPointerException();
362             
363         int result = 0;
364         foreach(E v; _array) {
365             result = dg(v);
366             if(result != 0) return result;
367         }
368         return result;
369     }
370 
371 
372     /*
373      * Private remove method that skips bounds checking and does not
374      * return the value removed.
375      */
376     // private void fastRemove(int index) {
377     //     modCount++;
378     //     int numMoved = size - index - 1;
379     //     if (numMoved > 0)
380     //         System.arraycopy(_array, index+1, _array, index,
381     //                          numMoved);
382     //     _array[--size] = null; // clear to let GC do its work
383     // }
384 
385     /**
386      * Removes all of the elements from this list.  The list will
387      * be empty after this call returns.
388      */
389     override void clear() {
390         _array.clear();
391     }
392 
393     /**
394      * Appends all of the elements in the specified collection to the end of
395      * this list, in the order that they are returned by the
396      * specified collection's Iterator.  The behavior of this operation is
397      * undefined if the specified collection is modified while the operation
398      * is in progress.  (This implies that the behavior of this call is
399      * undefined if the specified collection is this list, and this
400      * list is nonempty.)
401      *
402      * @param c collection containing elements to be added to this list
403      * @return <tt>true</tt> if this list changed as a result of the call
404      * @throws NullPointerException if the specified collection is null
405      */
406     // bool addAll(Collection<E> c) {
407     //     Object[] a = c.toArray();
408     //     int numNew = a.length;
409     //     ensureCapacityInternal(size + numNew);  // Increments modCount
410     //     System.arraycopy(a, 0, _array, size, numNew);
411     //     size += numNew;
412     //     return numNew != 0;
413     // }
414 
415     /**
416      * Inserts all of the elements in the specified collection into this
417      * list, starting at the specified position.  Shifts the element
418      * currently at that position (if any) and any subsequent elements to
419      * the right (increases their indices).  The new elements will appear
420      * in the list in the order that they are returned by the
421      * specified collection's iterator.
422      *
423      * @param index index at which to insert the first element from the
424      *              specified collection
425      * @param c collection containing elements to be added to this list
426      * @return <tt>true</tt> if this list changed as a result of the call
427      * @throws IndexOutOfBoundsException {@inheritDoc}
428      * @throws NullPointerException if the specified collection is null
429      */
430     // bool addAll(int index, Collection<E> c) {
431     //     rangeCheckForAdd(index);
432 
433     //     Object[] a = c.toArray();
434     //     int numNew = a.length;
435     //     ensureCapacityInternal(size + numNew);  // Increments modCount
436 
437     //     int numMoved = size - index;
438     //     if (numMoved > 0)
439     //         System.arraycopy(_array, index, _array, index + numNew,
440     //                          numMoved);
441 
442     //     System.arraycopy(a, 0, _array, index, numNew);
443     //     size += numNew;
444     //     return numNew != 0;
445     // }
446 
447     /**
448      * Removes from this list all of the elements whose index is between
449      * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
450      * Shifts any succeeding elements to the left (reduces their index).
451      * This call shortens the list by {@code (toIndex - fromIndex)} elements.
452      * (If {@code toIndex==fromIndex}, this operation has no effect.)
453      *
454      * @throws IndexOutOfBoundsException if {@code fromIndex} or
455      *         {@code toIndex} is out of range
456      *         ({@code fromIndex < 0 ||
457      *          fromIndex >= size() ||
458      *          toIndex > size() ||
459      *          toIndex < fromIndex})
460      */
461     protected void removeRange(int fromIndex, int toIndex) {
462         _array.linearRemove(_array[fromIndex..toIndex]);
463     }
464 
465     /**
466      * Checks if the given index is in range.  If not, throws an appropriate
467      * runtime exception.  This method does *not* check if the index is
468      * negative: It is always used immediately prior to an array access,
469      * which throws an ArrayIndexOutOfBoundsException if index is negative.
470      */
471     private void rangeCheck(int index) {
472         if (index >= _array.length)
473             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
474     }
475 
476     /**
477      * A version of rangeCheck used by add and addAll.
478      */
479     private void rangeCheckForAdd(int index) {
480         if (index > _array.length || index < 0)
481             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
482     }
483 
484     /**
485      * Constructs an IndexOutOfBoundsException detail message.
486      * Of the many possible refactorings of the error handling code,
487      * this "outlining" performs best with both server and client VMs.
488      */
489     private string outOfBoundsMsg(int index) {
490         return "Index: "~index.to!string()~", Size: " ~ to!string(size());
491     }
492 
493     /**
494      * Removes from this list all of its elements that are contained in the
495      * specified collection.
496      *
497      * @param c collection containing elements to be removed from this list
498      * @return {@code true} if this list changed as a result of the call
499      * @throws ClassCastException if the class of an element of this list
500      *         is incompatible with the specified collection
501      * (<a href="Collection.html#optional-restrictions">optional</a>)
502      * @throws NullPointerException if this list contains a null element and the
503      *         specified collection does not permit null elements
504      * (<a href="Collection.html#optional-restrictions">optional</a>),
505      *         or if the specified collection is null
506      * @see Collection#contains(Object)
507      */
508     // bool removeAll(Collection<?> c) {
509     //     Objects.requireNonNull(c);
510     //     return batchRemove(c, false);
511     // }
512 
513     /**
514      * Retains only the elements in this list that are contained in the
515      * specified collection.  In other words, removes from this list all
516      * of its elements that are not contained in the specified collection.
517      *
518      * @param c collection containing elements to be retained in this list
519      * @return {@code true} if this list changed as a result of the call
520      * @throws ClassCastException if the class of an element of this list
521      *         is incompatible with the specified collection
522      * (<a href="Collection.html#optional-restrictions">optional</a>)
523      * @throws NullPointerException if this list contains a null element and the
524      *         specified collection does not permit null elements
525      * (<a href="Collection.html#optional-restrictions">optional</a>),
526      *         or if the specified collection is null
527      * @see Collection#contains(Object)
528      */
529     // bool retainAll(Collection!E c) {
530     //     assert(c !is null);
531     //     // return batchRemove(c, true);
532 
533     //     _array[].remove!(x => !c.canFind(x));
534     //     return true;
535     // }
536 
537     // private bool batchRemove(Collection<?> c, bool complement) {
538     //     final Object[] _array = this._array;
539     //     int r = 0, w = 0;
540     //     bool modified = false;
541     //     try {
542     //         for (; r < size; r++)
543     //             if (c.contains(_array[r]) == complement)
544     //                 _array[w++] = _array[r];
545     //     } finally {
546     //         // Preserve behavioral compatibility with AbstractCollection,
547     //         // even if c.contains() throws.
548     //         if (r != size) {
549     //             System.arraycopy(_array, r,
550     //                              _array, w,
551     //                              size - r);
552     //             w += size - r;
553     //         }
554     //         if (w != size) {
555     //             // clear to let GC do its work
556     //             for (int i = w; i < size; i++)
557     //                 _array[i] = null;
558     //             modCount += size - w;
559     //             size = w;
560     //             modified = true;
561     //         }
562     //     }
563     //     return modified;
564     // }
565 
566     /**
567      * Save the state of the <tt>ArrayList</tt> instance to a stream (that
568      * is, serialize it).
569      *
570      * @serialData The length of the array backing the <tt>ArrayList</tt>
571      *             instance is emitted (int), followed by all of its elements
572      *             (each an <tt>Object</tt>) in the proper order.
573      */
574     // private void writeObject(java.io.ObjectOutputStream s)
575     //     throws java.io.IOException{
576     //     // Write out element count, and any hidden stuff
577     //     int expectedModCount = modCount;
578     //     s.defaultWriteObject();
579 
580     //     // Write out size as capacity for behavioural compatibility with clone()
581     //     s.writeInt(size);
582 
583     //     // Write out all elements in the proper order.
584     //     for (int i=0; i<size; i++) {
585     //         s.writeObject(_array[i]);
586     //     }
587 
588     //     if (modCount != expectedModCount) {
589     //         throw new ConcurrentModificationException();
590     //     }
591     // }
592 
593     /**
594      * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
595      * deserialize it).
596      */
597     // private void readObject(java.io.ObjectInputStream s)
598     //     throws java.io.IOException, ClassNotFoundException {
599     //     _array = EMPTY_ELEMENTDATA;
600 
601     //     // Read in size, and any hidden stuff
602     //     s.defaultReadObject();
603 
604     //     // Read in capacity
605     //     s.readInt(); // ignored
606 
607     //     if (size > 0) {
608     //         // be like clone(), allocate array based upon size not capacity
609     //         ensureCapacityInternal(size);
610 
611     //         Object[] a = _array;
612     //         // Read in all elements in the proper order.
613     //         for (int i=0; i<size; i++) {
614     //             a[i] = s.readObject();
615     //         }
616     //     }
617     // }
618 
619 
620     /**
621      * Returns a view of the portion of this list between the specified
622      * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
623      * {@code fromIndex} and {@code toIndex} are equal, the returned list is
624      * empty.)  The returned list is backed by this list, so non-structural
625      * changes in the returned list are reflected in this list, and vice-versa.
626      * The returned list supports all of the optional list operations.
627      *
628      * <p>This method eliminates the need for explicit range operations (of
629      * the sort that commonly exist for arrays).  Any operation that expects
630      * a list can be used as a range operation by passing a subList view
631      * instead of a whole list.  For example, the following idiom
632      * removes a range of elements from a list:
633      * <pre>
634      *      list.subList(from, to).clear();
635      * </pre>
636      * Similar idioms may be constructed for {@link #indexOf(Object)} and
637      * {@link #lastIndexOf(Object)}, and all of the algorithms in the
638      * {@link Collections} class can be applied to a subList.
639      *
640      * <p>The semantics of the list returned by this method become undefined if
641      * the backing list (i.e., this list) is <i>structurally modified</i> in
642      * any way other than via the returned list.  (Structural modifications are
643      * those that change the size of this list, or otherwise perturb it in such
644      * a fashion that iterations in progress may yield incorrect results.)
645      *
646      * @throws IndexOutOfBoundsException {@inheritDoc}
647      * @throws Exception {@inheritDoc}
648      */
649     // List<E> subList(int fromIndex, int toIndex) {
650     //     subListRangeCheck(fromIndex, toIndex, size);
651     //     return new SubList(this, 0, fromIndex, toIndex);
652     // }
653 
654     // static void subListRangeCheck(int fromIndex, int toIndex, int size) {
655     //     if (fromIndex < 0)
656     //         throw new IndexOutOfBoundsException("fromIndex = " ~ fromIndex);
657     //     if (toIndex > size)
658     //         throw new IndexOutOfBoundsException("toIndex = " ~ toIndex);
659     //     if (fromIndex > toIndex)
660     //         throw new Exception("fromIndex(" ~ fromIndex +
661     //                                            ") > toIndex(" ~ toIndex ~ ")");
662     // }
663 
664     static if (isOrderingComparable!E) {
665     override void sort(bool isAscending = true) {
666         
667             // https://issues.dlang.org/show_bug.cgi?id=15304
668             // std.algorithm.sort(_array[]);
669             
670             int expectedModCount = modCount;
671             if(isAscending)
672                 std.algorithm.sort!(lessThan!E)(_array[]);
673             else
674                 std.algorithm.sort!(greaterthan!E)(_array[]);
675                 
676             if (modCount != expectedModCount)
677                 throw new ConcurrentModificationException();
678             modCount++;
679         } 
680     }
681 
682 
683     override void sort(Comparator!E c) {
684         int expectedModCount = modCount;
685         std.algorithm.sort!((a, b) => c.compare(a, b) < 0)(_array[]);
686 
687         if (modCount != expectedModCount)
688             throw new ConcurrentModificationException();
689         modCount++;
690     }
691 
692 }
693 
694 /**
695  * Lazy List creation.
696  * <p>
697  * A List helper class that attempts to avoid unnecessary List creation. If a
698  * method needs to create a List to return, but it is expected that this will
699  * either be empty or frequently contain a single item, then using LazyList will
700  * avoid additional object creations by using {@link Collections#EMPTY_LIST} or
701  * {@link Collections#singletonList(Object)} where possible.
702  * </p>
703  * <p>
704  * LazyList works by passing an opaque representation of the list in and out of
705  * all the LazyList methods. This opaque object is either null for an empty
706  * list, an Object for a list with a single entry or an {@link ArrayList} for a
707  * list of items.
708  * </p>
709  * <strong>Usage</strong>
710  * 
711  * <pre>
712  * Object lazylist = null;
713  * while (loopCondition) {
714  * 	Object item = getItem();
715  * 	if (item.isToBeAdded())
716  * 		lazylist = LazyList.add(lazylist, item);
717  * }
718  * return LazyList.getList(lazylist);
719  * </pre>
720  *
721  * An ArrayList of default size is used as the initial LazyList.
722  *
723  * @see java.util.List
724  */
725 class LazyList
726 {
727     // this(){
728 
729     // }
730 
731 	/**
732 	 * Add an item to a LazyList
733 	 * 
734 	 * @param list
735 	 *            The list to add to or null if none yet created.
736 	 * @param item
737 	 *            The item to add.
738 	 * @return The lazylist created or added to.
739 	 */
740     static Object add(Object list, Object item) {
741 		if (list is null) {
742 			if (typeid(item) == typeid(List!Object) || item is null) {
743 				List!Object l = new ArrayList!Object();
744 				l.add(item);
745 				return cast(Object)l;
746 			}
747 
748 			return item;
749 		}
750 
751 		if (typeid(list) == typeid(List!Object)) {
752 			(cast(List!Object) list).add(item);
753 			return list;
754 		}
755 
756 		List!Object l = new ArrayList!Object();
757 		l.add(list);
758 		l.add(item);
759 		return cast(Object)l;
760 	}
761 
762     	/**
763 	 * Get the real List from a LazyList.
764 	 * 
765 	 * @param list
766 	 *            A LazyList returned from LazyList.add(Object) or null
767 	 * @param nullForEmpty
768 	 *            If true, null is returned instead of an empty list.
769 	 * @return The List of added items, which may be null, an EMPTY_LIST or a
770 	 *         SingletonList.
771 	 * @param <E>
772 	 *            the list entry type
773 	 */
774 	static List!E getList(E)(Object list, bool nullForEmpty) {
775 		if (list is null) {
776 			if (nullForEmpty)
777 				return null;
778 			return  new EmptyList!E(); // Collections.emptyList();
779 		}
780         List!E r = cast(List!E) list;
781 		if (r !is null)
782 			return r;
783 
784 		// return (List<E>) Collections.singletonList(list);
785         auto l = new ArrayList!E();
786         l.add(cast(E)list);
787         return l;
788 	}
789 
790 
791 	/**
792 	 * The size of a lazy List
793 	 * 
794 	 * @param list
795 	 *            A LazyList returned from LazyList.add(Object) or null
796 	 * @return the size of the list.
797 	 */
798 	static int size(T)(List!(T) list) {
799 		if (list is null)
800 			return 0;
801 		return list.size();
802 	}
803 
804 }