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