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 }