001    /**
002     * <copyright>
003     *
004     * Copyright (c) 2009 IBM Corporation and others.
005     * All rights reserved.   This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors: 
011     *   IBM - Initial API and implementation
012     *
013     * </copyright>
014     *
015     * $Id: AbstractEList.java,v 1.1 2009/01/16 12:55:02 emerks Exp $
016     */
017    package org.eclipse.emf.common.util;
018    
019    
020    import java.util.AbstractList;
021    import java.util.Collection;
022    import java.util.ConcurrentModificationException;
023    import java.util.Iterator;
024    import java.util.List;
025    import java.util.ListIterator;
026    import java.util.NoSuchElementException;
027    
028    
029    /**
030     * A highly extensible abstract list implementation.
031     */
032    public abstract class AbstractEList<E> extends AbstractList<E> implements EList<E>
033    {
034      /**
035       * Creates an empty instance with no initial capacity.
036       * The data storage will be null.
037       */
038      public AbstractEList()
039      {
040        super();
041      }
042    
043      /**
044       * Returns whether <code>equals</code> rather than <code>==</code> should be used to compare members.
045       * The default is to return <code>true</code> but clients can optimize performance by returning <code>false</code>.
046       * The performance difference is highly significant.
047       * @return whether <code>equals</code> rather than <code>==</code> should be used.
048       */
049      protected boolean useEquals()
050      {
051        return true;
052      }
053    
054      /**
055       * Returns whether two objects are equal using the {@link #useEquals appropriate} comparison mechanism.
056       * @return whether two objects are equal.
057       */
058      protected boolean equalObjects(Object firstObject, Object secondObject)
059      {
060        return
061          useEquals() && firstObject != null ?
062            firstObject.equals(secondObject) :
063            firstObject == secondObject;
064      }
065    
066      /**
067       * Returns whether <code>null</code> is a valid object for the list.
068       * The default is to return <code>true</code>, but clients can override this to exclude <code>null</code>.
069       * @return whether <code>null</code> is a valid object for the list.
070       */
071      protected boolean canContainNull()
072      {
073        return true;
074      }
075    
076      /**
077       * Returns whether objects are constrained to appear at most once in the list.
078       * The default is to return <code>false</code>, but clients can override this to ensure uniqueness of contents.
079       * The performance impact is significant: operations such as <code>add</code> are O(n) as a result requiring uniqueness.
080       * @return whether objects are constrained to appear at most once in the list.
081       */
082      protected boolean isUnique()
083      {
084        return false;
085      }
086    
087      /**
088       * Validates a new content object and returns the validated object.
089       * This implementation checks for null, if {@link #canContainNull necessary} and returns the argument object.
090       * Clients may throw additional types of runtime exceptions
091       * in order to handle constraint violations.
092       * @param index the position of the new content.
093       * @param object the new content.
094       * @return the validated content.
095       * @exception IllegalArgumentException if a constraint prevents the object from being added.
096       */
097      protected E validate(int index, E object)
098      {
099        if (!canContainNull() && object == null)
100        {
101          throw new IllegalArgumentException("The 'no null' constraint is violated");
102        }
103    
104        return object;
105      }
106    
107      /**
108       * Resolves the object at the index and returns the result.
109       * This implementation simply returns the <code>object</code>;
110       * clients can use this to transform objects as they are fetched.
111       * @param index the position of the content.
112       * @param object the content.
113       * @return the resolved object.
114       */
115      protected E resolve(int index, E object)
116      {
117        return object;
118      }
119    
120      /**
121       * Called to indicate that the data storage has been set.
122       * This implementation does nothing;
123       * clients can use this to monitor settings to the data storage.
124       * @param index the position that was set.
125       * @param newObject the new object at the position.
126       * @param oldObject the old object at the position.
127       */
128      protected void didSet(int index, E newObject, E oldObject)
129      {
130        // Do nothing.
131      }
132    
133      /**
134       * Called to indicate that an object has been added to the data storage.
135       * This implementation does nothing;
136       * clients can use this to monitor additions to the data storage.
137       * @param index the position object the new object.
138       * @param newObject the new object at the position.
139       */
140      protected void didAdd(int index, E newObject)
141      {
142        // Do nothing.
143      }
144    
145      /**
146       * Called to indicate that an object has been removed from the data storage.
147       * This implementation does nothing;
148       * clients can use this to monitor removals from the data storage.
149       * @param index the position of the old object.
150       * @param oldObject the old object at the position.
151       */
152      protected void didRemove(int index, E oldObject)
153      {
154        // Do nothing.
155      }
156    
157      /**
158       * Called to indicate that the data storage has been cleared.
159       * This implementation calls {@link #didRemove didRemove} for each object;
160       * clients can use this to monitor clearing  of the data storage.
161       * @param size the original size of the list.
162       * @param oldObjects the old data storage being discarded.
163       * @see #didRemove
164       */
165      protected void didClear(int size, Object [] oldObjects)
166      {
167        if (oldObjects != null)
168        {
169          for (int i = 0; i < size; ++i)
170          {
171            @SuppressWarnings("unchecked") E object = (E)oldObjects[i];
172            didRemove(i, object);
173          }
174        }
175      }
176    
177      /**
178       * Called to indicate that an object has been moved in the data storage.
179       * This implementation does nothing;
180       * clients can use this to monitor movement in the data storage.
181       * @param index the position of the moved object.
182       * @param movedObject the moved object at the position.
183       * @param oldIndex the position the object was at before the move.
184       */
185      protected void didMove(int index, E movedObject, int oldIndex)
186      {
187        // Do nothing.
188      }
189    
190      /**
191       * Called to indicate that the data storage has been changed.
192       * This implementation does nothing;
193       * clients can use this to monitor change in the data storage.
194       */
195      protected void didChange()
196      {
197        // Do nothing.
198      }
199    
200      /**
201       * An IndexOutOfBoundsException that constructs a message from the argument data.
202       * Having this avoids having the byte code that computes the message repeated/inlined at the creation site.
203       */
204      protected static class BasicIndexOutOfBoundsException extends IndexOutOfBoundsException
205      {
206        private static final long serialVersionUID = 1L;
207    
208        /**
209         * Constructs an instance with a message based on the arguments.
210         */
211        public BasicIndexOutOfBoundsException(int index, int size)
212        {
213          super("index=" + index + ", size=" + size);
214        }
215      }
216     
217      /**
218       * Returns the object at the index without {@link #resolve resolving} it.
219       * @param index the position in question.
220       * @return the object at the index.
221       * @exception IndexOutOfBoundsException if the index isn't within the size range.
222       * @see #resolve
223       * @see #get
224       */
225      protected E basicGet(int index)
226      {
227        int size = size();
228        if (index >= size)
229          throw new BasicIndexOutOfBoundsException(index, size);
230    
231        return primitiveGet(index);
232      }
233    
234      /**
235       * Returns the object at the index without {@link #resolve resolving} it and without range checking the index.
236       * @param index the position in question.
237       * @return the object at the index.
238       * @see #resolve
239       * @see #get
240       * @see #basicGet(int)
241       */
242      protected abstract E primitiveGet(int index);
243    
244      /**
245       * Sets the object at the index
246       * and returns the old object at the index.
247       * This implementation delegates to {@link #setUnique setUnique}
248       * after range checking and after {@link #isUnique uniqueness} checking.
249       * @param index the position in question.
250       * @param object the object to set.
251       * @return the old object at the index.
252       * @exception IndexOutOfBoundsException if the index isn't within the size range.
253       * @exception IllegalArgumentException if there is a constraint violation, e.g., non-uniqueness.
254       * @see #setUnique
255       */
256      @Override
257      public E set(int index, E object)
258      {
259        int size = size();
260        if (index >= size)
261          throw new BasicIndexOutOfBoundsException(index, size);
262    
263        if (isUnique())
264        {
265          int currentIndex = indexOf(object);
266          if (currentIndex >=0 && currentIndex != index)
267          {
268            throw new IllegalArgumentException("The 'no duplicates' constraint is violated");
269          }
270        }
271    
272        return setUnique(index, object);
273      }
274    
275      /**
276       * Sets the object at the index
277       * and returns the old object at the index;
278       * it does no ranging checking or uniqueness checking.
279       * This implementation delegates to {@link #assign assign}, {@link #didSet didSet}, and {@link #didChange didChange}.
280       * @param index the position in question.
281       * @param object the object to set.
282       * @return the old object at the index.
283       * @see #set
284       */
285      public abstract E setUnique(int index, E object);
286    
287      /**
288       * Adds the object at the end of the list
289       * and returns whether the object was added;
290       * if {@link #isUnique uniqueness} is required,
291       * duplicates will be ignored and <code>false</code> will be returned.
292       * This implementation delegates to {@link #addUnique(Object) addUnique(E)}
293       * after uniqueness checking.
294       * @param object the object to be added.
295       * @return whether the object was added.
296       * @see #addUnique(Object)
297       */
298      @Override
299      public boolean add(E object)
300      {
301        if (isUnique() && contains(object))
302        {
303          return false;
304        }
305        else
306        {
307          addUnique(object);
308          return true;
309        }
310      }
311    
312      /**
313       * Adds the object at the end of the list;
314       * it does no uniqueness checking.
315       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
316       * after uniqueness checking.
317       * @param object the object to be added.
318       * @see #add(Object)
319       */
320      public abstract void addUnique(E object);
321    
322      /**
323       * Adds the object at the given index in the list.
324       * If {@link #isUnique uniqueness} is required,
325       * duplicates will be ignored.
326       * This implementation delegates to {@link #addUnique(int, Object) addUnique(int, E)}
327       * after uniqueness checking.
328       * @param object the object to be added.
329       * @exception IllegalArgumentException if {@link #isUnique uniqueness} is required,
330       * and the object is a duplicate.
331       * @see #addUnique(int, Object)
332       */
333      @Override
334      public void add(int index, E object)
335      {
336        int size = size();
337        if (index > size)
338          throw new BasicIndexOutOfBoundsException(index, size);
339    
340        if (isUnique() && contains(object))
341        {
342          throw new IllegalArgumentException("The 'no duplicates' constraint is violated");
343        }
344    
345        addUnique(index, object);
346      }
347    
348      /**
349       * Adds the object at the given index in the list;
350       * it does no ranging checking or uniqueness checking.
351       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
352       * @param object the object to be added.
353       * @see #add(int, Object)
354       */
355      public abstract void addUnique(int index, E object);
356    
357      /**
358       * Adds each object of the collection to the end of the list.
359       * If {@link #isUnique uniqueness} is required,
360       * duplicates will be {@link #getNonDuplicates removed} from the collection,
361       * which could even result in an empty collection.
362       * This implementation delegates to {@link #addAllUnique(Collection) addAllUnique(Collection)}
363       * after uniqueness checking.
364       * @param collection the collection of objects to be added.
365       * @see #addAllUnique(Collection)
366       */
367      @Override
368      public boolean addAll(Collection<? extends E> collection)
369      {
370        if (isUnique())
371        {
372           collection = getNonDuplicates(collection);
373        }
374        return addAllUnique(collection);
375      }
376    
377      /**
378       * Adds each object of the collection to the end of the list;
379       * it does no uniqueness checking.
380       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
381       * @param collection the collection of objects to be added.
382       * @see #addAll(Collection)
383       */
384      public abstract boolean addAllUnique(Collection<? extends E> collection);
385    
386      /**
387       * Adds each object of the collection at each successive index in the list
388       * and returns whether any objects were added.
389       * If {@link #isUnique uniqueness} is required,
390       * duplicates will be {@link #getNonDuplicates removed} from the collection,
391       * which could even result in an empty collection.
392       * This implementation delegates to {@link #addAllUnique(int, Collection) addAllUnique(int, Collection)}
393       * after uniqueness checking.
394       * @param index the index at which to add.
395       * @param collection the collection of objects to be added.
396       * @return whether any objects were added.
397       * @see #addAllUnique(int, Collection)
398       */
399      @Override
400      public boolean addAll(int index, Collection<? extends E> collection)
401      {
402        int size = size();
403        if (index > size)
404          throw new BasicIndexOutOfBoundsException(index, size);
405    
406        if (isUnique())
407        {
408          collection = getNonDuplicates(collection);
409        }
410        return addAllUnique(index, collection);
411      }
412    
413      /**
414       * Adds each object of the collection at each successive index in the list
415       * and returns whether any objects were added;
416       * it does no ranging checking or uniqueness checking.
417       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
418       * @param index the index at which to add.
419       * @param collection the collection of objects to be added.
420       * @return whether any objects were added.
421       * @see #addAll(int, Collection)
422       */
423      public abstract boolean addAllUnique(int index, Collection<? extends E> collection);
424    
425      /**
426       * Adds each object from start to end of the array at the index of list
427       * and returns whether any objects were added;
428       * it does no ranging checking or uniqueness checking.
429       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
430       * @param objects the objects to be added.
431       * @param start the index of first object to be added.
432       * @param end the index past the last object to be added.
433       * @return whether any objects were added.
434       * @see #addAllUnique(Object[], int, int)
435       */
436      public abstract boolean addAllUnique(Object [] objects, int start, int end);
437    
438      /**
439       * Adds each object from start to end of the array at each successive index in the list
440       * and returns whether any objects were added;
441       * it does no ranging checking or uniqueness checking.
442       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
443       * @param index the index at which to add.
444       * @param objects the objects to be added.
445       * @param start the index of first object to be added.
446       * @param end the index past the last object to be added.
447       * @return whether any objects were added.
448       * @see #addAllUnique(Object[], int, int)
449       */
450      public abstract boolean addAllUnique(int index, Object [] objects, int start, int end);
451    
452      /**
453       * Removes the object from the list and returns whether the object was actually contained by the list.
454       * This implementation uses {@link #indexOf indexOf} to find the object
455       * and delegates to {@link #remove(int) remove(int)}
456       * in the case that it finds the object.
457       * @param object the object to be removed.
458       * @return whether the object was actually contained by the list.
459       */
460      @Override
461      public boolean remove(Object object)
462      {
463        int index = indexOf(object);
464        if (index >= 0)
465        {
466          remove(index);
467          return true;
468        }
469        else
470        {
471          return false;
472        }
473      }
474    
475      /**
476       * Removes each object of the collection from the list and returns whether any object was actually contained by the list.
477       * @param collection the collection of objects to be removed.
478       * @return whether any object was actually contained by the list.
479       */
480      @Override
481      public boolean removeAll(Collection<?> collection)
482      {
483        boolean modified = false;
484        for (int i = size(); --i >= 0; )
485        {
486          if (collection.contains(primitiveGet(i)))
487          {
488            remove(i);
489            modified = true;
490          }
491        }
492    
493        return modified;
494      }
495    
496      /**
497       * Removes the object at the index from the list and returns it.
498       * This implementation delegates to {@link #didRemove didRemove} and {@link #didChange didChange}.
499       * @param index the position of the object to remove.
500       * @return the removed object.
501       * @exception IndexOutOfBoundsException if the index isn't within the size range.
502       */
503      @Override
504      public abstract E remove(int index);
505    
506      /**
507       * Removes from the list each object not contained by the collection
508       * and returns whether any object was actually removed.
509       * This delegates to {@link #remove(int) remove(int)}
510       * in the case that it finds an object that isn't retained.
511       * @param collection the collection of objects to be retained.
512       * @return whether any object was actually removed.
513       */
514      @Override
515      public boolean retainAll(Collection<?> collection)
516      {
517        boolean modified = false;
518        for (int i = size(); --i >= 0; )
519        {
520          if (!collection.contains(primitiveGet(i)))
521          {
522            remove(i);
523            modified = true;
524          }
525        }
526        return modified;
527      }
528    
529      /**
530       * Moves the object to the index of the list.
531       * This implementation uses {@link #indexOf} of find the object
532       * and delegates to {@link #move(int, int) move(int, int)}.
533       * @param index the new position for the object in the list.
534       * @param object the object to be moved.
535       * @exception IndexOutOfBoundsException if the index isn't within the size range or the object isn't contained by the list.
536       */
537      public void move(int index, E object)
538      {
539        move(index, indexOf(object));
540      }
541    
542      /**
543       * Moves the object at the source index of the list to the target index of the list
544       * and returns the moved object.
545       * This implementation delegates to {@link #assign assign}, {@link #didMove didMove}, and {@link #didChange didChange}.
546       * @param targetIndex the new position for the object in the list.
547       * @param sourceIndex the old position of the object in the list.
548       * @return the moved object.
549       * @exception IndexOutOfBoundsException if either index isn't within the size range.
550       */
551      public abstract E move(int targetIndex, int sourceIndex);
552    
553    
554      /**
555       * Returns whether the object is a list with corresponding equal objects.
556       * This implementation uses either <code>equals</code> or <code>"=="</code> depending on {@link #useEquals useEquals}.
557       * @return whether the object is a list with corresponding equal objects.
558       * @see #useEquals
559       */
560      @Override
561      public boolean equals(Object object) 
562      {
563        if (object == this)
564        {
565          return true;
566        }
567    
568        if (!(object instanceof List<?>))
569        {
570          return false;
571        }
572    
573        List<?> list = (List<?>)object;
574        int size = size();
575        if (list.size() != size)
576        {
577          return false;
578        }
579    
580        Iterator<?> objects = list.iterator();
581        if (useEquals())
582        {
583          for (int i = 0; i < size; ++i)
584          {
585            Object o1 = primitiveGet(i);
586            Object o2 = objects.next();
587            if (o1 == null ? o2 != null : !o1.equals(o2))
588            {
589              return false;
590            }
591          }
592        }
593        else
594        {
595          for (int i = 0; i < size; ++i)
596          {
597            Object o1 = primitiveGet(i);
598            Object o2 = objects.next();
599            if (o1 != o2)
600            {
601              return false;
602            }
603          }
604        }
605    
606        return true;
607      }
608    
609      /**
610       * Returns a hash code computed from each object's hash code.
611       * @return a hash code.
612       */
613      @Override
614      public int hashCode() 
615      {
616        int hashCode = 1;
617        for (int i = 0, size = size(); i < size; ++i)
618        {
619          Object object = primitiveGet(i);
620          hashCode = 31 * hashCode + (object == null ? 0 : object.hashCode());
621        }
622        return hashCode;
623      }
624    
625      /**
626       * Returns a string of the form <code>"[object1, object2]"</code>.
627       * @return a string of the form <code>"[object1, object2]"</code>.
628       */
629      @Override
630      public String toString() 
631      {
632        StringBuffer stringBuffer = new StringBuffer();
633        stringBuffer.append("[");
634        for (int i = 0, size = size(); i < size; )
635        {
636          stringBuffer.append(String.valueOf(primitiveGet(i)));
637          if (++i < size)
638          {
639            stringBuffer.append(", ");
640          }
641        }
642        stringBuffer.append("]");
643        return stringBuffer.toString();
644      }
645    
646      /**
647       * Returns an iterator.
648       * This implementation allocates a {@link AbstractEList.EIterator}.
649       * @return an iterator.
650       * @see AbstractEList.EIterator
651       */
652      @Override
653      public Iterator<E> iterator()
654      {
655        return new EIterator<E>();
656      }
657    
658      /**
659       * An extensible iterator implementation.
660       */
661      protected class EIterator<E1> implements Iterator<E1>
662      {
663        /**
664         * The current position of the iterator.
665         */
666        protected int cursor = 0;
667    
668        /**
669         * The previous position of the iterator.
670         */
671        protected int lastCursor = -1;
672    
673        /**
674         * The modification count of the containing list.
675         */
676        protected int expectedModCount = modCount;
677    
678        /**
679         * Returns whether there are more objects.
680         * @return whether there are more objects.
681         */
682        public boolean hasNext()
683        {
684          return cursor != size();
685        }
686    
687        /**
688         * Returns the next object and advances the iterator.
689         * This implementation delegates to {@link #doNext doNext}.
690         * @return the next object.
691         * @exception NoSuchElementException if the iterator is done.
692         */
693        @SuppressWarnings("unchecked")
694        public E1 next()
695        {
696          return (E1)doNext();
697        }
698    
699        /**
700         * Returns the next object and advances the iterator.
701         * This implementation delegates to {@link AbstractEList#get get}.
702         * @return the next object.
703         * @exception NoSuchElementException if the iterator is done.
704         */
705        protected E doNext()
706        {
707          try
708          {
709            E next = get(cursor);
710            checkModCount();
711            lastCursor = cursor++;
712            return next;
713          }
714          catch (IndexOutOfBoundsException exception)
715          {
716            checkModCount();
717            throw new NoSuchElementException();
718          }
719        }
720    
721        /**
722         * Removes the last object returned by {@link #next()} from the list,
723         * it's an optional operation.
724         * This implementation can also function in a list iterator
725         * to act upon on the object returned by calling <code>previous</code>.
726         * @exception IllegalStateException
727         * if <code>next</code> has not yet been called,
728         * or <code>remove</code> has already been called after the last call to <code>next</code>.
729         */
730        public void remove()
731        {
732          if (lastCursor == -1)
733          {
734            throw new IllegalStateException();
735          }
736          checkModCount();
737    
738          try
739          {
740            AbstractEList.this.remove(lastCursor);
741            expectedModCount = modCount;
742            if (lastCursor < cursor)
743            {
744              --cursor;
745            }
746            lastCursor = -1;
747          }
748          catch (IndexOutOfBoundsException exception)
749          {
750            throw new ConcurrentModificationException();
751          }
752        }
753    
754        /**
755         * Checks that the modification count is as expected.
756         * @exception ConcurrentModificationException if the modification count is not as expected.
757         */
758        protected void checkModCount()
759        {
760          if (modCount != expectedModCount)
761          {
762            throw new ConcurrentModificationException();
763          }
764        }
765      }
766    
767      /**
768       * Returns a read-only iterator that does not {@link #resolve resolve} objects.
769       * This implementation allocates a {@link NonResolvingEIterator}.
770       * @return a read-only iterator that does not resolve objects.
771       */
772      protected Iterator<E> basicIterator()
773      {
774        return new NonResolvingEIterator<E>();
775      }
776    
777      /**
778       * An extended read-only iterator that does not {@link AbstractEList#resolve resolve} objects.
779       */
780      protected class NonResolvingEIterator<E1> extends EIterator<E1>
781      {
782        /**
783         * Returns the next object and advances the iterator.
784         * This implementation accesses the data storage directly.
785         * @return the next object.
786         * @exception NoSuchElementException if the iterator is done.
787         */
788        @Override
789        protected E doNext()
790        {
791          try
792          {
793            E next = primitiveGet(cursor);
794            checkModCount();
795            lastCursor = cursor++;
796            return next;
797          }
798          catch (IndexOutOfBoundsException exception)
799          {
800            checkModCount();
801            throw new NoSuchElementException();
802          }
803        }
804    
805        /**
806         * Throws and exception.
807         * @exception UnsupportedOperationException always because it's not supported.
808         */
809        @Override
810        public void remove()
811        {
812          throw new UnsupportedOperationException();
813        }
814      }
815    
816      /**
817       * Returns a list iterator.
818       * This implementation allocates a {@link AbstractEList.EListIterator}.
819       * @return a list iterator.
820       * @see AbstractEList.EListIterator
821       */
822      @Override
823      public ListIterator<E> listIterator()
824      {
825        return new EListIterator<E>();
826      }
827    
828      /**
829       * Returns a list iterator advanced to the given index.
830       * This implementation allocates a {@link AbstractEList.EListIterator}.
831       * @param index the starting index.
832       * @return a list iterator advanced to the index.
833       * @see AbstractEList.EListIterator
834       * @exception IndexOutOfBoundsException if the index isn't within the size range.
835       */
836      @Override
837      public ListIterator<E> listIterator(int index)
838      {
839        int size = size();
840        if (index < 0 || index > size)
841          throw new BasicIndexOutOfBoundsException(index, size);
842    
843        return new EListIterator<E>(index);
844      }
845    
846      /**
847       * An extensible list iterator implementation.
848       */
849      protected class EListIterator<E1> extends EIterator<E1> implements ListIterator<E1>
850      {
851        /**
852         * Creates an instance.
853         */
854        public EListIterator()
855        {
856          super();
857        }
858    
859        /**
860         * Creates an instance advanced to the index.
861         * @param index the starting index.
862         */
863        public EListIterator(int index)
864        {
865          cursor = index;
866        }
867    
868        /**
869         * Returns whether there are more objects for {@link #previous}.
870         * Returns whether there are more objects.
871         */
872        public boolean hasPrevious()
873        {
874          return cursor != 0;
875        }
876    
877        /**
878         * Returns the previous object and advances the iterator.
879         * This implementation delegates to {@link #doPrevious doPrevious}.
880         * @return the previous object.
881         * @exception NoSuchElementException if the iterator is done.
882         */
883        @SuppressWarnings("unchecked")
884        public E1 previous()
885        {
886          return (E1)doPrevious();
887        }
888    
889        /**
890         * Returns the previous object and advances the iterator.
891         * This implementation delegates to {@link AbstractEList#get get}.
892         * @return the previous object.
893         * @exception NoSuchElementException if the iterator is done.
894         */
895        protected E doPrevious()
896        {
897          try
898          {
899            E previous = get(--cursor);
900            checkModCount();
901            lastCursor = cursor;
902            return previous;
903          }
904          catch (IndexOutOfBoundsException exception)
905          {
906            checkModCount();
907            throw new NoSuchElementException();
908          }
909        }
910    
911        /**
912         * Returns the index of the object that would be returned by calling {@link #next() next}.
913         * @return the index of the object that would be returned by calling <code>next</code>.
914         */
915        public int nextIndex()
916        {
917          return cursor;
918        }
919    
920        /**
921         * Returns the index of the object that would be returned by calling {@link #previous previous}.
922         * @return the index of the object that would be returned by calling <code>previous</code>.
923         */
924        public int previousIndex()
925        {
926          return cursor - 1;
927        }
928    
929        /**
930         * Sets the object at the index of the last call to {@link #next() next} or {@link #previous previous}.
931         * This implementation delegates to {@link AbstractEList#set set}.
932         * @param object the object to set.
933         * @exception IllegalStateException
934         * if <code>next</code> or <code>previous</code> have not yet been called,
935         * or {@link #remove(Object) remove} or {@link #add add} have already been called
936         * after the last call to <code>next</code> or <code>previous</code>.
937         */
938        @SuppressWarnings("unchecked")
939        public void set(E1 object)
940        {
941          doSet((E)object);
942        }
943    
944        /**
945         * Sets the object at the index of the last call to {@link #next() next} or {@link #previous previous}.
946         * This implementation delegates to {@link AbstractEList#set set}.
947         * @param object the object to set.
948         * @exception IllegalStateException
949         * if <code>next</code> or <code>previous</code> have not yet been called,
950         * or {@link #remove(Object) remove} or {@link #add add} have already been called
951         * after the last call to <code>next</code> or <code>previous</code>.
952         */
953        protected void doSet(E object)
954        {
955          if (lastCursor == -1)
956          {
957            throw new IllegalStateException();
958          }
959          checkModCount();
960    
961          try
962          {
963            AbstractEList.this.set(lastCursor, object);
964          }
965          catch (IndexOutOfBoundsException exception)
966          {
967            throw new ConcurrentModificationException();
968          }
969        }
970    
971        /**
972         * Adds the object at the {@link #next() next} index and advances the iterator past it.
973         * This implementation delegates to {@link #doAdd(Object) doAdd(E)}.
974         * @param object the object to add.
975         */
976        @SuppressWarnings("unchecked")
977        public void add(E1 object)
978        {
979          doAdd((E)object);
980        }
981    
982        /**
983         * Adds the object at the {@link #next() next} index and advances the iterator past it.
984         * This implementation delegates to {@link AbstractEList#add(int, Object) add(int, E)}.
985         * @param object the object to add.
986         */
987        protected void doAdd(E object)
988        {
989          checkModCount();
990    
991          try
992          {
993            AbstractEList.this.add(cursor++, object);
994            expectedModCount = modCount;
995            lastCursor = -1;
996          }
997          catch (IndexOutOfBoundsException exception)
998          {
999            throw new ConcurrentModificationException();
1000          }
1001        }
1002      }
1003    
1004      /**
1005       * Returns a read-only list iterator that does not {@link #resolve resolve} objects.
1006       * This implementation allocates a {@link NonResolvingEListIterator}.
1007       * @return a read-only list iterator that does not resolve objects.
1008       */
1009      protected ListIterator<E> basicListIterator()
1010      {
1011        return new NonResolvingEListIterator<E>();
1012      }
1013    
1014      /**
1015       * Returns a read-only list iterator advanced to the given index that does not {@link #resolve resolve} objects.
1016       * This implementation allocates a {@link NonResolvingEListIterator}.
1017       * @param index the starting index.
1018       * @return a read-only list iterator advanced to the index.
1019       * @exception IndexOutOfBoundsException if the index isn't within the size range.
1020       */
1021      protected ListIterator<E> basicListIterator(int index)
1022      {
1023        int size = size();
1024        if (index < 0 || index > size)
1025          throw new BasicIndexOutOfBoundsException(index, size);
1026    
1027        return new NonResolvingEListIterator<E>(index);
1028      }
1029    
1030      /**
1031       * An extended read-only list iterator that does not {@link AbstractEList#resolve resolve} objects.
1032       */
1033      protected class NonResolvingEListIterator<E1> extends EListIterator<E1>
1034      {
1035        /**
1036         * Creates an instance.
1037         */
1038        public NonResolvingEListIterator()
1039        {
1040          super();
1041        }
1042    
1043        /**
1044         * Creates an instance advanced to the index.
1045         * @param index the starting index.
1046         */
1047        public NonResolvingEListIterator(int index)
1048        {
1049          super(index);
1050        }
1051    
1052        /**
1053         * Returns the next object and advances the iterator.
1054         * This implementation accesses the data storage directly.
1055         * @return the next object.
1056         * @exception NoSuchElementException if the iterator is done.
1057         */
1058        @Override
1059        protected E doNext()
1060        {
1061          try
1062          {
1063            E next = primitiveGet(cursor);
1064            checkModCount();
1065            lastCursor = cursor++;
1066            return next;
1067          }
1068          catch (IndexOutOfBoundsException exception)
1069          {
1070            checkModCount();
1071            throw new NoSuchElementException();
1072          }
1073        }
1074    
1075        /**
1076         * Returns the previous object and advances the iterator.
1077         * This implementation accesses the data storage directly.
1078         * @return the previous object.
1079         * @exception NoSuchElementException if the iterator is done.
1080         */
1081        @Override
1082        protected E doPrevious()
1083        {
1084          try
1085          {
1086            E previous = primitiveGet(--cursor);
1087            checkModCount();
1088            lastCursor = cursor;
1089            return previous;
1090          }
1091          catch (IndexOutOfBoundsException exception)
1092          {
1093            checkModCount();
1094            throw new NoSuchElementException();
1095          }
1096        }
1097    
1098        /**
1099         * Throws an exception.
1100         * @exception UnsupportedOperationException always because it's not supported.
1101         */
1102        @Override
1103        public void remove()
1104        {
1105          throw new UnsupportedOperationException();
1106        }
1107    
1108        /**
1109         * Throws an exception.
1110         * @exception UnsupportedOperationException always because it's not supported.
1111         */
1112        @Override
1113        public void set(E1 object)
1114        {
1115          throw new UnsupportedOperationException();
1116        }
1117    
1118        /**
1119         * Throws an exception.
1120         * @exception UnsupportedOperationException always because it's not supported.
1121         */
1122        @Override
1123        public void add(E1 object)
1124        {
1125          throw new UnsupportedOperationException();
1126        }
1127      }
1128    
1129      /**
1130       * Returns an <b>unsafe</b> list that provides a {@link #resolve non-resolving} view of the underlying data storage.
1131       * @return an <b>unsafe</b> list that provides a non-resolving view of the underlying data storage.
1132       */
1133      protected abstract List<E> basicList();
1134    
1135      /**
1136       * Returns the collection of objects in the given collection that are also contained by this list.
1137       * @param collection the other collection.
1138       * @return the collection of objects in the given collection that are also contained by this list.
1139       */
1140      protected Collection<E> getDuplicates(Collection<?> collection)
1141      {
1142        if (collection.isEmpty())
1143        {
1144          return ECollections.emptyEList();
1145        }
1146        else
1147        {
1148          Collection<E> filteredResult = useEquals() ? new BasicEList<E>(collection.size()) : new BasicEList.FastCompare<E>(collection.size());
1149          for (E object : this)
1150          {
1151            if (collection.contains(object))
1152            {
1153              filteredResult.add(object);
1154            }
1155          }
1156          return filteredResult;
1157        }
1158      }
1159    
1160      /**
1161       * Returns the collection of objects in the given collection that are not also contained by this list.
1162       * @param collection the other collection.
1163       * @return the collection of objects in the given collection that are not also contained by this list.
1164       */
1165      protected Collection<E> getNonDuplicates(Collection<? extends E> collection)
1166      {
1167        Collection<E> result = useEquals() ?  new UniqueEList<E>(collection.size()) : new UniqueEList.FastCompare<E>(collection.size());
1168        for (E object : collection)
1169        {
1170          if (!contains(object))
1171          {
1172            result.add(object);
1173          }
1174        }
1175        return result;
1176      }
1177    }