summaryrefslogtreecommitdiffstats
path: root/libjava/java/util/AbstractList.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/util/AbstractList.java')
-rw-r--r--libjava/java/util/AbstractList.java558
1 files changed, 558 insertions, 0 deletions
diff --git a/libjava/java/util/AbstractList.java b/libjava/java/util/AbstractList.java
new file mode 100644
index 00000000000..da76a8b3104
--- /dev/null
+++ b/libjava/java/util/AbstractList.java
@@ -0,0 +1,558 @@
+/* AbstractList.java -- Abstract implementation of most of List
+ Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
+
+
+// TO DO:
+// ~ Doc comments for almost everything.
+// ~ Better general commenting
+
+package java.util;
+
+/**
+ * A basic implementation of most of the methods in the List interface to make
+ * it easier to create a List based on a random-access data structure. To
+ * create an unmodifiable list, it is only necessary to override the size() and
+ * get(int) methods (this contrasts with all other abstract collection classes
+ * which require an iterator to be provided). To make the list modifiable, the
+ * set(int, Object) method should also be overridden, and to make the list
+ * resizable, the add(int, Object) and remove(int) methods should be overridden
+ * too. Other methods should be overridden if the backing data structure allows
+ * for a more efficient implementation. The precise implementation used by
+ * AbstractList is documented, so that subclasses can tell which methods could
+ * be implemented more efficiently.
+ */
+public abstract class AbstractList extends AbstractCollection implements List {
+
+ /**
+ * A count of the number of structural modifications that have been made to
+ * the list (that is, insertions and removals).
+ */
+ protected transient int modCount = 0;
+
+ public abstract Object get(int index);
+
+ public void add(int index, Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean add(Object o) {
+ add(size(), o);
+ return true;
+ }
+
+ public boolean addAll(int index, Collection c) {
+ Iterator i = c.iterator();
+ if (i.hasNext()) {
+ do {
+ add(index++, i.next());
+ } while (i.hasNext());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void clear() {
+ removeRange(0, size());
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (!(o instanceof List)) {
+ return false;
+ } else {
+ Iterator i1 = iterator();
+ Iterator i2 = ((List)o).iterator();
+ while (i1.hasNext()) {
+ if (!i2.hasNext()) {
+ return false;
+ } else {
+ Object e = i1.next();
+ if (e == null ? i2.next() != null : !e.equals(i2.next())) {
+ return false;
+ }
+ }
+ }
+ if (i2.hasNext()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ public int hashCode() {
+ int hashCode = 1;
+ Iterator i = iterator();
+ while (i.hasNext()) {
+ Object obj = i.next();
+ hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
+ }
+ return hashCode;
+ }
+
+ public int indexOf(Object o) {
+ int index = 0;
+ ListIterator i = listIterator();
+ if (o == null) {
+ while (i.hasNext()) {
+ if (i.next() == null) {
+ return index;
+ }
+ index++;
+ }
+ } else {
+ while (i.hasNext()) {
+ if (o.equals(i.next())) {
+ return index;
+ }
+ index++;
+ }
+ }
+ return -1;
+ }
+
+ public Iterator iterator() {
+ return new Iterator() {
+ private int knownMod = modCount;
+ private int position = 0;
+ boolean removed = true;
+
+ private void checkMod() {
+ if (knownMod != modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ public boolean hasNext() {
+ checkMod();
+ return position < size();
+ }
+
+ public Object next() {
+ checkMod();
+ removed = false;
+ try {
+ return get(position++);
+ } catch (IndexOutOfBoundsException e) {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove() {
+ checkMod();
+ if (removed) {
+ throw new IllegalStateException();
+ }
+ AbstractList.this.remove(--position);
+ knownMod = modCount;
+ removed = true;
+ }
+ };
+ }
+
+ public int lastIndexOf(Object o) {
+ int index = size();
+ ListIterator i = listIterator(index);
+ if (o == null) {
+ while (i.hasPrevious()) {
+ index--;
+ if (i.previous() == null) {
+ return index;
+ }
+ }
+ } else {
+ while (i.hasPrevious()) {
+ index--;
+ if (o.equals(i.previous())) {
+ return index;
+ }
+ }
+ }
+ return -1;
+ }
+
+ public ListIterator listIterator() {
+ return listIterator(0);
+ }
+
+ public ListIterator listIterator(final int index) {
+
+ if (index < 0 || index > size()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ return new ListIterator() {
+ private int knownMod = modCount;
+ private int position = index;
+ private int lastReturned = -1;
+
+ private void checkMod() {
+ if (knownMod != modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ public boolean hasNext() {
+ checkMod();
+ return position < size();
+ }
+
+ public boolean hasPrevious() {
+ checkMod();
+ return position > 0;
+ }
+
+ public Object next() {
+ checkMod();
+ if (hasNext()) {
+ lastReturned = position++;
+ return get(lastReturned);
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public Object previous() {
+ checkMod();
+ if (hasPrevious()) {
+ lastReturned = --position;
+ return get(lastReturned);
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public int nextIndex() {
+ checkMod();
+ return position;
+ }
+
+ public int previousIndex() {
+ checkMod();
+ return position - 1;
+ }
+
+ public void remove() {
+ checkMod();
+ if (lastReturned < 0) {
+ throw new IllegalStateException();
+ }
+ AbstractList.this.remove(lastReturned);
+ knownMod = modCount;
+ position = lastReturned;
+ lastReturned = -1;
+ }
+
+ public void set(Object o) {
+ checkMod();
+ if (lastReturned < 0) {
+ throw new IllegalStateException();
+ }
+ AbstractList.this.set(lastReturned, o);
+ }
+
+ public void add(Object o) {
+ checkMod();
+ AbstractList.this.add(position++, o);
+ lastReturned = -1;
+ knownMod = modCount;
+ }
+ };
+ }
+
+ public Object remove(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Remove a subsection of the list. This is called by the clear and
+ * removeRange methods of the class which implements subList, which are
+ * difficult for subclasses to override directly. Therefore, this method
+ * should be overridden instead by the more efficient implementation, if one
+ * exists.
+ * <p>
+ * This implementation first checks for illegal or out of range arguments. It
+ * then obtains a ListIterator over the list using listIterator(fromIndex).
+ * It then calls next() and remove() on this iterator repeatedly, toIndex -
+ * fromIndex times.
+ *
+ * @param fromIndex the index, inclusive, to remove from.
+ * @param toIndex the index, exclusive, to remove to.
+ * @exception UnsupportedOperationException if this list does not support
+ * the removeRange operation.
+ * @exception IndexOutOfBoundsException if fromIndex > toIndex || fromIndex <
+ * 0 || toIndex > size().
+ */
+ protected void removeRange(int fromIndex, int toIndex) {
+ if (fromIndex > toIndex) {
+ throw new IllegalArgumentException();
+ } else if (fromIndex < 0 || toIndex > size()) {
+ throw new IndexOutOfBoundsException();
+ } else {
+ ListIterator i = listIterator(fromIndex);
+ for (int index = fromIndex; index < toIndex; index++) {
+ i.next();
+ i.remove();
+ }
+ }
+ }
+
+ public Object set(int index, Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ public List subList(final int fromIndex, final int toIndex) {
+ if (fromIndex > toIndex)
+ throw new IllegalArgumentException();
+ if (fromIndex < 0 || toIndex > size())
+ throw new IndexOutOfBoundsException();
+ return new SubList(this, fromIndex, toIndex);
+ }
+
+ static class SubList extends AbstractList {
+
+ private AbstractList backingList;
+ private int offset;
+ private int size;
+
+ public SubList(AbstractList backing, int fromIndex, int toIndex) {
+ backingList = backing;
+ upMod();
+ offset = fromIndex;
+ size = toIndex - fromIndex;
+ }
+
+ // Note that within this class two fields called modCount are inherited -
+ // one from the superclass, and one from the outer class.
+ // The code uses both these two fields and *no other* to provide fail-fast
+ // behaviour. For correct operation, the two fields should contain equal
+ // values. Therefore, if this.modCount != backingList.modCount, there
+ // has been a concurrent modification. This is all achieved purely by using
+ // the modCount field, precisely according to the docs of AbstractList.
+ // See the methods upMod and checkMod.
+
+ /**
+ * This method checks the two modCount fields to ensure that there has
+ * not been a concurrent modification. It throws an exception if there
+ * has been, and otherwise returns normally.
+ * Note that since this method is private, it will be inlined.
+ *
+ * @exception ConcurrentModificationException if there has been a
+ * concurrent modification.
+ */
+ private void checkMod() {
+ if (this.modCount != backingList.modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ /**
+ * This method is called after every method that causes a structural
+ * modification to the backing list. It updates the local modCount field
+ * to match that of the backing list.
+ * Note that since this method is private, it will be inlined.
+ */
+ private void upMod() {
+ this.modCount = backingList.modCount;
+ }
+
+ /**
+ * This method checks that a value is between 0 and size (inclusive). If
+ * it is not, an exception is thrown.
+ * Note that since this method is private, it will be inlined.
+ *
+ * @exception IndexOutOfBoundsException if the value is out of range.
+ */
+ private void checkBoundsInclusive(int index) {
+ if (index < 0 || index > size) {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * This method checks that a value is between 0 (inclusive) and size
+ * (exclusive). If it is not, an exception is thrown.
+ * Note that since this method is private, it will be inlined.
+ *
+ * @exception IndexOutOfBoundsException if the value is out of range.
+ */
+ private void checkBoundsExclusive(int index) {
+ if (index < 0 || index >= size) {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public int size() {
+ checkMod();
+ return size;
+ }
+
+ public Iterator iterator() {
+ return listIterator();
+ }
+
+ public ListIterator listIterator(final int index) {
+
+ checkMod();
+ checkBoundsInclusive(index);
+
+ return new ListIterator() {
+ ListIterator i = backingList.listIterator(index + offset);
+ int position = index;
+
+ public boolean hasNext() {
+ checkMod();
+ return position < size;
+ }
+
+ public boolean hasPrevious() {
+ checkMod();
+ return position > 0;
+ }
+
+ public Object next() {
+ if (position < size) {
+ Object o = i.next();
+ position++;
+ return o;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public Object previous() {
+ if (position > 0) {
+ Object o = i.previous();
+ position--;
+ return o;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public int nextIndex() {
+ return offset + i.nextIndex();
+ }
+
+ public int previousIndex() {
+ return offset + i.previousIndex();
+ }
+
+ public void remove() {
+ i.remove();
+ upMod();
+ size--;
+ position = nextIndex();
+ }
+
+ public void set(Object o) {
+ i.set(o);
+ }
+
+ public void add(Object o) {
+ i.add(o);
+ upMod();
+ size++;
+ position++;
+ }
+
+ // Here is the reason why the various modCount fields are mostly
+ // ignored in this wrapper listIterator.
+ // IF the backing listIterator is failfast, then the following holds:
+ // Using any other method on this list will call a corresponding
+ // method on the backing list *after* the backing listIterator
+ // is created, which will in turn cause a ConcurrentModException
+ // when this listIterator comes to use the backing one. So it is
+ // implicitly failfast.
+ // If the backing listIterator is NOT failfast, then the whole of
+ // this list isn't failfast, because the modCount field of the
+ // backing list is not valid. It would still be *possible* to
+ // make the iterator failfast wrt modifications of the sublist
+ // only, but somewhat pointless when the list can be changed under
+ // us.
+ // Either way, no explicit handling of modCount is needed.
+ // However upMod() must be called in add and remove, and size
+ // must also be updated in these two methods, since they do not go
+ // through the corresponding methods of the subList.
+
+ };
+ }
+
+ public Object set(int index, Object o) {
+ checkMod();
+ checkBoundsExclusive(index);
+ o = backingList.set(index + offset, o);
+ upMod();
+ return o;
+ }
+
+ public Object get(int index) {
+ checkMod();
+ checkBoundsExclusive(index);
+ return backingList.get(index + offset);
+ }
+
+ public void add(int index, Object o) {
+ checkMod();
+ checkBoundsInclusive(index);
+ backingList.add(index + offset, o);
+ upMod();
+ size++;
+ }
+
+ public Object remove(int index) {
+ checkMod();
+ checkBoundsExclusive(index);
+ Object o = backingList.remove(index + offset);
+ upMod();
+ size--;
+ return o;
+ }
+
+ public void removeRange(int fromIndex, int toIndex) {
+ checkMod();
+ checkBoundsExclusive(fromIndex);
+ checkBoundsInclusive(toIndex);
+
+ // this call will catch the toIndex < fromIndex condition
+ backingList.removeRange(offset + fromIndex, offset + toIndex);
+ upMod();
+ size -= toIndex - fromIndex;
+ }
+
+ public boolean addAll(int index, Collection c) {
+ checkMod();
+ checkBoundsInclusive(index);
+ int s = backingList.size();
+ boolean result = backingList.addAll(offset + index, c);
+ upMod();
+ size += backingList.size() - s;
+ return result;
+ }
+ }
+}
OpenPOWER on IntegriCloud