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