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