Commit 7177dab5 by Bryce McKinlay Committed by Bryce McKinlay

AbstractList.java: Throw messages with IndexOutOfBoundsExceptions.

2000-11-02  Bryce McKinlay  <bryce@albatross.co.nz>

	* java/util/AbstractList.java: Throw messages with
	IndexOutOfBoundsExceptions.
	 (listIterator()): Call listIterator(0).
	(size): New field. Initialize to size().
	(hasNext): Test position against size, not size().
	(remove): Increment knownMod by one instead of resetting it from
	modCount.
	(add): Ditto.
	(SubList.upMod): Removed.
	(SubList.set): Don't call upMod() or update knownMod.
	(SubList.add(int,Object)): Increment modCount instead of calling
	upMod().
	(SubList.remove): Ditto.
	(SubList.addAll): Don't call backingList.size(). Increment size from
	c.size().
	(SubList.iterator): New method. Call listIterator(0).
	(SubList.listIterator): New method. Restore code to return an
	anonymous listIterator implementation (with some changes).
	* java/util/AbstractSequentialList.java: Throw messages with
	IndexOutOfBoundsExceptions.
	(addAll): Add a specnote.
	* java/util/ArrayList.java (removeRange): Get the math right.
	(addAll): Increment modCount _before_ creating iterator.
	* java/util/LinkedList.java: Rewritten, mostly.

From-SVN: r37203
parent 17e2e7f9
2000-11-02 Bryce McKinlay <bryce@albatross.co.nz>
* java/util/AbstractList.java: Throw messages with
IndexOutOfBoundsExceptions.
(listIterator()): Call listIterator(0).
(size): New field. Initialize to size().
(hasNext): Test position against size, not size().
(remove): Increment knownMod by one instead of resetting it from
modCount.
(add): Ditto.
(SubList.upMod): Removed.
(SubList.set): Don't call upMod() or update knownMod.
(SubList.add(int,Object)): Increment modCount instead of caling upMod().
(SubList.remove): Ditto.
(SubList.addAll): Don't call backingList.size(). Increment size from
c.size().
(SubList.iterator): New method. Call listIterator(0).
(SubList.listIterator): New method. Restore code to return an anonymous
listIterator implementation (with some changes).
* java/util/AbstractSequentialList.java: Throw messages with
IndexOutOfBoundsExceptions.
(addAll): Add a specnote.
* java/util/ArrayList.java (removeRange): Get the math right.
(addAll): Increment modCount _before_ creating iterator.
* java/util/LinkedList.java: Rewritten, mostly.
2000-11-01 Tom Tromey <tromey@cygnus.com> 2000-11-01 Tom Tromey <tromey@cygnus.com>
* scripts/encodings.pl: Added `ASCII' alias. * scripts/encodings.pl: Added `ASCII' alias.
......
...@@ -145,15 +145,22 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -145,15 +145,22 @@ public abstract class AbstractList extends AbstractCollection implements List
return -1; return -1;
} }
/**
* Return an Iterator over this List. This implementation calls
* listIterator(0).
*
* @return an Iterator over this List
*/
public ListIterator listIterator() public ListIterator listIterator()
{ {
return new AbstractListItr(0); return listIterator(0);
} }
public ListIterator listIterator(int index) public ListIterator listIterator(int index)
{ {
if (index < 0 || index > size()) if (index < 0 || index > size())
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size());
return new AbstractListItr(index); return new AbstractListItr(index);
} }
...@@ -193,10 +200,10 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -193,10 +200,10 @@ public abstract class AbstractList extends AbstractCollection implements List
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public List subList(final int fromIndex, final int toIndex) public List subList(int fromIndex, int toIndex)
{ {
if (fromIndex > toIndex) if (fromIndex > toIndex)
throw new IllegalArgumentException(); throw new IllegalArgumentException(fromIndex + " > " + toIndex);
if (fromIndex < 0 || toIndex > size()) if (fromIndex < 0 || toIndex > size())
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
...@@ -208,6 +215,7 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -208,6 +215,7 @@ public abstract class AbstractList extends AbstractCollection implements List
private int knownMod = modCount; private int knownMod = modCount;
private int position; private int position;
private int lastReturned = -1; private int lastReturned = -1;
private int size = size();
AbstractListItr(int start_pos) AbstractListItr(int start_pos)
{ {
...@@ -223,7 +231,7 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -223,7 +231,7 @@ public abstract class AbstractList extends AbstractCollection implements List
public boolean hasNext() public boolean hasNext()
{ {
checkMod(); checkMod();
return position < size(); return position < size;
} }
public boolean hasPrevious() public boolean hasPrevious()
...@@ -235,7 +243,7 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -235,7 +243,7 @@ public abstract class AbstractList extends AbstractCollection implements List
public Object next() public Object next()
{ {
checkMod(); checkMod();
if (position < size()) if (position < size)
{ {
lastReturned = position++; lastReturned = position++;
return get(lastReturned); return get(lastReturned);
...@@ -280,7 +288,7 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -280,7 +288,7 @@ public abstract class AbstractList extends AbstractCollection implements List
throw new IllegalStateException(); throw new IllegalStateException();
} }
AbstractList.this.remove(lastReturned); AbstractList.this.remove(lastReturned);
knownMod = modCount; knownMod++;
position = lastReturned; position = lastReturned;
lastReturned = -1; lastReturned = -1;
} }
...@@ -298,7 +306,7 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -298,7 +306,7 @@ public abstract class AbstractList extends AbstractCollection implements List
checkMod(); checkMod();
AbstractList.this.add(position++, o); AbstractList.this.add(position++, o);
lastReturned = -1; lastReturned = -1;
knownMod = modCount; knownMod++;
} }
} // AbstractList.Iterator } // AbstractList.Iterator
...@@ -311,7 +319,9 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -311,7 +319,9 @@ public abstract class AbstractList extends AbstractCollection implements List
public SubList(AbstractList backing, int fromIndex, int toIndex) public SubList(AbstractList backing, int fromIndex, int toIndex)
{ {
backingList = backing; backingList = backing;
upMod(); // FIXME: The `this' prefixes in this class are a workaround for a
// gcj bug. They should be removed later.
this.modCount = backingList.modCount;
offset = fromIndex; offset = fromIndex;
size = toIndex - fromIndex; size = toIndex - fromIndex;
} }
...@@ -332,17 +342,6 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -332,17 +342,6 @@ public abstract class AbstractList extends AbstractCollection implements List
} }
/** /**
* 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 * This method checks that a value is between 0 and size (inclusive). If
* it is not, an exception is thrown. * it is not, an exception is thrown.
* Note that since this method is private, it will be inlined. * Note that since this method is private, it will be inlined.
...@@ -352,7 +351,8 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -352,7 +351,8 @@ public abstract class AbstractList extends AbstractCollection implements List
private void checkBoundsInclusive(int index) private void checkBoundsInclusive(int index)
{ {
if (index < 0 || index > size) if (index < 0 || index > size)
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
} }
/** /**
...@@ -365,7 +365,8 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -365,7 +365,8 @@ public abstract class AbstractList extends AbstractCollection implements List
private void checkBoundsExclusive(int index) private void checkBoundsExclusive(int index)
{ {
if (index < 0 || index >= size) if (index < 0 || index >= size)
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
} }
public int size() public int size()
...@@ -379,7 +380,6 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -379,7 +380,6 @@ public abstract class AbstractList extends AbstractCollection implements List
checkMod(); checkMod();
checkBoundsExclusive(index); checkBoundsExclusive(index);
o = backingList.set(index + offset, o); o = backingList.set(index + offset, o);
upMod();
return o; return o;
} }
...@@ -395,7 +395,7 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -395,7 +395,7 @@ public abstract class AbstractList extends AbstractCollection implements List
checkMod(); checkMod();
checkBoundsInclusive(index); checkBoundsInclusive(index);
backingList.add(index + offset, o); backingList.add(index + offset, o);
upMod(); this.modCount++;
size++; size++;
} }
...@@ -404,7 +404,7 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -404,7 +404,7 @@ public abstract class AbstractList extends AbstractCollection implements List
checkMod(); checkMod();
checkBoundsExclusive(index); checkBoundsExclusive(index);
Object o = backingList.remove(index + offset); Object o = backingList.remove(index + offset);
upMod(); this.modCount++;
size--; size--;
return o; return o;
} }
...@@ -417,7 +417,7 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -417,7 +417,7 @@ public abstract class AbstractList extends AbstractCollection implements List
// this call will catch the toIndex < fromIndex condition // this call will catch the toIndex < fromIndex condition
backingList.removeRange(offset + fromIndex, offset + toIndex); backingList.removeRange(offset + fromIndex, offset + toIndex);
upMod(); this.modCount = backingList.modCount;
size -= toIndex - fromIndex; size -= toIndex - fromIndex;
} }
...@@ -425,11 +425,114 @@ public abstract class AbstractList extends AbstractCollection implements List ...@@ -425,11 +425,114 @@ public abstract class AbstractList extends AbstractCollection implements List
{ {
checkMod(); checkMod();
checkBoundsInclusive(index); checkBoundsInclusive(index);
int s = backingList.size(); int csize = c.size();
boolean result = backingList.addAll(offset + index, c); boolean result = backingList.addAll(offset + index, c);
upMod(); this.modCount = backingList.modCount;
size += backingList.size() - s; size += csize;
return result; return result;
} }
public Iterator iterator()
{
return listIterator(0);
}
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();
SubList.this.modCount++;
size--;
position = nextIndex();
}
public void set(Object o)
{
i.set(o);
}
public void add(Object o)
{
i.add(o);
SubList.this.modCount++;
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 modCount++ must be executed 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.
};
}
} // AbstractList.SubList } // AbstractList.SubList
} }
...@@ -64,6 +64,12 @@ public abstract class AbstractSequentialList extends AbstractList ...@@ -64,6 +64,12 @@ public abstract class AbstractSequentialList extends AbstractList
i.add(o); i.add(o);
} }
/**
* @specnote The spec in the JDK1.3 online docs is wrong. The implementation
* should not call next() to skip over new elements as they are
* added, because iterator.add() should add new elements BEFORE
* the cursor.
*/
public boolean addAll(int index, Collection c) public boolean addAll(int index, Collection c)
{ {
boolean modified = false; boolean modified = false;
...@@ -81,7 +87,8 @@ public abstract class AbstractSequentialList extends AbstractList ...@@ -81,7 +87,8 @@ public abstract class AbstractSequentialList extends AbstractList
{ {
ListIterator i = listIterator(index); ListIterator i = listIterator(index);
if (index < 0 || index > size()) if (index < 0 || index > size())
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size());
return i.next(); return i.next();
} }
...@@ -100,7 +107,8 @@ public abstract class AbstractSequentialList extends AbstractList ...@@ -100,7 +107,8 @@ public abstract class AbstractSequentialList extends AbstractList
{ {
ListIterator i = listIterator(index); ListIterator i = listIterator(index);
if (index < 0 || index > size()) if (index < 0 || index > size())
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size());
Object removed = i.next(); Object removed = i.next();
i.remove(); i.remove();
return removed; return removed;
...@@ -110,7 +118,8 @@ public abstract class AbstractSequentialList extends AbstractList ...@@ -110,7 +118,8 @@ public abstract class AbstractSequentialList extends AbstractList
{ {
ListIterator i = listIterator(index); ListIterator i = listIterator(index);
if (index < 0 || index > size()) if (index < 0 || index > size())
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size());
Object old = i.next(); Object old = i.next();
i.set(o); i.set(o);
return old; return old;
......
...@@ -43,7 +43,7 @@ import java.io.ObjectStreamField; ...@@ -43,7 +43,7 @@ import java.io.ObjectStreamField;
* to or removing from the end of a list, checking the size, &c. * to or removing from the end of a list, checking the size, &c.
* *
* @author Jon A. Zeppieri * @author Jon A. Zeppieri
* @version $Id: ArrayList.java,v 1.6 2000/10/26 10:19:00 bryce Exp $ * @version $Id: ArrayList.java,v 1.2 2000/10/29 05:06:10 bryce Exp $
* @see java.util.AbstractList * @see java.util.AbstractList
* @see java.util.List * @see java.util.List
*/ */
...@@ -187,7 +187,7 @@ public class ArrayList extends AbstractList ...@@ -187,7 +187,7 @@ public class ArrayList extends AbstractList
if (fromIndex != toIndex) if (fromIndex != toIndex)
{ {
System.arraycopy(data, toIndex, data, fromIndex, size - toIndex); System.arraycopy(data, toIndex, data, fromIndex, size - toIndex);
size -= (fromIndex - toIndex); size -= (toIndex - fromIndex);
} }
} }
...@@ -219,9 +219,9 @@ public class ArrayList extends AbstractList ...@@ -219,9 +219,9 @@ public class ArrayList extends AbstractList
*/ */
public boolean addAll(Collection c) public boolean addAll(Collection c)
{ {
modCount++;
Iterator itr = c.iterator(); Iterator itr = c.iterator();
int csize = c.size(); int csize = c.size();
modCount++;
ensureCapacity(size + csize); ensureCapacity(size + csize);
for (int pos = 0; pos < csize; pos++) for (int pos = 0; pos < csize; pos++)
{ {
...@@ -240,13 +240,13 @@ public class ArrayList extends AbstractList ...@@ -240,13 +240,13 @@ public class ArrayList extends AbstractList
*/ */
public boolean addAll(int index, Collection c) public boolean addAll(int index, Collection c)
{ {
Iterator itr = c.iterator();
int csize = c.size();
modCount++;
if (index < 0 || index > size) if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size); size);
modCount++;
Iterator itr = c.iterator();
int csize = c.size();
ensureCapacity(size + csize); ensureCapacity(size + csize);
int end = index + csize; int end = index + csize;
if (size > 0 && index != size) if (size > 0 && index != size)
......
...@@ -30,11 +30,12 @@ import java.io.Serializable; ...@@ -30,11 +30,12 @@ import java.io.Serializable;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Array;
// TO DO: // TO DO:
// ~ Doc comment for the class. // ~ Doc comment for the class.
// ~ Doc comments for the non-list methods. // ~ Doc comments for the non-list methods.
// ~ Some commenting on the Backing API and other general implementation notes. // ~ other general implementation notes.
/** /**
* Linked list implementation of the List interface. * Linked list implementation of the List interface.
...@@ -49,7 +50,8 @@ public class LinkedList extends AbstractSequentialList ...@@ -49,7 +50,8 @@ public class LinkedList extends AbstractSequentialList
* previous field) of the list. The data field is null. If the list is empty, * previous field) of the list. The data field is null. If the list is empty,
* both the head and the tail point to ends itself. * both the head and the tail point to ends itself.
*/ */
transient Entry ends = new Entry(); transient Entry first;
transient Entry last;
/** /**
* The current length of the list. * The current length of the list.
...@@ -59,217 +61,15 @@ public class LinkedList extends AbstractSequentialList ...@@ -59,217 +61,15 @@ public class LinkedList extends AbstractSequentialList
/** /**
* Class to represent an entry in the list. Holds a single element. * Class to represent an entry in the list. Holds a single element.
*/ */
private static class Entry { private static class Entry
{
/** Object data;
* The list element.
*/
Object data = null;
/**
* The next entry in the list. If this is the last entry in the list, the
* ends field of the list is held here.
*/
Entry next;
/**
* The previous entry in the list. If this is the first entry in the list,
* the ends field of the list is held here.
*/
Entry previous;
/**
* Create an entry with given data and linkage.
*/
Entry(Object d, Entry n, Entry p) {
data = d;
next = n;
previous = p;
}
/**
* Create an entry with no data and linking to itself, for use as the ends
* field of the list.
*/
Entry() {
next = previous = this;
}
/**
* Remove this entry.
*/
Object remove() {
previous.next = next;
next.previous = previous;
return data;
}
}
private static interface Backing {
void checkMod(int known);
void upMod();
void incSize(int by);
void decSize(int by);
}
private final Backing back = new Backing() {
public void checkMod(int known) {
if (known != modCount) {
throw new ConcurrentModificationException();
}
}
public void upMod() {
modCount++;
}
public void incSize(int by) {
size += by;
}
public void decSize(int by) {
size -= by;
}
};
/** A ListIterator over the list. This class keeps track of its
* position in the list, the size of the list, and the two list
* entries it is between. This enables it to be used identically
* for both the list itself and a sublist of the list.
*/
private static class Iter implements ListIterator {
/**
* The index of the element that will be returned by next().
*/
int pos;
/**
* The size of the backing list.
*/
int size;
/**
* The entry containing the element that will be returned by next().
*/
Entry next; Entry next;
/**
* The entry containing the element that will be returned by previous().
*/
Entry previous; Entry previous;
/** Entry(Object data)
* The entry that will be affected by remove() or set(). {
*/ this.data = data;
Entry recent;
/**
* The known value of the modCount of the backing list.
*/
int knownMod;
private final Backing b;
/**
* Create a new Iter starting at a given Entry within the list, at a given
* position, in a list of given size.
*
* @param index the index to begin iteration.
* @exception IndexOutOfBoundsException if index < 0 || index > size.
*/
Iter(Backing backing, Entry n, int index, int s, int modCount) {
b = backing;
pos = index;
size = s;
next = n;
previous = n.previous;
knownMod = modCount;
}
public int nextIndex() {
b.checkMod(knownMod);
return pos;
}
public int previousIndex() {
b.checkMod(knownMod);
return pos - 1;
}
public boolean hasNext() {
b.checkMod(knownMod);
return pos < size;
}
public boolean hasPrevious() {
b.checkMod(knownMod);
return pos > 0;
}
public Object next() {
b.checkMod(knownMod);
if (pos >= size) {
throw new NoSuchElementException();
} else {
pos++;
recent = previous = next;
next = recent.next;
return recent.data;
}
}
public Object previous() {
b.checkMod(knownMod);
if (pos <= 0) {
throw new NoSuchElementException();
} else {
pos--;
recent = next = previous;
previous = recent.previous;
return recent.data;
}
}
public void remove() {
b.checkMod(knownMod);
if (recent == null) {
throw new IllegalStateException();
}
// Adjust the position to before the removed element
if (recent == previous) pos--;
// Could use recent.remove() but this way is quicker, and also correctly
// fixes next and previous.
next = recent.previous.next = recent.next;
previous = recent.next.previous = recent.previous;
size--;
b.decSize(1);
knownMod++;
b.upMod();
recent = null;
}
public void add(Object o) {
b.checkMod(knownMod);
previous.next = next.previous = new Entry(o, next, previous);
// New for 1.2RC1 - the semantics changed so that the iterator is
// positioned *after* the new element.
previous = previous.next;
pos++;
size++;
b.incSize(1);
knownMod++;
b.upMod();
recent = null;
}
public void set(Object o) {
b.checkMod(knownMod);
if (recent == null) {
throw new IllegalStateException();
}
recent.data = o;
} }
} }
...@@ -279,40 +79,68 @@ public class LinkedList extends AbstractSequentialList ...@@ -279,40 +79,68 @@ public class LinkedList extends AbstractSequentialList
* paths to get to the Entry required. This implies that the first or last * paths to get to the Entry required. This implies that the first or last
* entry in the list is obtained in constant time, which is a very desirable * entry in the list is obtained in constant time, which is a very desirable
* property. * property.
* For speed and flexibility in which ranges are valid, range checking is not * For speed and flexibility, range checking is not done in this method:
* done in this method, and if n is outside the range -1 <= n <= size, the * Incorrect values will be returned if (n < 0) or (n >= size).
* result will be wrong (but no exception will be thrown).
* Note that you *can* obtain entries at position -1 and size, which are
* equal to prehead and posttail respectively.
* This method is static so that it can also be used in subList.
* *
* @param n the number of the entry to get. * @param n the number of the entry to get.
* @param size the size of the list to get the entry in.
* @param head the entry before the first element of the list (usually ends).
* @param tail the entry after the last element of the list (usually ends).
*/ */
static Entry getEntry(int n, int size, Entry head, Entry tail) { private Entry getEntry(int n)
{
Entry e;
if (n < size / 2)
{
e = first;
// n less than size/2, iterate from start // n less than size/2, iterate from start
if (n < size >> 1) { while (n-- > 0)
while (n-- >= 0) { {
head = head.next; e = e.next;
} }
return head; }
else
{
e = last;
// n greater than size/2, iterate from end // n greater than size/2, iterate from end
} else { while (++n < size)
while (++n <= size) { {
tail = tail.previous; e = e.previous;
} }
return tail;
} }
return e;
}
/** Remove an entry from the list. This will adjust size and deal with
* `first' and `last' appropriatly. It does not effect modCount, that is
* the responsibility of the caller. */
private void removeEntry(Entry e)
{
if (size == 1)
first = last = null;
else
{
if (e == first)
{
first = e.next;
e.next.previous = null;
}
else if (e == last)
{
last = e.previous;
e.previous.next = null;
}
else
{
e.next.previous = e.previous;
e.previous.next = e.next;
}
}
size--;
} }
/** /**
* Create an empty linked list. * Create an empty linked list.
*/ */
public LinkedList() { public LinkedList()
{
super(); super();
} }
...@@ -322,7 +150,8 @@ public class LinkedList extends AbstractSequentialList ...@@ -322,7 +150,8 @@ public class LinkedList extends AbstractSequentialList
* *
* @param c the collection to populate this list from. * @param c the collection to populate this list from.
*/ */
public LinkedList(Collection c) { public LinkedList(Collection c)
{
super(); super();
// Note: addAll could be made slightly faster, but not enough so to justify // Note: addAll could be made slightly faster, but not enough so to justify
// re-implementing it from scratch. It is just a matter of a relatively // re-implementing it from scratch. It is just a matter of a relatively
...@@ -330,207 +159,294 @@ public class LinkedList extends AbstractSequentialList ...@@ -330,207 +159,294 @@ public class LinkedList extends AbstractSequentialList
addAll(c); addAll(c);
} }
public Object getFirst() { public Object getFirst()
if (size == 0) { {
if (size == 0)
throw new NoSuchElementException(); throw new NoSuchElementException();
} return first.data;
return ends.next.data;
} }
public Object getLast() { public Object getLast()
if (size == 0) { {
if (size == 0)
throw new NoSuchElementException(); throw new NoSuchElementException();
} return last.data;
return ends.previous.data;
} }
public Object removeFirst() { public Object removeFirst()
if (size == 0) { {
if (size == 0)
throw new NoSuchElementException(); throw new NoSuchElementException();
}
size--; size--;
modCount++; modCount++;
return ends.next.remove(); Object r = first.data;
if (first.next != null)
first.next.previous = null;
return r;
} }
public Object removeLast() { public Object removeLast()
if (size == 0) { {
if (size == 0)
throw new NoSuchElementException(); throw new NoSuchElementException();
}
size--; size--;
modCount++; modCount++;
return ends.previous.remove(); Object r = last.data;
if (last.previous != null)
last.previous.next = null;
return r;
} }
public void addFirst(Object o) { public void addFirst(Object o)
ends.next.previous = ends.next = new Entry(o, ends.next, ends); {
modCount++;
Entry e = new Entry(o);
if (size == 0)
first = last = e;
else
{
e.next = first;
first.previous = e;
first = e;
}
size++; size++;
}
public void addLast(Object o)
{
modCount++; modCount++;
addLastEntry(new Entry(o));
} }
public void addLast(Object o) { private void addLastEntry(Entry e)
ends.previous.next = ends.previous = new Entry(o, ends, ends.previous); {
if (size == 0)
first = last = e;
else
{
e.previous = last;
last.next = e;
last = e;
}
size++; size++;
modCount++;
} }
/** public boolean contains(Object o)
* Obtain the number of elements currently in this list. {
* Entry e = first;
* @returns the number of elements currently in this list. while (e != null)
*/ {
public int size() { if (e.data == null ? o == null : o.equals(e.data))
return size; return true;
e = e.next;
}
return false;
} }
/** public int size()
* Remove a range of elements from this list. {
* return size;
* @param fromIndex the index, inclusive, to remove from.
* @param toIndex the index, exclusive, to remove to.
* @exception IndexOutOfBoundsException if fromIndex > toIndex || fromIndex <
* 0 || toIndex > size().
*/
// Note: normally removeRange is provided to allow efficient ways to
// implement clear() on subLists. However, in this case clear on subLists
// works anyway, so this implementation is included just for completeness
// and because subclasses might try to use it.
protected void removeRange(int fromIndex, int toIndex) {
subList(fromIndex, toIndex).clear();
} }
/** public boolean add(Object o)
* Clear the list. {
*/
public void clear() {
ends.next = ends.previous = ends;
modCount++; modCount++;
size = 0; addLastEntry(new Entry(o));
return true;
} }
/** public boolean remove(Object o)
* Obtain a ListIterator over this list, starting at a given index. The {
* ListIterator returned by this method supports the add, remove and set modCount++;
* methods. Entry e = first;
* while (e != null)
* @param index the index of the element to be returned by the first call to {
* next(), or size() to be initially positioned at the end of the list. if (e.data == null ? o == null : o.equals(e.data))
* @exception IndexOutOfBoundsException if index < 0 || index > size(). {
*/ removeEntry(e);
public ListIterator listIterator(int index) { return true;
// Check bounds
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException();
} }
e = e.next;
return new Iter(back, getEntry(index, size, ends, ends),
index, size, modCount);
} }
return false;
/**
* Obtain a List view of a subsection of this list, from fromIndex
* (inclusive) to toIndex (exclusive). The returned list is modifiable in
* every respect. Changes to the returned list are reflected in this list. If
* this list is structurally modified is any way other than through the
* returned list, any subsequent operations on the returned list will result
* in a ConcurrentModificationException (that is, the returned list is
* fail-fast).
*
* @param fromIndex the index that the returned list should start from
* (inclusive).
* @param toIndex the index that the returned list should go to (exclusive).
* @returns a List backed by a subsection of this list.
* @exception IndexOutOfBoundsException if fromIndex < 0 || toIndex > size()
* || fromIndex > toIndex.
*/
public List subList(int fromIndex, int toIndex) {
// Check bounds
if (fromIndex > toIndex || fromIndex < 0 || toIndex > size) {
throw new IndexOutOfBoundsException();
} }
return new SubLinkedList(back, modCount, public boolean addAll(Collection c)
getEntry(fromIndex - 1, size, ends, ends), {
getEntry(toIndex, size, ends, ends), return addAll(size, c);
toIndex - fromIndex);
} }
private static class SubLinkedList extends AbstractSequentialList { public boolean addAll(int index, Collection c)
{
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
modCount++;
int csize = c.size();
Entry head; // entry before the beginning if (csize == 0)
Entry tail; // entry after the end return false;
int size;
private final Backing b;
private final Backing back = new Backing() { Iterator itr = c.iterator();
public void checkMod(int known) {
if (known != modCount) { // Get the entries just before and after index. If index is at the start
throw new ConcurrentModificationException(); // of the list, BEFORE is null. If index is at the end of thelist, AFTER is
// null. If the list is empty, both are null.
Entry after = null;
Entry before = null;
if (index != size)
{
after = getEntry(index);
before = after.previous;
}
else
before = last;
// Create the first new entry. We do not yet set the link from `before'
// to the first entry, in order to deal with the case where (c == this).
// [Actually, we don't have to handle this case to fufill the
// contract for addAll(), but Sun's implementation appears to.]
Entry e = new Entry(itr.next());
e.previous = before;
Entry prev = e;
Entry firstNew = e;
// Create and link all the remaining entries.
for (int pos = 1; pos < csize; pos++)
{
e = new Entry(itr.next());
e.previous = prev;
prev.next = e;
prev = e;
} }
// Fix up the links between the last new entry and the following entry.
prev.next = after;
if (after != null)
after.previous = e;
else
last = e;
if (before != null)
before.next = firstNew;
else
first = firstNew;
size += csize;
return true;
} }
public void upMod() {
public void clear()
{
modCount++; modCount++;
first = null;
last = null;
size = 0;
} }
public void incSize(int by) {
size += by;
}
public void decSize(int by) {
size -= by;
}
};
SubLinkedList(Backing backing, int knownMod, Entry h, Entry t, int s) { public Object get(int index)
this.modCount = knownMod; {
b = backing; if (index < 0 || index >= size)
head = h; throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
tail = t; size);
size = s; Entry e = getEntry(index);
return e.data;
} }
public int size() { public Object set(int index, Object o)
b.checkMod(this.modCount); {
return size; if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
Entry e = getEntry(index);
Object old = e.data;
e.data = o;
return old;
} }
public ListIterator listIterator(int index) { public void add(int index, Object o)
b.checkMod(this.modCount); {
if (index < 0 || index > size)
// Check bounds throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
if (index < 0 || index > size) { size);
throw new IndexOutOfBoundsException(); modCount++;
addEntry(index, new Entry(o));
} }
return new Iter(back, getEntry(index, size, head, tail), private void addEntry(int index, Entry e)
index, size, modCount); {
if (index < size)
{
Entry after = getEntry(index);
e.next = after;
e.previous = after.previous;
if (after.previous == null)
first = e;
else
after.previous.next = e;
after.previous = e;
size++;
}
else
addLastEntry(e);
} }
public void clear() { public Object remove(int index)
b.checkMod(this.modCount); {
head.next = tail; if (index < 0 || index >= size)
tail.previous = head; throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size = 0; size);
b.decSize(size);
modCount++; modCount++;
b.upMod(); Entry e = getEntry(index);
removeEntry(e);
return e.data;
} }
// No removeRange because this class cannot be publically subclassed. public int indexOf(Object o)
{
public List subList(int fromIndex, int toIndex) { int index = 0;
b.checkMod(this.modCount); Entry e = first;
while (e != null)
// Check bounds {
if (fromIndex > toIndex || fromIndex < 0 || toIndex > size) { if (e.data == null ? o == null : o.equals(e.data))
throw new IndexOutOfBoundsException(); return index;
++index;
e = e.next;
}
return -1;
} }
return new SubLinkedList(back, this.modCount, public int lastIndexOf(Object o)
getEntry(fromIndex - 1, size, head, tail), {
getEntry(toIndex, size, head, tail), int index = size - 1;
toIndex - fromIndex); Entry e = last;
while (e != null)
{
if (e.data == null ? o == null : o.equals(e.data))
return index;
--index;
e = e.previous;
}
return -1;
} }
/**
* Obtain a ListIterator over this list, starting at a given index. The
* ListIterator returned by this method supports the add, remove and set
* methods.
*
* @param index the index of the element to be returned by the first call to
* next(), or size() to be initially positioned at the end of the list.
* @exception IndexOutOfBoundsException if index < 0 || index > size().
*/
public ListIterator listIterator(int index)
{
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
return new LinkedListItr(index);
} }
/** /**
...@@ -540,32 +456,58 @@ public class LinkedList extends AbstractSequentialList ...@@ -540,32 +456,58 @@ public class LinkedList extends AbstractSequentialList
*/ */
public Object clone() public Object clone()
{ {
LinkedList copy; LinkedList copy = null;
try try
{ {
copy = (LinkedList) super.clone(); copy = (LinkedList) super.clone();
} }
catch (CloneNotSupportedException ex) catch (CloneNotSupportedException ex)
{ {
throw new InternalError(ex.getMessage());
} }
copy.size = 0; copy.size = 0;
copy.ends = new Entry();
copy.addAll(this); copy.addAll(this);
return copy; return copy;
} }
public Object[] toArray()
{
Object[] array = new Object[size];
Entry e = first;
for (int i = 0; i < size; i++)
{
array[i] = e.data;
e = e.next;
}
return array;
}
public Object[] toArray(Object[] array)
{
if (array.length < size)
array = (Object[]) Array.newInstance(array.getClass().getComponentType(),
size);
else if (array.length > size)
array[size] = null;
Entry e = first;
for (int i = 0; i < size; i++)
{
array[i] = e.data;
e = e.next;
}
return array;
}
/** /**
* Serialize an object to a stream. * Serialize an object to a stream.
* @serialdata the size of the list (int), followed by all the elements * @serialdata the size of the list (int), followed by all the elements
* (Object) in proper order. * (Object) in proper order.
*/ */
private void writeObject(ObjectOutputStream s) private void writeObject(ObjectOutputStream s) throws IOException
throws IOException
{ {
s.writeInt(size); s.writeInt(size);
for (Iterator i = iterator(); i.hasNext(); ) Iterator itr = iterator();
s.writeObject(i.next()); for (int i = 0; i < size; i++)
s.writeObject(itr.next());
} }
/** /**
...@@ -577,8 +519,133 @@ public class LinkedList extends AbstractSequentialList ...@@ -577,8 +519,133 @@ public class LinkedList extends AbstractSequentialList
throws IOException, ClassNotFoundException throws IOException, ClassNotFoundException
{ {
int serialSize = s.readInt(); int serialSize = s.readInt();
ends = new Entry(); for (int i = 0; i < serialSize; i++)
for (int i=0; i< serialSize; i++) addLastEntry(new Entry(s.readObject()));
addLast(s.readObject()); }
/** A ListIterator over the list. This class keeps track of its
* position in the list, the size of the list, and the two list
* entries it is between. This enables it to be used identically
* for both the list itself and a sublist of the list.
*/
class LinkedListItr implements ListIterator
{
int knownMod;
Entry next; // entry that will be returned by next().
Entry previous; // entry that will be returned by previous().
Entry lastReturned; // entry that will be affected by remove() or set().
int position; // index of `next'.
/**
* Create a new Iter starting at a given Entry within the list, at a given
* position, in a list of given size.
*/
LinkedListItr(int index)
{
if (index == size)
{
next = null;
previous = last;
}
else
{
next = getEntry(index);
previous = next.previous;
}
position = index;
knownMod = modCount;
}
private void checkMod()
{
if (knownMod != modCount)
throw new ConcurrentModificationException();
}
public int nextIndex()
{
checkMod();
return position;
}
public int previousIndex()
{
checkMod();
return position - 1;
}
public boolean hasNext()
{
checkMod();
return (next != null);
}
public boolean hasPrevious()
{
checkMod();
return (previous != null);
}
public Object next()
{
checkMod();
if (next == null)
throw new NoSuchElementException();
position++;
lastReturned = previous = next;
next = lastReturned.next;
return lastReturned.data;
}
public Object previous()
{
checkMod();
if (previous == null)
throw new NoSuchElementException();
position--;
lastReturned = next = previous;
previous = lastReturned.previous;
return lastReturned.data;
}
public void remove()
{
checkMod();
if (lastReturned == null)
throw new IllegalStateException();
// Adjust the position to before the removed element, if the element
// being removed is behind the cursor.
if (lastReturned == previous)
position--;
next = lastReturned.next;
previous = lastReturned.previous;
// Because the list is being manipulated directly, there's no need to
// touch either modCount or knownMod here.
removeEntry(lastReturned);
lastReturned = null;
}
public void add(Object o)
{
checkMod();
// Because the list is being manipulated directly, there's no need to
// touch either modCount or knownMod here.
Entry e = new Entry(o);
addEntry(position, e);
previous = e;
position++;
lastReturned = null;
}
public void set(Object o)
{
checkMod();
if (lastReturned == null)
throw new IllegalStateException();
lastReturned.data = o;
} }
} // class LinkedListItr
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment