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: ArrayDelegatingEList.java,v 1.2 2009/08/25 07:58:57 emerks Exp $
016     */
017    package org.eclipse.emf.common.util;
018    
019    
020    import java.io.IOException;
021    import java.io.ObjectInputStream;
022    import java.io.ObjectOutputStream;
023    import java.io.Serializable;
024    import java.lang.reflect.Array;
025    import java.util.Collection;
026    import java.util.ConcurrentModificationException;
027    import java.util.Iterator;
028    import java.util.List;
029    import java.util.ListIterator;
030    import java.util.RandomAccess;
031    
032    
033    /**
034     * A highly extensible abstract list implementation {@link #data() logically backed by an array} that is <b>never<b> modified.
035     *
036     */
037    public abstract class ArrayDelegatingEList<E> extends AbstractEList<E> implements RandomAccess, Cloneable, Serializable
038    {
039      private static final long serialVersionUID = 1L;
040    
041      /**
042       * Creates an empty instance with no initial capacity.
043       * The data storage will be null.
044       */
045      public ArrayDelegatingEList()
046      {
047        super();
048      }
049    
050      /**
051       * Creates an instance that is a copy of the collection.
052       * @param collection the initial contents of the list.
053       */
054      public ArrayDelegatingEList(Collection<? extends E> collection)
055      {
056        // Conditionally create the data.
057        //
058        int size = collection.size();
059        if (size > 0)
060        {
061          Object [] data = newData(size);
062          collection.toArray(data);
063          setData(data);
064        }
065      }
066    
067      /**
068       * Creates an initialized instance that directly uses the given arguments.
069       * @param data the underlying storage of the list.
070       */
071      protected ArrayDelegatingEList(Object [] data)
072      {
073        setData(data);
074      }
075    
076      /**
077       * Returns new allocated data storage.
078       * Clients may override this to create typed storage.
079       * The cost of type checking via a typed array is negligible.
080       * @return new data storage.
081       */
082      protected Object [] newData(int capacity)
083      {
084        return new Object [capacity];
085      }
086      
087      /**
088       * Assigns the object into the data storage at the given index and returns the object that's been stored.
089       * Clients can monitor access to the storage via this method.
090       * @param index the position of the new content.
091       * @param object the new content.
092       * @return the object that's been stored.
093       *
094       */
095      protected E assign(Object [] data, int index, E object)
096      {
097        data[index] = object;
098        return object;
099      }
100    
101      /**
102       * Returns the number of objects in the list.
103       * @return the number of objects in the list.
104       */
105      @Override
106      public final int size()
107      {
108        Object[] data = data();
109        return data == null ? 0 : data.length;
110      }
111    
112      /**
113       * Returns whether the list has zero size.
114       * @return whether the list has zero size.
115       */
116      @Override
117      public boolean isEmpty()
118      {
119        return data() == null;
120      }
121    
122      /**
123       * Returns whether the list contains the object.
124       * This implementation uses either <code>equals</code> or <code>"=="</code> depending on {@link #useEquals useEquals}.
125       * @param object the object in question.
126       * @return whether the list contains the object.
127       * @see #useEquals
128       */
129      @Override
130      public boolean contains(Object object)
131      {
132        Object[] data = data();
133        if (data != null)
134        {
135          if (useEquals() && object != null)
136          {
137            for (Object datum : data)
138            {
139              if (object.equals(datum))
140              {
141                return true;
142              }
143            }
144          }
145          else
146          {
147            for (Object datum : data)
148            {
149              if (datum == object)
150              {
151                return true;
152              }
153            }
154          }
155        }
156    
157        return false;
158      }
159    
160      /**
161       * Returns the position of the first occurrence of the object in the list.
162       * This implementation uses either <code>equals</code> or <code>"=="</code> depending on {@link #useEquals useEquals}.
163       * @param object the object in question.
164       * @return the position of the first occurrence of the object in the list.
165       */
166      @Override
167      public int indexOf(Object object)
168      {
169        Object[] data = data();
170        if (data != null)
171        {
172          if (useEquals() && object != null)
173          {
174            for (int i = 0, size = data.length; i < size; ++i)
175            {
176              if (object.equals(data[i]))
177              {
178                return i;
179              }
180            }
181          }
182          else
183          {
184            for (int i = 0, size = data.length; i < size; ++i)
185            {
186              if (data[i] == object)
187              {
188                return i;
189              }
190            }
191          }
192        }
193        return -1;
194      }
195    
196      /**
197       * Returns the position of the last occurrence of the object in the list.
198       * This implementation uses either <code>equals</code> or <code>"=="</code> depending on {@link #useEquals useEquals}.
199       * @param object the object in question.
200       * @return the position of the last occurrence of the object in the list.
201       */
202      @Override
203      public int lastIndexOf(Object object)
204      {
205        Object[] data = data();
206        if (data != null)
207        {
208          if (useEquals() && object != null)
209          {
210            for (int i = data.length - 1; i >= 0; --i)
211            {
212              if (object.equals(data[i]))
213              {
214                return i;
215              }
216            }
217          }
218          else
219          {
220            for (int i = data.length - 1; i >= 0; --i)
221            {
222              if (data[i] == object)
223              {
224                return i;
225              }
226            }
227          }
228        }
229        return -1;
230      }
231    
232      /**
233       * Returns an array containing all the objects in sequence.
234       * Clients may override {@link #newData newData} to create typed storage in this case.
235       * @return an array containing all the objects in sequence.
236       * @see #newData
237       */
238      @Override
239      public Object[] toArray()
240      {
241        Object[] data = data();
242        int size = data == null ? 0 : data.length;
243        Object[] result = newData(size);
244    
245        // Guard for no data.
246        //
247        if (size > 0)
248        {
249          System.arraycopy(data, 0, result, 0, size);
250        }
251        return result;
252      }
253    
254      /**
255       * Returns an array containing all the objects in sequence.
256       * @param array the array that will be filled and returned, if it's big enough;
257       * otherwise, a suitably large array of the same type will be allocated and used instead.
258       * @return an array containing all the objects in sequence.
259       * @see #newData
260       */
261      @Override
262      public <T> T[] toArray(T[] array)
263      {
264        // Guard for no data.
265        //
266        Object[] data = data();
267        int size = data == null ? 0 : data.length;
268        if (size > 0)
269        {
270          if (array.length < size)
271          {
272            @SuppressWarnings("unchecked") T [] newArray = (T[])Array.newInstance(array.getClass().getComponentType(), size);
273            array  = newArray;
274          }
275    
276          System.arraycopy(data, 0, array, 0, size);
277        }
278    
279        if (array.length > size)
280        {
281          array[size] = null;
282        }
283    
284        return array;
285      }
286    
287      /**
288       * Returns direct <b>unsafe</b> access to the underlying data storage.
289       * Clients may <b>not</b> modify this array's elements
290       * but <b>may</b> assume that the array remains valid even as the list is modified.
291       * The array's length is exactly the same as the list's {@link #size() size};
292       * <code>null</code> is used to represent the empty list.
293       * @return direct <b>unsafe</b> access to the underlying data storage.
294       */
295      public abstract Object [] data();
296    
297      /**
298       * Updates directly and <b>unsafely</b> the underlying data storage.
299       * Clients <b>must</b> be aware that this subverts all callbacks
300       * and hence possibly the integrity of the list.
301       * The list implementation itself calls this method whenever a modification of the list requires a new backing array.
302       * @param data the new underlying data storage.
303       */
304      public void setData(Object [] data)
305      {
306        ++modCount;
307      }
308    
309      /**
310       * Returns the object at the index.
311       * This implementation delegates to {@link #resolve resolve}
312       * so that clients may transform the fetched object.
313       * @param index the position in question.
314       * @return the object at the index.
315       * @exception IndexOutOfBoundsException if the index isn't within the size range.
316       * @see #resolve
317       * @see #basicGet
318       */
319      @SuppressWarnings({"unchecked", "null"})
320      @Override
321      public E get(int index)
322      {
323        Object[] data = data();
324        int size = data == null ? 0 : data.length;
325        if (index >= size)
326          throw new BasicIndexOutOfBoundsException(index, size);
327    
328        return resolve(index, (E)data[index]);
329      }
330    
331      /**
332       * Returns the object at the index without {@link #resolve resolving} it.
333       * @param index the position in question.
334       * @return the object at the index.
335       * @exception IndexOutOfBoundsException if the index isn't within the size range.
336       * @see #resolve
337       * @see #get
338       */
339      @SuppressWarnings({"unchecked", "null"})
340      @Override
341      public E basicGet(int index)
342      {
343        Object[] data = data();
344        int size = data == null ? 0 : data.length;
345        if (index >= size)
346          throw new BasicIndexOutOfBoundsException(index, size);
347    
348        return (E)data[index];
349      }
350      
351      @Override
352      @SuppressWarnings({"unchecked"})
353      protected E primitiveGet(int index)
354      {
355        return (E)data()[index];
356      }
357    
358      /**
359       * Sets the object at the index
360       * and returns the old object at the index;
361       * it does no ranging checking or uniqueness checking.
362       * This implementation delegates to {@link #assign assign}, {@link #didSet didSet}, and {@link #didChange didChange}.
363       * @param index the position in question.
364       * @param object the object to set.
365       * @return the old object at the index.
366       * @see #set
367       */
368      @Override
369      public E setUnique(int index, E object)
370      {
371        Object[] data = copy();
372        @SuppressWarnings("unchecked") E oldObject = (E)data[index];
373        assign(data, index, validate(index, object));
374        setData(data);
375        didSet(index, object, oldObject);
376        didChange();
377        return oldObject;
378      }
379    
380      /**
381       * Adds the object at the end of the list;
382       * it does no uniqueness checking.
383       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
384       * after uniqueness checking.
385       * @param object the object to be added.
386       * @see #add(Object)
387       */
388      @Override
389      public void addUnique(E object)
390      {
391        int size = size();
392        Object [] data = grow(size + 1);
393        assign(data, size, validate(size, object));
394        setData(data);
395        didAdd(size, object);
396        didChange();
397      }
398    
399      /**
400       * Adds the object at the given index in the list;
401       * it does no ranging checking or uniqueness checking.
402       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
403       * @param object the object to be added.
404       * @see #add(int, Object)
405       */
406      @Override
407      public void addUnique(int index, E object)
408      {
409        Object[] oldData = data();
410        int size = oldData == null ? 0 : oldData.length;
411        Object[] data = grow(size + 1);
412        E validatedObject = validate(index, object);
413        if (index != size)
414        {
415          System.arraycopy(oldData, index, data, index + 1, size - index);
416        }
417        assign(data, index, validatedObject);
418        setData(data);
419        didAdd(index, object);
420        didChange();
421      }
422    
423      /**
424       * Adds each object of the collection to the end of the list;
425       * it does no uniqueness checking.
426       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
427       * @param collection the collection of objects to be added.
428       * @see #addAll(Collection)
429       */
430      @Override
431      public boolean addAllUnique(Collection<? extends E> collection)
432      {
433        int growth = collection.size();
434        if (growth != 0)
435        {
436          int oldSize = size();
437          int size = oldSize + growth;
438          Object[] data = grow(size);
439    
440          Iterator<? extends E> objects = collection.iterator();
441          for (int i = oldSize; i < size; ++i)
442          {
443            E object = objects.next();
444            assign(data, i, validate(i, object));
445          }
446          setData(data);
447          for (int i = oldSize; i < size; ++i)
448          {
449            @SuppressWarnings("unchecked") E object = (E)data[i];
450            didAdd(i, object);
451            didChange();
452          }
453          return true;
454        }
455        else
456        {
457          ++modCount;
458          return false;
459        }
460      }
461    
462      /**
463       * Adds each object of the collection at each successive index in the list
464       * and returns whether any objects were added;
465       * it does no ranging checking or uniqueness checking.
466       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
467       * @param index the index at which to add.
468       * @param collection the collection of objects to be added.
469       * @return whether any objects were added.
470       * @see #addAll(int, Collection)
471       */
472      @Override
473      public boolean addAllUnique(int index, Collection<? extends E> collection)
474      {
475        int growth = collection.size();
476        if (growth != 0)
477        {
478          Object[] oldData = data();
479          int oldSize = oldData == null ? 0 : oldData.length;
480          int size = oldSize + growth;
481          Object[] data = grow(size);
482    
483          int shifted = oldSize - index;
484          if (shifted > 0)
485          {
486            System.arraycopy(oldData, index, data, index + growth, shifted);
487          }
488    
489          Iterator<? extends E> objects = collection.iterator();
490          for (int i = 0; i < growth; ++i)
491          {
492            E object = objects.next();
493            int currentIndex = index + i;
494            assign(data, currentIndex, validate(currentIndex, object));
495          }
496          setData(data);
497          for (int i = 0; i < growth; ++i)
498          {
499            @SuppressWarnings("unchecked") E object = (E)data[index];
500            didAdd(index, object);
501            didChange();
502            index++;
503          }
504          return true;
505        }
506        else
507        {
508          ++modCount;
509          return false;
510        }
511      }
512    
513      /**
514       * Adds each object from start to end of the array at the index of list
515       * and returns whether any objects were added;
516       * it does no ranging checking or uniqueness checking.
517       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
518       * @param objects the objects to be added.
519       * @param start the index of first object to be added.
520       * @param end the index past the last object to be added.
521       * @return whether any objects were added.
522       * @see #addAllUnique(Object[], int, int)
523       */
524      @Override
525      public boolean addAllUnique(Object [] objects, int start, int end)
526      {
527        int growth = end - start;
528        if (growth > 0)
529        {
530          int oldSize = size();
531          int size = oldSize + growth;
532          Object[] data = grow(size);
533    
534          for (int i = start, index = size; i < end; ++i, ++index)
535          {
536            @SuppressWarnings("unchecked") E object = (E)objects[i];
537            assign(data, index, validate(index, object));
538          }
539          setData(data);
540          for (int i = start, index = size; i < end; ++i, ++index)
541          {
542            @SuppressWarnings("unchecked") E object = (E)objects[i];
543            didAdd(index, object);
544            didChange();
545          }
546          return true;
547        }
548        else
549        {
550          ++modCount;
551          return false;
552        }
553      }
554    
555      /**
556       * Adds each object from start to end of the array at each successive index in the list
557       * and returns whether any objects were added;
558       * it does no ranging checking or uniqueness checking.
559       * This implementation delegates to {@link #assign assign}, {@link #didAdd didAdd}, and {@link #didChange didChange}.
560       * @param index the index at which to add.
561       * @param objects the objects to be added.
562       * @param start the index of first object to be added.
563       * @param end the index past the last object to be added.
564       * @return whether any objects were added.
565       * @see #addAllUnique(Object[], int, int)
566       */
567      @Override
568      public boolean addAllUnique(int index, Object [] objects, int start, int end)
569      {
570        int growth = end - start;
571        if (growth > 0)
572        {
573          Object[] oldData = data();
574          int oldSize = oldData == null ? 0 : oldData.length;
575          int size = oldSize + growth;
576          Object[] data = grow(size);
577    
578          int shifted = oldSize - index;
579          if (shifted > 0)
580          {
581            System.arraycopy(oldData, index, data, index + growth, shifted);
582          }
583    
584          for (int i = start, currentIndex = index; i < end; ++i, ++currentIndex)
585          {
586            @SuppressWarnings("unchecked") E object = (E)objects[i];
587            assign(data, currentIndex, validate(currentIndex, object));
588          }
589          setData(data);
590          for (int i = start, currentIndex = index; i < end; ++i, ++currentIndex)
591          {
592            @SuppressWarnings("unchecked") E object = (E)objects[i];
593            didAdd(currentIndex, object);
594            didChange();
595          }
596          return true;
597        }
598        else
599        {
600          ++modCount;
601          return false;
602        }
603      }
604    
605      /**
606       * Removes each object of the collection from the list and returns whether any object was actually contained by the list.
607       * @param collection the collection of objects to be removed.
608       * @return whether any object was actually contained by the list.
609       */
610      @SuppressWarnings("null")
611      @Override
612      public boolean removeAll(Collection<?> collection)
613      {
614        Object[] data = data();
615        int size = data == null ? 0 : data.length;
616        boolean modified = false;
617        for (int i = size; --i >= 0; )
618        {
619          if (collection.contains(data[i]))
620          {
621            remove(i);
622            modified = true;
623          }
624        }
625    
626        return modified;
627      }
628    
629      /**
630       * Removes the object at the index from the list and returns it.
631       * This implementation delegates to {@link #didRemove didRemove} and {@link #didChange didChange}.
632       * @param index the position of the object to remove.
633       * @return the removed object.
634       * @exception IndexOutOfBoundsException if the index isn't within the size range.
635       */
636      @SuppressWarnings("null")
637      @Override
638      public E remove(int index)
639      {
640        Object[] data = data();
641        int size = data == null ? 0 : data.length;
642        if (index >= size)
643          throw new BasicIndexOutOfBoundsException(index, size);
644    
645        @SuppressWarnings("unchecked") E oldObject = (E)data[index];
646    
647        Object[] newData = newData(size - 1);
648        System.arraycopy(data, 0, newData, 0, index);
649        int shifted = size - index - 1;
650        if (shifted > 0)
651        {
652          System.arraycopy(data, index+1, newData, index, shifted);
653        }
654    
655        setData(newData);
656        didRemove(index, oldObject);
657        didChange();
658    
659        return oldObject;
660      }
661    
662      /**
663       * Removes from the list each object not contained by the collection
664       * and returns whether any object was actually removed.
665       * This delegates to {@link #remove(int) remove(int)}
666       * in the case that it finds an object that isn't retained.
667       * @param collection the collection of objects to be retained.
668       * @return whether any object was actually removed.
669       */
670      @SuppressWarnings("null")
671      @Override
672      public boolean retainAll(Collection<?> collection)
673      {
674        boolean modified = false;
675        Object[] data = data();
676        int size = data == null ? 0 : data.length;
677        for (int i = size; --i >= 0; )
678        {
679          if (!collection.contains(data[i]))
680          {
681            remove(i);
682            modified = true;
683          }
684        }
685        return modified;
686      }
687    
688      /**
689       * Clears the list of all objects.
690       * This implementation discards the data storage without modifying it
691       * and delegates to {@link #didClear didClear} and {@link #didChange didChange}.
692       */
693      @Override
694      public void clear()
695      {
696        ++modCount;
697    
698        Object[] oldData = data();
699        int oldSize = oldData == null ? 0 : oldData.length;
700    
701        // Give it all back to the garbage collector.
702        //
703        setData(null);
704    
705        didClear(oldSize, oldData);
706        didChange();
707      }
708    
709      /**
710       * Moves the object at the source index of the list to the target index of the list
711       * and returns the moved object.
712       * This implementation delegates to {@link #assign assign}, {@link #didMove didMove}, and {@link #didChange didChange}.
713       * @param targetIndex the new position for the object in the list.
714       * @param sourceIndex the old position of the object in the list.
715       * @return the moved object.
716       * @exception IndexOutOfBoundsException if either index isn't within the size range.
717       */
718      @SuppressWarnings("null")
719      @Override
720      public E move(int targetIndex, int sourceIndex)
721      {
722        Object[] data = copy();
723        int size = data == null ? 0 : data.length;
724        if (targetIndex >= size)
725          throw new IndexOutOfBoundsException("targetIndex=" + targetIndex + ", size=" + size);
726    
727        if (sourceIndex >= size)
728          throw new IndexOutOfBoundsException("sourceIndex=" + sourceIndex + ", size=" + size);
729    
730        @SuppressWarnings("unchecked") E object = (E)data[sourceIndex];
731        if (targetIndex != sourceIndex)
732        {
733          if (targetIndex < sourceIndex)
734          {
735            System.arraycopy(data, targetIndex, data, targetIndex + 1, sourceIndex - targetIndex);
736          }
737          else
738          {
739            System.arraycopy(data, sourceIndex + 1, data, sourceIndex, targetIndex - sourceIndex);
740          }
741          assign(data, targetIndex, object);
742          setData(data);
743          didMove(targetIndex, object, sourceIndex);
744          didChange();
745        }
746        return object;
747      }
748    
749      /**
750       * Grows the capacity of the list to exactly the new size.
751       */
752      protected Object[] grow(int size)
753      {
754        Object[] oldData = data();
755        Object[] data = newData(size);
756        if (oldData != null)
757        {
758          System.arraycopy(oldData, 0, data, 0, oldData.length);
759        }
760        return data;
761      }
762    
763      private static Object [] EMPTY_ARRAY = new Object [0];
764    
765      /**
766       * Returns a copy of the existing data array.
767       */
768      protected Object[] copy()
769      {
770        Object[] data = data();
771        if (data != null)
772        {
773          Object[] newData = newData(data.length);
774          System.arraycopy(data, 0, newData, 0, data.length);
775          return newData;
776        }
777        else
778        {
779          return EMPTY_ARRAY;
780        }
781      }
782    
783      private synchronized void writeObject(ObjectOutputStream objectOutputStream) throws IOException
784      {
785        objectOutputStream.defaultWriteObject();
786        Object[] data = data();
787        int size = data == null ? 0 : data.length;
788        if (data == null)
789        {
790          objectOutputStream.writeInt(0);
791        }
792        else
793        {
794          objectOutputStream.writeInt(size);
795          for (int i = 0; i < size; ++i)
796          {
797            objectOutputStream.writeObject(data[i]);
798          }
799        }
800      }
801    
802      private synchronized void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException
803      {
804        objectInputStream.defaultReadObject();
805        int size = objectInputStream.readInt();
806        Object[] data;
807        if (size > 0)
808        {
809          try
810          {
811            data = newData(size);
812          }
813          catch (Throwable exception)
814          {
815            data = new Object[size];
816          }
817    
818          setData(data);
819    
820          for (int i = 0; i < size; ++i)
821          {
822            @SuppressWarnings("unchecked") E object = (E)objectInputStream.readObject();
823            didAdd(i, assign(data, i, object));
824          }
825        }
826      }
827    
828      /**
829       * Returns a shallow copy of this list.
830       * @return a shallow copy of this list.
831       */
832      @Override
833      public Object clone()
834      {
835        try
836        {
837          @SuppressWarnings("unchecked") ArrayDelegatingEList<E> clone = (ArrayDelegatingEList<E>)super.clone();
838          Object[] data = data();
839          int size = data == null ? 0 : data.length;
840          if (size > 0)
841          {
842            Object[] newData = newData(size);
843            clone.setData(newData);
844            System.arraycopy(data, 0, newData, 0, size);
845          }
846          return clone;
847        }
848        catch (CloneNotSupportedException exception)
849        {
850          throw new InternalError();
851        }
852      }
853    
854      /**
855       * Returns an iterator.
856       * This implementation allocates a {@link ArrayDelegatingEList.EIterator}.
857       * @return an iterator.
858       * @see ArrayDelegatingEList.EIterator
859       */
860      @Override
861      public Iterator<E> iterator()
862      {
863        return new EIterator<E>();
864      }
865    
866      /**
867       * An extensible iterator implementation.
868       */
869      protected class EIterator<E1> extends AbstractEList<E>.EIterator<E1>
870      {
871        /**
872         * The expected data array of the containing list.
873         */
874        protected Object [] expectedData = data();
875    
876        /**
877         * Checks that the modification count and data array are as expected.
878         * @exception ConcurrentModificationException if the modification count is not as expected.
879         */
880        @Override
881        protected void checkModCount()
882        {
883          if (modCount != expectedModCount || data() != expectedData)
884          {
885            throw new ConcurrentModificationException();
886          }
887        }
888      }
889    
890      /**
891       * Returns a read-only iterator that does not {@link #resolve resolve} objects.
892       * This implementation allocates a {@link NonResolvingEIterator}.
893       * @return a read-only iterator that does not resolve objects.
894       */
895      @Override
896      protected Iterator<E> basicIterator()
897      {
898        return new NonResolvingEIterator<E>();
899      }
900    
901      /**
902       * An extended read-only iterator that does not {@link ArrayDelegatingEList#resolve resolve} objects.
903       */
904      protected class NonResolvingEIterator<E1> extends AbstractEList<E>.NonResolvingEIterator<E1>
905      {
906        /**
907         * The expected data array of the containing list.
908         */
909        protected Object [] expectedData = data();
910    
911        /**
912         * Checks that the modification count and data array are as expected.
913         * @exception ConcurrentModificationException if the modification count is not as expected.
914         */
915        @Override
916        protected void checkModCount()
917        {
918          if (modCount != expectedModCount || data() != expectedData)
919          {
920            throw new ConcurrentModificationException();
921          }
922        }
923      }
924    
925      /**
926       * Returns a list iterator.
927       * This implementation allocates a {@link ArrayDelegatingEList.EListIterator}.
928       * @return a list iterator.
929       * @see ArrayDelegatingEList.EListIterator
930       */
931      @Override
932      public ListIterator<E> listIterator()
933      {
934        return new EListIterator<E>();
935      }
936    
937      /**
938       * Returns a list iterator advanced to the given index.
939       * This implementation allocates a {@link ArrayDelegatingEList.EListIterator}.
940       * @param index the starting index.
941       * @return a list iterator advanced to the index.
942       * @see ArrayDelegatingEList.EListIterator
943       * @exception IndexOutOfBoundsException if the index isn't within the size range.
944       */
945      @Override
946      public ListIterator<E> listIterator(int index)
947      {
948        int size = size();
949        if (index < 0 || index > size)
950          throw new BasicIndexOutOfBoundsException(index, size);
951    
952        return new EListIterator<E>(index);
953      }
954    
955      /**
956       * An extensible list iterator implementation.
957       */
958      protected class EListIterator<E1> extends AbstractEList<E>.EListIterator<E1>
959      {
960        /**
961         * The expected data array of the containing list.
962         */
963        protected Object [] expectedData = data();
964    
965        /**
966         * Creates an instance.
967         */
968        public EListIterator()
969        {
970          super();
971        }
972    
973        /**
974         * Creates an instance advanced to the index.
975         * @param index the starting index.
976         */
977        public EListIterator(int index)
978        {
979          super(index);
980        }
981    
982        /**
983         * Checks that the modification count and data array are as expected.
984         * @exception ConcurrentModificationException if the modification count is not as expected.
985         */
986        @Override
987        protected void checkModCount()
988        {
989          if (modCount != expectedModCount || data() != expectedData)
990          {
991            throw new ConcurrentModificationException();
992          }
993        }
994      }
995    
996      /**
997       * Returns a read-only list iterator that does not {@link #resolve resolve} objects.
998       * This implementation allocates a {@link NonResolvingEListIterator}.
999       * @return a read-only list iterator that does not resolve objects.
1000       */
1001      @Override
1002      protected ListIterator<E> basicListIterator()
1003      {
1004        return new NonResolvingEListIterator<E>();
1005      }
1006    
1007      /**
1008       * Returns a read-only list iterator advanced to the given index that does not {@link #resolve resolve} objects.
1009       * This implementation allocates a {@link NonResolvingEListIterator}.
1010       * @param index the starting index.
1011       * @return a read-only list iterator advanced to the index.
1012       * @exception IndexOutOfBoundsException if the index isn't within the size range.
1013       */
1014      @Override
1015      protected ListIterator<E> basicListIterator(int index)
1016      {
1017        int size = size();
1018        if (index < 0 || index > size)
1019          throw new BasicIndexOutOfBoundsException(index, size);
1020    
1021        return new NonResolvingEListIterator<E>(index);
1022      }
1023    
1024      /**
1025       * An extended read-only list iterator that does not {@link ArrayDelegatingEList#resolve resolve} objects.
1026       */
1027      protected class NonResolvingEListIterator<E1> extends AbstractEList<E>.NonResolvingEListIterator<E1>
1028      {
1029        /**
1030         * The expected data array of the containing list.
1031         */
1032        protected Object [] expectedData = data();
1033    
1034        /**
1035         * Creates an instance.
1036         */
1037        public NonResolvingEListIterator()
1038        {
1039          super();
1040        }
1041    
1042        /**
1043         * Creates an instance advanced to the index.
1044         * @param index the starting index.
1045         */
1046        public NonResolvingEListIterator(int index)
1047        {
1048          super(index);
1049        }
1050    
1051        /**
1052         * Checks that the modification count and data array are as expected.
1053         * @exception ConcurrentModificationException if the modification count is not as expected.
1054         */
1055        @Override
1056        protected void checkModCount()
1057        {
1058          if (modCount != expectedModCount || data() != expectedData)
1059          {
1060            throw new ConcurrentModificationException();
1061          }
1062        }
1063      }
1064    
1065      /**
1066       * Returns an <b>unsafe</b> list that provides a {@link #resolve non-resolving} view of the underlying data storage.
1067       * @return an <b>unsafe</b> list that provides a non-resolving view of the underlying data storage.
1068       */
1069      @Override
1070      protected List<E> basicList()
1071      {
1072        Object[] data = data();
1073        int size = data == null ? 0 : data.length;
1074        if (size == 0)
1075        {
1076          return ECollections.emptyEList();
1077        }
1078        else
1079        {
1080          return new BasicEList.UnmodifiableEList<E>(size, data);
1081        }
1082      }
1083    }