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