1 /* AbstractList.java -- Abstract implementation of most of List
2 Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 As a special exception, if you link this library with other files to
22 produce an executable, this library does not by itself cause the
23 resulting executable to be covered by the GNU General Public License.
24 This exception does not however invalidate any other reasons why the
25 executable file might be covered by the GNU General Public License. */
29 // ~ Doc comments for almost everything.
30 // ~ Better general commenting
35 * A basic implementation of most of the methods in the List interface to make
36 * it easier to create a List based on a random-access data structure. To
37 * create an unmodifiable list, it is only necessary to override the size() and
38 * get(int) methods (this contrasts with all other abstract collection classes
39 * which require an iterator to be provided). To make the list modifiable, the
40 * set(int, Object) method should also be overridden, and to make the list
41 * resizable, the add(int, Object) and remove(int) methods should be overridden
42 * too. Other methods should be overridden if the backing data structure allows
43 * for a more efficient implementation. The precise implementation used by
44 * AbstractList is documented, so that subclasses can tell which methods could
45 * be implemented more efficiently.
47 public abstract class AbstractList extends AbstractCollection implements List {
50 * A count of the number of structural modifications that have been made to
51 * the list (that is, insertions and removals).
53 protected transient int modCount = 0;
55 public abstract Object get(int index);
57 public void add(int index, Object o) {
58 throw new UnsupportedOperationException();
61 public boolean add(Object o) {
66 public boolean addAll(int index, Collection c) {
67 Iterator i = c.iterator();
70 add(index++, i.next());
71 } while (i.hasNext());
79 removeRange(0, size());
82 public boolean equals(Object o) {
85 } else if (!(o instanceof List)) {
88 Iterator i1 = iterator();
89 Iterator i2 = ((List)o).iterator();
90 while (i1.hasNext()) {
95 if (e == null ? i2.next() != null : !e.equals(i2.next())) {
108 public int hashCode() {
110 Iterator i = iterator();
111 while (i.hasNext()) {
112 Object obj = i.next();
113 hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
118 public int indexOf(Object o) {
120 ListIterator i = listIterator();
122 while (i.hasNext()) {
123 if (i.next() == null) {
129 while (i.hasNext()) {
130 if (o.equals(i.next())) {
139 public Iterator iterator() {
140 return new Iterator() {
141 private int knownMod = modCount;
142 private int position = 0;
143 boolean removed = true;
145 private void checkMod() {
146 if (knownMod != modCount) {
147 throw new ConcurrentModificationException();
151 public boolean hasNext() {
153 return position < size();
156 public Object next() {
160 return get(position++);
161 } catch (IndexOutOfBoundsException e) {
162 throw new NoSuchElementException();
166 public void remove() {
169 throw new IllegalStateException();
171 AbstractList.this.remove(--position);
178 public int lastIndexOf(Object o) {
180 ListIterator i = listIterator(index);
182 while (i.hasPrevious()) {
184 if (i.previous() == null) {
189 while (i.hasPrevious()) {
191 if (o.equals(i.previous())) {
199 public ListIterator listIterator() {
200 return listIterator(0);
203 public ListIterator listIterator(final int index) {
205 if (index < 0 || index > size()) {
206 throw new IndexOutOfBoundsException();
209 return new ListIterator() {
210 private int knownMod = modCount;
211 private int position = index;
212 private int lastReturned = -1;
214 private void checkMod() {
215 if (knownMod != modCount) {
216 throw new ConcurrentModificationException();
220 public boolean hasNext() {
222 return position < size();
225 public boolean hasPrevious() {
230 public Object next() {
233 lastReturned = position++;
234 return get(lastReturned);
236 throw new NoSuchElementException();
240 public Object previous() {
243 lastReturned = --position;
244 return get(lastReturned);
246 throw new NoSuchElementException();
250 public int nextIndex() {
255 public int previousIndex() {
260 public void remove() {
262 if (lastReturned < 0) {
263 throw new IllegalStateException();
265 AbstractList.this.remove(lastReturned);
267 position = lastReturned;
271 public void set(Object o) {
273 if (lastReturned < 0) {
274 throw new IllegalStateException();
276 AbstractList.this.set(lastReturned, o);
279 public void add(Object o) {
281 AbstractList.this.add(position++, o);
288 public Object remove(int index) {
289 throw new UnsupportedOperationException();
293 * Remove a subsection of the list. This is called by the clear and
294 * removeRange methods of the class which implements subList, which are
295 * difficult for subclasses to override directly. Therefore, this method
296 * should be overridden instead by the more efficient implementation, if one
299 * This implementation first checks for illegal or out of range arguments. It
300 * then obtains a ListIterator over the list using listIterator(fromIndex).
301 * It then calls next() and remove() on this iterator repeatedly, toIndex -
304 * @param fromIndex the index, inclusive, to remove from.
305 * @param toIndex the index, exclusive, to remove to.
306 * @exception UnsupportedOperationException if this list does not support
307 * the removeRange operation.
308 * @exception IndexOutOfBoundsException if fromIndex > toIndex || fromIndex <
309 * 0 || toIndex > size().
311 protected void removeRange(int fromIndex, int toIndex) {
312 if (fromIndex > toIndex) {
313 throw new IllegalArgumentException();
314 } else if (fromIndex < 0 || toIndex > size()) {
315 throw new IndexOutOfBoundsException();
317 ListIterator i = listIterator(fromIndex);
318 for (int index = fromIndex; index < toIndex; index++) {
325 public Object set(int index, Object o) {
326 throw new UnsupportedOperationException();
329 public List subList(final int fromIndex, final int toIndex) {
330 if (fromIndex > toIndex)
331 throw new IllegalArgumentException();
332 if (fromIndex < 0 || toIndex > size())
333 throw new IndexOutOfBoundsException();
334 return new SubList(this, fromIndex, toIndex);
337 static class SubList extends AbstractList {
339 private AbstractList backingList;
343 public SubList(AbstractList backing, int fromIndex, int toIndex) {
344 backingList = backing;
347 size = toIndex - fromIndex;
350 // Note that within this class two fields called modCount are inherited -
351 // one from the superclass, and one from the outer class.
352 // The code uses both these two fields and *no other* to provide fail-fast
353 // behaviour. For correct operation, the two fields should contain equal
354 // values. Therefore, if this.modCount != backingList.modCount, there
355 // has been a concurrent modification. This is all achieved purely by using
356 // the modCount field, precisely according to the docs of AbstractList.
357 // See the methods upMod and checkMod.
360 * This method checks the two modCount fields to ensure that there has
361 * not been a concurrent modification. It throws an exception if there
362 * has been, and otherwise returns normally.
363 * Note that since this method is private, it will be inlined.
365 * @exception ConcurrentModificationException if there has been a
366 * concurrent modification.
368 private void checkMod() {
369 if (this.modCount != backingList.modCount) {
370 throw new ConcurrentModificationException();
375 * This method is called after every method that causes a structural
376 * modification to the backing list. It updates the local modCount field
377 * to match that of the backing list.
378 * Note that since this method is private, it will be inlined.
380 private void upMod() {
381 this.modCount = backingList.modCount;
385 * This method checks that a value is between 0 and size (inclusive). If
386 * it is not, an exception is thrown.
387 * Note that since this method is private, it will be inlined.
389 * @exception IndexOutOfBoundsException if the value is out of range.
391 private void checkBoundsInclusive(int index) {
392 if (index < 0 || index > size) {
393 throw new IndexOutOfBoundsException();
398 * This method checks that a value is between 0 (inclusive) and size
399 * (exclusive). If it is not, an exception is thrown.
400 * Note that since this method is private, it will be inlined.
402 * @exception IndexOutOfBoundsException if the value is out of range.
404 private void checkBoundsExclusive(int index) {
405 if (index < 0 || index >= size) {
406 throw new IndexOutOfBoundsException();
415 public Iterator iterator() {
416 return listIterator();
419 public ListIterator listIterator(final int index) {
422 checkBoundsInclusive(index);
424 return new ListIterator() {
425 ListIterator i = backingList.listIterator(index + offset);
426 int position = index;
428 public boolean hasNext() {
430 return position < size;
433 public boolean hasPrevious() {
438 public Object next() {
439 if (position < size) {
444 throw new NoSuchElementException();
448 public Object previous() {
450 Object o = i.previous();
454 throw new NoSuchElementException();
458 public int nextIndex() {
459 return offset + i.nextIndex();
462 public int previousIndex() {
463 return offset + i.previousIndex();
466 public void remove() {
470 position = nextIndex();
473 public void set(Object o) {
477 public void add(Object o) {
484 // Here is the reason why the various modCount fields are mostly
485 // ignored in this wrapper listIterator.
486 // IF the backing listIterator is failfast, then the following holds:
487 // Using any other method on this list will call a corresponding
488 // method on the backing list *after* the backing listIterator
489 // is created, which will in turn cause a ConcurrentModException
490 // when this listIterator comes to use the backing one. So it is
491 // implicitly failfast.
492 // If the backing listIterator is NOT failfast, then the whole of
493 // this list isn't failfast, because the modCount field of the
494 // backing list is not valid. It would still be *possible* to
495 // make the iterator failfast wrt modifications of the sublist
496 // only, but somewhat pointless when the list can be changed under
498 // Either way, no explicit handling of modCount is needed.
499 // However upMod() must be called in add and remove, and size
500 // must also be updated in these two methods, since they do not go
501 // through the corresponding methods of the subList.
506 public Object set(int index, Object o) {
508 checkBoundsExclusive(index);
509 o = backingList.set(index + offset, o);
514 public Object get(int index) {
516 checkBoundsExclusive(index);
517 return backingList.get(index + offset);
520 public void add(int index, Object o) {
522 checkBoundsInclusive(index);
523 backingList.add(index + offset, o);
528 public Object remove(int index) {
530 checkBoundsExclusive(index);
531 Object o = backingList.remove(index + offset);
537 public void removeRange(int fromIndex, int toIndex) {
539 checkBoundsExclusive(fromIndex);
540 checkBoundsInclusive(toIndex);
542 // this call will catch the toIndex < fromIndex condition
543 backingList.removeRange(offset + fromIndex, offset + toIndex);
545 size -= toIndex - fromIndex;
548 public boolean addAll(int index, Collection c) {
550 checkBoundsInclusive(index);
551 int s = backingList.size();
552 boolean result = backingList.addAll(offset + index, c);
554 size += backingList.size() - s;