Add CursorableLinkedList to list subpackage
Rework AbstractLL/NodeCachingLL to allow for this Update tests git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@131447 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
abb9990e0d
commit
0b9cb552be
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/list/AbstractLinkedList.java,v 1.1 2003/12/11 00:18:06 scolebourne Exp $
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/list/AbstractLinkedList.java,v 1.2 2003/12/24 01:15:40 scolebourne Exp $
|
||||
* ====================================================================
|
||||
*
|
||||
* The Apache Software License, Version 1.1
|
||||
|
@ -75,20 +75,18 @@ import org.apache.commons.collections.OrderedIterator;
|
|||
* An abstract implementation of a linked list which provides numerous points for
|
||||
* subclasses to override.
|
||||
* <p>
|
||||
* Overridable methods are provided to change the storage node, and to change how
|
||||
* entries are added to and removed from the map. Hopefully, all you need for
|
||||
* unusual subclasses is here.
|
||||
* <p>
|
||||
* This class currently extends AbstractList, but do not rely on that. It may change.
|
||||
* Overridable methods are provided to change the storage node and to change how
|
||||
* nodes are added to and removed. Hopefully, all you need for unusual subclasses
|
||||
* is here.
|
||||
*
|
||||
* @since Commons Collections 3.0
|
||||
* @version $Revision: 1.1 $ $Date: 2003/12/11 00:18:06 $
|
||||
* @version $Revision: 1.2 $ $Date: 2003/12/24 01:15:40 $
|
||||
*
|
||||
* @author Rich Dougherty
|
||||
* @author Phil Steitz
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public abstract class AbstractLinkedList extends AbstractList implements List {
|
||||
public abstract class AbstractLinkedList implements List {
|
||||
|
||||
/*
|
||||
* Implementation notes:
|
||||
|
@ -99,7 +97,6 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
* - a modification count is kept, with the same semantics as
|
||||
* {@link java.util.LinkedList}.
|
||||
* - respects {@link AbstractList#modCount}
|
||||
* - only extends AbstractList for subList() - TODO
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -110,8 +107,8 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
protected transient Node header;
|
||||
/** The size of the list */
|
||||
protected transient int size;
|
||||
// /** Modification count for iterators */
|
||||
// protected transient int modCount;
|
||||
/** Modification count for iterators */
|
||||
protected transient int modCount;
|
||||
|
||||
/**
|
||||
* Constructor that does nothing intended for deserialization.
|
||||
|
@ -164,11 +161,11 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
}
|
||||
|
||||
public ListIterator listIterator() {
|
||||
return new LinkedListIterator();
|
||||
return new LinkedListIterator(this, 0);
|
||||
}
|
||||
|
||||
public ListIterator listIterator(int startIndex) {
|
||||
return new LinkedListIterator(startIndex);
|
||||
public ListIterator listIterator(int fromIndex) {
|
||||
return new LinkedListIterator(this, fromIndex);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -208,6 +205,40 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public Object[] toArray() {
|
||||
return toArray(new Object[size]);
|
||||
}
|
||||
|
||||
public Object[] toArray(Object[] array) {
|
||||
// Extend the array if needed
|
||||
if (array.length < size) {
|
||||
Class componentType = array.getClass().getComponentType();
|
||||
array = (Object[]) Array.newInstance(componentType, size);
|
||||
}
|
||||
// Copy the values into the array
|
||||
int i = 0;
|
||||
for (Node node = header.next; node != header; node = node.next, i++) {
|
||||
array[i] = node.value;
|
||||
}
|
||||
// Set the value after the last value to null
|
||||
if (array.length > size) {
|
||||
array[size] = null;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a sublist of the main list.
|
||||
*
|
||||
* @param fromIndexInclusive the index to start from
|
||||
* @param toIndexExclusive the index to end at
|
||||
* @return the new sublist
|
||||
*/
|
||||
public List subList(int fromIndexInclusive, int toIndexExclusive) {
|
||||
return new LinkedSubList(this, fromIndexInclusive, toIndexExclusive);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public boolean add(Object value) {
|
||||
addLast(value);
|
||||
|
@ -278,7 +309,7 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
public Object set(int index, Object value) {
|
||||
Node node = getNode(index, false);
|
||||
Object oldValue = node.value;
|
||||
node.value = value;
|
||||
updateNode(node, value);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
|
@ -286,30 +317,6 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
removeAllNodes();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public Object[] toArray() {
|
||||
return toArray(new Object[size]);
|
||||
}
|
||||
|
||||
public Object[] toArray(Object[] array) {
|
||||
// Extend the array if needed
|
||||
if (array.length < size) {
|
||||
Class componentType = array.getClass().getComponentType();
|
||||
array = (Object[]) Array.newInstance(componentType, size);
|
||||
}
|
||||
// Copy the values into the array
|
||||
Node node = header.next;
|
||||
for (int i = 0; i < size; i++) {
|
||||
array[i] = node.value;
|
||||
node = node.next;
|
||||
}
|
||||
// Set the value after the last value to null
|
||||
if (array.length > size) {
|
||||
array[size] = null;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public Object getFirst() {
|
||||
Node node = header.next;
|
||||
|
@ -327,12 +334,14 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
return node.value;
|
||||
}
|
||||
|
||||
public void addFirst(Object o) {
|
||||
public boolean addFirst(Object o) {
|
||||
addNodeAfter(header, o);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addLast(Object o) {
|
||||
public boolean addLast(Object o) {
|
||||
addNodeBefore(header, o);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object removeFirst() {
|
||||
|
@ -423,6 +432,18 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
return (value1 == value2 || (value1 == null ? false : value1.equals(value2)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the node with a new value.
|
||||
* This implementation sets the value on the node.
|
||||
* Subclasses can override this to record the change.
|
||||
*
|
||||
* @param node node to update
|
||||
* @param value new value of the node
|
||||
*/
|
||||
protected void updateNode(Node node, Object value) {
|
||||
node.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new node with previous, next and element all set to null.
|
||||
* This implementation creates a new empty Node.
|
||||
|
@ -439,42 +460,54 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
* This implementation creates a new Node with data.
|
||||
* Subclasses can override this to create a different class.
|
||||
*
|
||||
* @param previous node to precede the new node
|
||||
* @param next node to follow the new node
|
||||
* @param value value of the new node
|
||||
*/
|
||||
protected Node createNode(Node previous, Node next, Object value) {
|
||||
return new Node(previous, next, value);
|
||||
protected Node createNode(Object value) {
|
||||
return new Node(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new node with the specified object as its
|
||||
* <code>value</code> and inserts it before <code>node</code>.
|
||||
* <p>
|
||||
* This implementation uses {@link #createNode(Object)} and {@link #addNode(Node, Node)}.
|
||||
*
|
||||
* @param node node to insert before
|
||||
* @param value value of the newly added node
|
||||
* @throws NullPointerException if <code>node</code> is null
|
||||
*/
|
||||
protected void addNodeBefore(Node node, Object value) {
|
||||
Node newNode = createNode(node.previous, node, value);
|
||||
node.previous.next = newNode;
|
||||
node.previous = newNode;
|
||||
size++;
|
||||
modCount++;
|
||||
Node newNode = createNode(value);
|
||||
addNode(newNode, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new node with the specified object as its
|
||||
* <code>value</code> and inserts it after <code>node</code>.
|
||||
* <p>
|
||||
* This implementation uses {@link #createNode(Object)} and {@link #addNode(Node, Node)}.
|
||||
*
|
||||
* @param node node to insert after
|
||||
* @param value value of the newly added node
|
||||
* @throws NullPointerException if <code>node</code> is null
|
||||
*/
|
||||
protected void addNodeAfter(Node node, Object value) {
|
||||
Node newNode = createNode(node, node.next, value);
|
||||
node.next.previous = newNode;
|
||||
node.next = newNode;
|
||||
Node newNode = createNode(value);
|
||||
addNode(newNode, node.next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new node into the list.
|
||||
*
|
||||
* @param nodeToInsert new node to insert
|
||||
* @param insertBeforeNode node to insert before
|
||||
* @throws NullPointerException if either node is null
|
||||
*/
|
||||
protected void addNode(Node nodeToInsert, Node insertBeforeNode) {
|
||||
nodeToInsert.next = insertBeforeNode;
|
||||
nodeToInsert.previous = insertBeforeNode.previous;
|
||||
insertBeforeNode.previous.next = nodeToInsert;
|
||||
insertBeforeNode.previous = nodeToInsert;
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
@ -545,6 +578,26 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
return node;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Creates an iterator for the sublist.
|
||||
*
|
||||
* @param subList the sublist to get an iterator for
|
||||
*/
|
||||
protected Iterator createSubListIterator(LinkedSubList subList) {
|
||||
return createSubListListIterator(subList, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list iterator for the sublist.
|
||||
*
|
||||
* @param subList the sublist to get an iterator for
|
||||
* @param fromIndex the index to start from, relative to the sublist
|
||||
*/
|
||||
protected ListIterator createSubListListIterator(LinkedSubList subList, int fromIndex) {
|
||||
return new LinkedSubListIterator(subList, fromIndex);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Serializes the data held in this object to the stream specified.
|
||||
|
@ -577,28 +630,35 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* A node within the linked list.
|
||||
*
|
||||
* @author Rich Dougherty
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
protected static class Node {
|
||||
|
||||
/** A pointer to the node before this node */
|
||||
public Node previous;
|
||||
protected Node previous;
|
||||
/** A pointer to the node after this node */
|
||||
public Node next;
|
||||
protected Node next;
|
||||
/** The object contained within this node */
|
||||
public Object value;
|
||||
protected Object value;
|
||||
|
||||
/**
|
||||
* Constructs a new header node.
|
||||
*/
|
||||
public Node() {
|
||||
protected Node() {
|
||||
super();
|
||||
previous = this;
|
||||
next = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new node.
|
||||
*
|
||||
* @param value the value to store
|
||||
*/
|
||||
protected Node(Object value) {
|
||||
super();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new node.
|
||||
*
|
||||
|
@ -606,7 +666,7 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
* @param next the next node in the list
|
||||
* @param value the value to store
|
||||
*/
|
||||
public Node(Node previous, Node next, Object value) {
|
||||
protected Node(Node previous, Node next, Object value) {
|
||||
super();
|
||||
this.previous = previous;
|
||||
this.next = next;
|
||||
|
@ -617,16 +677,17 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* A list iterator over the linked list.
|
||||
*
|
||||
* @author Rich Dougherty
|
||||
*/
|
||||
protected class LinkedListIterator implements ListIterator, OrderedIterator {
|
||||
protected static class LinkedListIterator implements ListIterator, OrderedIterator {
|
||||
|
||||
/** The parent list */
|
||||
protected final AbstractLinkedList list;
|
||||
|
||||
/**
|
||||
* The node that will be returned by {@link #next()}. If this is equal
|
||||
* to {@link #marker} then there are no more values to return.
|
||||
*/
|
||||
protected Node nextNode;
|
||||
protected Node next;
|
||||
|
||||
/**
|
||||
* The index of {@link #nextNode}.
|
||||
|
@ -641,7 +702,7 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
* Should be accesed through {@link #getLastNodeReturned()} to enforce
|
||||
* this behaviour.
|
||||
*/
|
||||
protected Node lastNodeReturned;
|
||||
protected Node current;
|
||||
|
||||
/**
|
||||
* The modification count that the list is expected to have. If the list
|
||||
|
@ -651,24 +712,18 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
*/
|
||||
protected int expectedModCount;
|
||||
|
||||
/**
|
||||
* Create a ListIterator for a list, starting at the first value in
|
||||
* the list.
|
||||
*/
|
||||
public LinkedListIterator() throws IndexOutOfBoundsException {
|
||||
this(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ListIterator for a list.
|
||||
*
|
||||
* @param startIndex The index to start at.
|
||||
* @param parent the parent list
|
||||
* @param fromIndex the index to start at
|
||||
*/
|
||||
public LinkedListIterator(int startIndex) throws IndexOutOfBoundsException {
|
||||
public LinkedListIterator(AbstractLinkedList parent, int fromIndex) throws IndexOutOfBoundsException {
|
||||
super();
|
||||
expectedModCount = modCount;
|
||||
nextNode = getNode(startIndex, true);
|
||||
nextIndex = startIndex;
|
||||
this.list = parent;
|
||||
this.expectedModCount = list.modCount;
|
||||
this.next = list.getNode(fromIndex, true);
|
||||
this.nextIndex = fromIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -678,9 +733,8 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
* @throws ConcurrentModificationException If the list's modification
|
||||
* count isn't the value that was expected.
|
||||
*/
|
||||
protected void checkModCount()
|
||||
throws ConcurrentModificationException {
|
||||
if (modCount != expectedModCount) {
|
||||
protected void checkModCount() {
|
||||
if (list.modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
|
@ -693,14 +747,14 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
* with {@link #remove()} or a new node added with {@link #add(Object)}.
|
||||
*/
|
||||
protected Node getLastNodeReturned() throws IllegalStateException {
|
||||
if (lastNodeReturned == null) {
|
||||
if (current == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return lastNodeReturned;
|
||||
return current;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return nextNode != header;
|
||||
return next != list.header;
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
|
@ -709,15 +763,15 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
throw new NoSuchElementException("No element at index " +
|
||||
nextIndex + ".");
|
||||
}
|
||||
Object value = nextNode.value;
|
||||
lastNodeReturned = nextNode;
|
||||
nextNode = nextNode.next;
|
||||
Object value = next.value;
|
||||
current = next;
|
||||
next = next.next;
|
||||
nextIndex++;
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return nextNode.previous != header;
|
||||
return next.previous != list.header;
|
||||
}
|
||||
|
||||
public Object previous() {
|
||||
|
@ -725,9 +779,9 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
if (!hasPrevious()) {
|
||||
throw new NoSuchElementException("Already at start of list.");
|
||||
}
|
||||
nextNode = nextNode.previous;
|
||||
Object value = nextNode.value;
|
||||
lastNodeReturned = nextNode;
|
||||
next = next.previous;
|
||||
Object value = next.value;
|
||||
current = next;
|
||||
nextIndex--;
|
||||
return value;
|
||||
}
|
||||
|
@ -737,30 +791,192 @@ public abstract class AbstractLinkedList extends AbstractList implements List {
|
|||
}
|
||||
|
||||
public int previousIndex() {
|
||||
return nextIndex - 1;
|
||||
// not normally overridden, as relative to nextIndex()
|
||||
return nextIndex() - 1;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
checkModCount();
|
||||
removeNode(getLastNodeReturned());
|
||||
lastNodeReturned = null;
|
||||
list.removeNode(getLastNodeReturned());
|
||||
current = null;
|
||||
nextIndex--;
|
||||
expectedModCount++;
|
||||
}
|
||||
|
||||
public void set(Object o) {
|
||||
public void set(Object obj) {
|
||||
checkModCount();
|
||||
getLastNodeReturned().value = o;
|
||||
getLastNodeReturned().value = obj;
|
||||
}
|
||||
|
||||
public void add(Object o) {
|
||||
public void add(Object obj) {
|
||||
checkModCount();
|
||||
addNodeBefore(nextNode, o);
|
||||
lastNodeReturned = null;
|
||||
list.addNodeBefore(next, obj);
|
||||
current = null;
|
||||
nextIndex++;
|
||||
expectedModCount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* A list iterator over the linked sub list.
|
||||
*/
|
||||
protected static class LinkedSubListIterator extends LinkedListIterator {
|
||||
|
||||
/** The parent list */
|
||||
protected final LinkedSubList sub;
|
||||
|
||||
protected LinkedSubListIterator(LinkedSubList sub, int startIndex) {
|
||||
super(sub.list, startIndex + sub.offset);
|
||||
this.sub = sub;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return (nextIndex() < sub.size);
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return (previousIndex() >= 0);
|
||||
}
|
||||
|
||||
public int nextIndex() {
|
||||
return (super.nextIndex() - sub.offset);
|
||||
}
|
||||
|
||||
public void add(Object obj) {
|
||||
super.add(obj);
|
||||
sub.expectedModCount = list.modCount;
|
||||
sub.size++;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
super.remove();
|
||||
sub.expectedModCount = list.modCount;
|
||||
sub.size--;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* The sublist implementation for AbstractLinkedList.
|
||||
*/
|
||||
protected static class LinkedSubList extends AbstractList {
|
||||
/** The main list */
|
||||
private AbstractLinkedList list;
|
||||
/** Offset from the main list */
|
||||
private int offset;
|
||||
/** Sublist size */
|
||||
private int size;
|
||||
/** Sublist modCount */
|
||||
private int expectedModCount;
|
||||
|
||||
protected LinkedSubList(AbstractLinkedList list, int fromIndex, int toIndex) {
|
||||
if (fromIndex < 0) {
|
||||
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
|
||||
}
|
||||
if (toIndex > list.size()) {
|
||||
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
|
||||
}
|
||||
if (fromIndex > toIndex) {
|
||||
throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
|
||||
}
|
||||
this.list = list;
|
||||
this.offset = fromIndex;
|
||||
this.size = toIndex - fromIndex;
|
||||
this.expectedModCount = list.modCount;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
checkModCount();
|
||||
return size;
|
||||
}
|
||||
|
||||
public Object get(int index) {
|
||||
rangeCheck(index, size);
|
||||
checkModCount();
|
||||
return list.get(index + offset);
|
||||
}
|
||||
|
||||
public void add(int index, Object obj) {
|
||||
rangeCheck(index, size + 1);
|
||||
checkModCount();
|
||||
list.add(index + offset, obj);
|
||||
expectedModCount = list.modCount;
|
||||
size++;
|
||||
LinkedSubList.this.modCount++;
|
||||
}
|
||||
|
||||
public Object remove(int index) {
|
||||
rangeCheck(index, size);
|
||||
checkModCount();
|
||||
Object result = list.remove(index + offset);
|
||||
expectedModCount = list.modCount;
|
||||
size--;
|
||||
LinkedSubList.this.modCount++;
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean addAll(Collection coll) {
|
||||
return addAll(size, coll);
|
||||
}
|
||||
|
||||
public boolean addAll(int index, Collection coll) {
|
||||
rangeCheck(index, size + 1);
|
||||
int cSize = coll.size();
|
||||
if (cSize == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
checkModCount();
|
||||
list.addAll(offset + index, coll);
|
||||
expectedModCount = list.modCount;
|
||||
size += cSize;
|
||||
LinkedSubList.this.modCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object set(int index, Object obj) {
|
||||
rangeCheck(index, size);
|
||||
checkModCount();
|
||||
return list.set(index + offset, obj);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
checkModCount();
|
||||
Iterator it = iterator();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
checkModCount();
|
||||
return list.createSubListIterator(this);
|
||||
}
|
||||
|
||||
public ListIterator listIterator(final int index) {
|
||||
rangeCheck(index, size + 1);
|
||||
checkModCount();
|
||||
return list.createSubListListIterator(this, index);
|
||||
}
|
||||
|
||||
public List subList(int fromIndexInclusive, int toIndexExclusive) {
|
||||
return new LinkedSubList(list, fromIndexInclusive + offset, toIndexExclusive + offset);
|
||||
}
|
||||
|
||||
protected void rangeCheck(int index, int beyond) {
|
||||
if (index < 0 || index >= beyond) {
|
||||
throw new IndexOutOfBoundsException("Index '" + index + "' out of bounds for size '" + size + "'");
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkModCount() {
|
||||
if (list.modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,807 @@
|
|||
/*
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/list/CursorableLinkedList.java,v 1.1 2003/12/24 01:15:40 scolebourne Exp $
|
||||
* ====================================================================
|
||||
*
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if
|
||||
* any, must include the following acknowledgement:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowledgement may appear in the software itself,
|
||||
* if and wherever such third-party acknowledgements normally appear.
|
||||
*
|
||||
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||
* Foundation" must not be used to endorse or promote products derived
|
||||
* from this software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache"
|
||||
* nor may "Apache" appear in their names without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
package org.apache.commons.collections.list;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
* A <code>List</code> implementation with a <code>ListIterator</code> that
|
||||
* allows concurrent modifications to the underlying list.
|
||||
* <p>
|
||||
* This implementation supports all of the optional {@link List} operations.
|
||||
* It extends <code>AbstractLinkedList</code> and thus provides the
|
||||
* stack/queue/dequeue operations available in {@link java.util.LinkedList}.
|
||||
* <p>
|
||||
* The main feature of this class is the ability to modify the list and the
|
||||
* iterator at the same time. Both the {@link #listIterator()} and {@link #cursor()}
|
||||
* methods provides access to a <code>Cursor</code> instance which extends
|
||||
* <code>ListIterator</code>. The cursor allows changes to the list concurrent
|
||||
* with changes to the iterator. Note that the {@link #iterator()} method and
|
||||
* sublists do <b>not</b> provide this cursor behaviour.
|
||||
* <p>
|
||||
* The <code>Cursor</code> class is provided partly for backwards compatability
|
||||
* and partly because it allows the cursor to be directly closed. Closing the
|
||||
* cursor is optional because references are held via a <code>WeakReference</code>.
|
||||
* For most purposes, simply modify the iterator and list at will, and then let
|
||||
* the garbage collector to the rest.
|
||||
* <p>
|
||||
* <b>Note that this implementation is not synchronized.</b>
|
||||
*
|
||||
* @see java.util.LinkedList
|
||||
* @since Commons Collections 1.0
|
||||
* @version $Revision: 1.1 $ $Date: 2003/12/24 01:15:40 $
|
||||
*
|
||||
* @author Rodney Waldhoff
|
||||
* @author Janek Bogucki
|
||||
* @author Simon Kitching
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public class CursorableLinkedList extends AbstractLinkedList implements Serializable {
|
||||
|
||||
/** Ensure serialization compatability */
|
||||
private static final long serialVersionUID = 8836393098519411393L;
|
||||
|
||||
/** A list of the cursor currently open on this list */
|
||||
protected transient List cursors = new ArrayList();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Constructor that creates.
|
||||
*/
|
||||
public CursorableLinkedList() {
|
||||
super();
|
||||
init(); // must call init() as use super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that copies the specified collection
|
||||
*
|
||||
* @param coll the collection to copy
|
||||
*/
|
||||
public CursorableLinkedList(Collection coll) {
|
||||
super(coll);
|
||||
}
|
||||
|
||||
/**
|
||||
* The equivalent of a default constructor called
|
||||
* by any constructor and by <code>readObject</code>.
|
||||
*/
|
||||
protected void init() {
|
||||
super.init();
|
||||
cursors = new ArrayList();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns an iterator that does <b>not</b> support concurrent modification.
|
||||
* <p>
|
||||
* If the underlying list is modified while iterating using this iterator
|
||||
* a ConcurrentModificationException will occur.
|
||||
* The cursor behaviour is available via {@link #listIterator()}.
|
||||
*
|
||||
* @return a new iterator that does <b>not</b> support concurrent modification
|
||||
*/
|
||||
public Iterator iterator() {
|
||||
return super.listIterator(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cursor iterator that allows changes to the underlying list in parallel.
|
||||
* <p>
|
||||
* The cursor enables iteration and list changes to occur in any order without
|
||||
* invalidating the iterator (from one thread). When elements are added to the
|
||||
* list, an event is fired to all active cursors enabling them to adjust to the
|
||||
* change in the list.
|
||||
* <p>
|
||||
* When the "current" (i.e., last returned by {@link ListIterator#next}
|
||||
* or {@link ListIterator#previous}) element of the list is removed,
|
||||
* the cursor automatically adjusts to the change (invalidating the
|
||||
* last returned value such that it cannot be removed).
|
||||
*
|
||||
* @return a new cursor iterator
|
||||
*/
|
||||
public ListIterator listIterator() {
|
||||
return cursor(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cursor iterator that allows changes to the underlying list in parallel.
|
||||
* <p>
|
||||
* The cursor enables iteration and list changes to occur in any order without
|
||||
* invalidating the iterator (from one thread). When elements are added to the
|
||||
* list, an event is fired to all active cursors enabling them to adjust to the
|
||||
* change in the list.
|
||||
* <p>
|
||||
* When the "current" (i.e., last returned by {@link ListIterator#next}
|
||||
* or {@link ListIterator#previous}) element of the list is removed,
|
||||
* the cursor automatically adjusts to the change (invalidating the
|
||||
* last returned value such that it cannot be removed).
|
||||
*
|
||||
* @param fromIndex the index to start from
|
||||
* @return a new cursor iterator
|
||||
*/
|
||||
public ListIterator listIterator(int fromIndex) {
|
||||
return cursor(fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Cursor} for iterating through the elements of this list.
|
||||
* <p>
|
||||
* A <code>Cursor</code> is a <code>ListIterator</code> with an additional
|
||||
* <code>close()</code> method. Calling this method immediately discards the
|
||||
* references to the cursor. If it is not called, then the garbage collector
|
||||
* will still remove the reference as it is held via a <code>WeakReference</code>.
|
||||
* <p>
|
||||
* The cursor enables iteration and list changes to occur in any order without
|
||||
* invalidating the iterator (from one thread). When elements are added to the
|
||||
* list, an event is fired to all active cursors enabling them to adjust to the
|
||||
* change in the list.
|
||||
* <p>
|
||||
* When the "current" (i.e., last returned by {@link ListIterator#next}
|
||||
* or {@link ListIterator#previous}) element of the list is removed,
|
||||
* the cursor automatically adjusts to the change (invalidating the
|
||||
* last returned value such that it cannot be removed).
|
||||
* <p>
|
||||
* The {@link #listIterator()} method returns the same as this method, and can
|
||||
* be cast to a <code>Cursor</code> if the <code>close</code> method is required.
|
||||
*
|
||||
* @return a new cursor iterator
|
||||
*/
|
||||
public CursorableLinkedList.Cursor cursor() {
|
||||
return cursor(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Cursor} for iterating through the elements of this list
|
||||
* starting from a specified index.
|
||||
* <p>
|
||||
* A <code>Cursor</code> is a <code>ListIterator</code> with an additional
|
||||
* <code>close()</code> method. Calling this method immediately discards the
|
||||
* references to the cursor. If it is not called, then the garbage collector
|
||||
* will still remove the reference as it is held via a <code>WeakReference</code>.
|
||||
* <p>
|
||||
* The cursor enables iteration and list changes to occur in any order without
|
||||
* invalidating the iterator (from one thread). When elements are added to the
|
||||
* list, an event is fired to all active cursors enabling them to adjust to the
|
||||
* change in the list.
|
||||
* <p>
|
||||
* When the "current" (i.e., last returned by {@link ListIterator#next}
|
||||
* or {@link ListIterator#previous}) element of the list is removed,
|
||||
* the cursor automatically adjusts to the change (invalidating the
|
||||
* last returned value such that it cannot be removed).
|
||||
* <p>
|
||||
* The {@link #listIterator(int)} method returns the same as this method, and can
|
||||
* be cast to a <code>Cursor</code> if the <code>close</code> method is required.
|
||||
*
|
||||
* @param fromIndex the index to start from
|
||||
* @return a new cursor iterator
|
||||
* @throws IndexOutOfBoundsException if the index is out of range
|
||||
* (index < 0 || index > size()).
|
||||
*/
|
||||
public CursorableLinkedList.Cursor cursor(int fromIndex) {
|
||||
Cursor cursor = new Cursor(this, fromIndex);
|
||||
registerCursor(cursor);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Updates the node with a new value.
|
||||
* This implementation sets the value on the node.
|
||||
* Subclasses can override this to record the change.
|
||||
*
|
||||
* @param node node to update
|
||||
* @param value new value of the node
|
||||
*/
|
||||
protected void updateNode(Node node, Object value) {
|
||||
super.updateNode(node, value);
|
||||
broadcastNodeChanged(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new node into the list.
|
||||
*
|
||||
* @param nodeToInsert new node to insert
|
||||
* @param insertBeforeNode node to insert before
|
||||
* @throws NullPointerException if either node is null
|
||||
*/
|
||||
protected void addNode(Node nodeToInsert, Node insertBeforeNode) {
|
||||
super.addNode(nodeToInsert, insertBeforeNode);
|
||||
broadcastNodeInserted(nodeToInsert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified node from the list.
|
||||
*
|
||||
* @param node the node to remove
|
||||
* @throws NullPointerException if <code>node</code> is null
|
||||
*/
|
||||
protected void removeNode(Node node) {
|
||||
super.removeNode(node);
|
||||
broadcastNodeRemoved(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all nodes by iteration.
|
||||
*/
|
||||
protected void removeAllNodes() {
|
||||
if (size() > 0) {
|
||||
// superclass implementation would break all the iterators
|
||||
Iterator it = iterator();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Registers a cursor to be notified of changes to this list.
|
||||
*
|
||||
* @param cursor the cursor to register
|
||||
*/
|
||||
protected void registerCursor(Cursor cursor) {
|
||||
// We take this opportunity to clean the cursors list
|
||||
// of WeakReference objects to garbage-collected cursors.
|
||||
for (Iterator it = cursors.iterator(); it.hasNext();) {
|
||||
WeakReference ref = (WeakReference) it.next();
|
||||
if (ref.get() == null) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
cursors.add(new WeakReference(cursor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregisters a cursor from the list to be notified of changes.
|
||||
*
|
||||
* @param cursor the cursor to deregister
|
||||
*/
|
||||
protected void unregisterCursor(Cursor cursor) {
|
||||
for (Iterator it = cursors.iterator(); it.hasNext();) {
|
||||
WeakReference ref = (WeakReference) it.next();
|
||||
Cursor cur = (Cursor) ref.get();
|
||||
if (cur == null) {
|
||||
// some other unrelated cursor object has been
|
||||
// garbage-collected; let's take the opportunity to
|
||||
// clean up the cursors list anyway..
|
||||
it.remove();
|
||||
|
||||
} else if (cur == cursor) {
|
||||
ref.clear();
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Informs all of my registered cursors that the specified
|
||||
* element was changed.
|
||||
*
|
||||
* @param node the node that was changed
|
||||
*/
|
||||
protected void broadcastNodeChanged(Node node) {
|
||||
Iterator it = cursors.iterator();
|
||||
while (it.hasNext()) {
|
||||
WeakReference ref = (WeakReference) it.next();
|
||||
Cursor cursor = (Cursor) ref.get();
|
||||
if (cursor == null) {
|
||||
it.remove(); // clean up list
|
||||
} else {
|
||||
cursor.nodeChanged(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs all of my registered cursors that the specified
|
||||
* element was just removed from my list.
|
||||
*
|
||||
* @param node the node that was changed
|
||||
*/
|
||||
protected void broadcastNodeRemoved(Node node) {
|
||||
Iterator it = cursors.iterator();
|
||||
while (it.hasNext()) {
|
||||
WeakReference ref = (WeakReference) it.next();
|
||||
Cursor cursor = (Cursor) ref.get();
|
||||
if (cursor == null) {
|
||||
it.remove(); // clean up list
|
||||
} else {
|
||||
cursor.nodeRemoved(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs all of my registered cursors that the specified
|
||||
* element was just added to my list.
|
||||
*
|
||||
* @param node the node that was changed
|
||||
*/
|
||||
protected void broadcastNodeInserted(Node node) {
|
||||
Iterator it = cursors.iterator();
|
||||
while (it.hasNext()) {
|
||||
WeakReference ref = (WeakReference) it.next();
|
||||
Cursor cursor = (Cursor) ref.get();
|
||||
if (cursor == null) {
|
||||
it.remove(); // clean up list
|
||||
} else {
|
||||
cursor.nodeInserted(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Serializes the data held in this object to the stream specified.
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.defaultWriteObject();
|
||||
doWriteObject(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the data held in this object to the stream specified.
|
||||
*/
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
doReadObject(in);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* An extended <code>ListIterator</code> that allows concurrent changes to
|
||||
* the underlying list.
|
||||
*/
|
||||
public static class Cursor extends AbstractLinkedList.LinkedListIterator {
|
||||
/** Is the cursor valid (not closed) */
|
||||
boolean valid = true;
|
||||
/** Is the next index valid */
|
||||
boolean nextIndexValid = true;
|
||||
|
||||
/**
|
||||
* Constructs a new cursor.
|
||||
*
|
||||
* @param index the index to start from
|
||||
*/
|
||||
protected Cursor(CursorableLinkedList parent, int index) {
|
||||
super(parent, index);
|
||||
valid = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an object to the list.
|
||||
* The object added here will be the new 'previous' in the iterator.
|
||||
*
|
||||
* @param obj the object to add
|
||||
*/
|
||||
public void add(Object obj) {
|
||||
super.add(obj);
|
||||
// add on iterator does not return the added element
|
||||
next = next.next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the next element to be returned.
|
||||
*
|
||||
* @return the next index
|
||||
*/
|
||||
public int nextIndex() {
|
||||
if (nextIndexValid == false) {
|
||||
if (next == list.header) {
|
||||
nextIndex = list.size();
|
||||
} else {
|
||||
int pos = 0;
|
||||
Node temp = list.header.next;
|
||||
while (temp != next) {
|
||||
pos++;
|
||||
temp = temp.next;
|
||||
}
|
||||
nextIndex = pos;
|
||||
}
|
||||
nextIndexValid = true;
|
||||
}
|
||||
return nextIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle event from the list when a node has changed.
|
||||
*
|
||||
* @param node the node that changed
|
||||
*/
|
||||
protected void nodeChanged(Node node) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle event from the list when a node has been removed.
|
||||
*
|
||||
* @param node the node that was removed
|
||||
*/
|
||||
protected void nodeRemoved(Node node) {
|
||||
if (node == next) {
|
||||
next = node.next;
|
||||
} else if (node == current) {
|
||||
current = null;
|
||||
nextIndex--;
|
||||
} else {
|
||||
nextIndexValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle event from the list when a node has been added.
|
||||
*
|
||||
* @param node the node that was added
|
||||
*/
|
||||
protected void nodeInserted(Node node) {
|
||||
if (node.previous == current) {
|
||||
next = node;
|
||||
} else if (next.previous == node) {
|
||||
next = node;
|
||||
} else {
|
||||
nextIndexValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override superclass modCount check, and replace it with our valid flag.
|
||||
*/
|
||||
protected void checkModCount() {
|
||||
if (!valid) {
|
||||
throw new ConcurrentModificationException("Cursor closed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this cursor as no longer being needed. Any resources
|
||||
* associated with this cursor are immediately released.
|
||||
* In previous versions of this class, it was mandatory to close
|
||||
* all cursor objects to avoid memory leaks. It is <i>no longer</i>
|
||||
* necessary to call this close method; an instance of this class
|
||||
* can now be treated exactly like a normal iterator.
|
||||
*/
|
||||
public void close() {
|
||||
if (valid) {
|
||||
((CursorableLinkedList) list).unregisterCursor(this);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//class CursorableSubList extends CursorableLinkedList implements List {
|
||||
//
|
||||
// //--- constructors -----------------------------------------------
|
||||
//
|
||||
// CursorableSubList(CursorableLinkedList list, int from, int to) {
|
||||
// if(0 > from || list.size() < to) {
|
||||
// throw new IndexOutOfBoundsException();
|
||||
// } else if(from > to) {
|
||||
// throw new IllegalArgumentException();
|
||||
// }
|
||||
// _list = list;
|
||||
// if(from < list.size()) {
|
||||
// _head.setNext(_list.getListableAt(from));
|
||||
// _pre = (null == _head.next()) ? null : _head.next().prev();
|
||||
// } else {
|
||||
// _pre = _list.getListableAt(from-1);
|
||||
// }
|
||||
// if(from == to) {
|
||||
// _head.setNext(null);
|
||||
// _head.setPrev(null);
|
||||
// if(to < list.size()) {
|
||||
// _post = _list.getListableAt(to);
|
||||
// } else {
|
||||
// _post = null;
|
||||
// }
|
||||
// } else {
|
||||
// _head.setPrev(_list.getListableAt(to-1));
|
||||
// _post = _head.prev().next();
|
||||
// }
|
||||
// _size = to - from;
|
||||
// _modCount = _list._modCount;
|
||||
// }
|
||||
//
|
||||
// //--- public methods ------------------------------------------
|
||||
//
|
||||
// public void clear() {
|
||||
// checkForComod();
|
||||
// Iterator it = iterator();
|
||||
// while(it.hasNext()) {
|
||||
// it.next();
|
||||
// it.remove();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public Iterator iterator() {
|
||||
// checkForComod();
|
||||
// return super.iterator();
|
||||
// }
|
||||
//
|
||||
// public int size() {
|
||||
// checkForComod();
|
||||
// return super.size();
|
||||
// }
|
||||
//
|
||||
// public boolean isEmpty() {
|
||||
// checkForComod();
|
||||
// return super.isEmpty();
|
||||
// }
|
||||
//
|
||||
// public Object[] toArray() {
|
||||
// checkForComod();
|
||||
// return super.toArray();
|
||||
// }
|
||||
//
|
||||
// public Object[] toArray(Object a[]) {
|
||||
// checkForComod();
|
||||
// return super.toArray(a);
|
||||
// }
|
||||
//
|
||||
// public boolean contains(Object o) {
|
||||
// checkForComod();
|
||||
// return super.contains(o);
|
||||
// }
|
||||
//
|
||||
// public boolean remove(Object o) {
|
||||
// checkForComod();
|
||||
// return super.remove(o);
|
||||
// }
|
||||
//
|
||||
// public Object removeFirst() {
|
||||
// checkForComod();
|
||||
// return super.removeFirst();
|
||||
// }
|
||||
//
|
||||
// public Object removeLast() {
|
||||
// checkForComod();
|
||||
// return super.removeLast();
|
||||
// }
|
||||
//
|
||||
// public boolean addAll(Collection c) {
|
||||
// checkForComod();
|
||||
// return super.addAll(c);
|
||||
// }
|
||||
//
|
||||
// public boolean add(Object o) {
|
||||
// checkForComod();
|
||||
// return super.add(o);
|
||||
// }
|
||||
//
|
||||
// public boolean addFirst(Object o) {
|
||||
// checkForComod();
|
||||
// return super.addFirst(o);
|
||||
// }
|
||||
//
|
||||
// public boolean addLast(Object o) {
|
||||
// checkForComod();
|
||||
// return super.addLast(o);
|
||||
// }
|
||||
//
|
||||
// public boolean removeAll(Collection c) {
|
||||
// checkForComod();
|
||||
// return super.removeAll(c);
|
||||
// }
|
||||
//
|
||||
// public boolean containsAll(Collection c) {
|
||||
// checkForComod();
|
||||
// return super.containsAll(c);
|
||||
// }
|
||||
//
|
||||
// public boolean addAll(int index, Collection c) {
|
||||
// checkForComod();
|
||||
// return super.addAll(index,c);
|
||||
// }
|
||||
//
|
||||
// public int hashCode() {
|
||||
// checkForComod();
|
||||
// return super.hashCode();
|
||||
// }
|
||||
//
|
||||
// public boolean retainAll(Collection c) {
|
||||
// checkForComod();
|
||||
// return super.retainAll(c);
|
||||
// }
|
||||
//
|
||||
// public Object set(int index, Object element) {
|
||||
// checkForComod();
|
||||
// return super.set(index,element);
|
||||
// }
|
||||
//
|
||||
// public boolean equals(Object o) {
|
||||
// checkForComod();
|
||||
// return super.equals(o);
|
||||
// }
|
||||
//
|
||||
// public Object get(int index) {
|
||||
// checkForComod();
|
||||
// return super.get(index);
|
||||
// }
|
||||
//
|
||||
// public Object getFirst() {
|
||||
// checkForComod();
|
||||
// return super.getFirst();
|
||||
// }
|
||||
//
|
||||
// public Object getLast() {
|
||||
// checkForComod();
|
||||
// return super.getLast();
|
||||
// }
|
||||
//
|
||||
// public void add(int index, Object element) {
|
||||
// checkForComod();
|
||||
// super.add(index,element);
|
||||
// }
|
||||
//
|
||||
// public ListIterator listIterator(int index) {
|
||||
// checkForComod();
|
||||
// return super.listIterator(index);
|
||||
// }
|
||||
//
|
||||
// public Object remove(int index) {
|
||||
// checkForComod();
|
||||
// return super.remove(index);
|
||||
// }
|
||||
//
|
||||
// public int indexOf(Object o) {
|
||||
// checkForComod();
|
||||
// return super.indexOf(o);
|
||||
// }
|
||||
//
|
||||
// public int lastIndexOf(Object o) {
|
||||
// checkForComod();
|
||||
// return super.lastIndexOf(o);
|
||||
// }
|
||||
//
|
||||
// public ListIterator listIterator() {
|
||||
// checkForComod();
|
||||
// return super.listIterator();
|
||||
// }
|
||||
//
|
||||
// public List subList(int fromIndex, int toIndex) {
|
||||
// checkForComod();
|
||||
// return super.subList(fromIndex,toIndex);
|
||||
// }
|
||||
//
|
||||
// //--- protected methods ------------------------------------------
|
||||
//
|
||||
// /**
|
||||
// * Inserts a new <i>value</i> into my
|
||||
// * list, after the specified <i>before</i> element, and before the
|
||||
// * specified <i>after</i> element
|
||||
// *
|
||||
// * @return the newly created {@link CursorableLinkedList.Listable}
|
||||
// */
|
||||
// protected Listable insertListable(Listable before, Listable after, Object value) {
|
||||
// _modCount++;
|
||||
// _size++;
|
||||
// Listable elt = _list.insertListable((null == before ? _pre : before), (null == after ? _post : after),value);
|
||||
// if(null == _head.next()) {
|
||||
// _head.setNext(elt);
|
||||
// _head.setPrev(elt);
|
||||
// }
|
||||
// if(before == _head.prev()) {
|
||||
// _head.setPrev(elt);
|
||||
// }
|
||||
// if(after == _head.next()) {
|
||||
// _head.setNext(elt);
|
||||
// }
|
||||
// broadcastListableInserted(elt);
|
||||
// return elt;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Removes the given {@link CursorableLinkedList.Listable} from my list.
|
||||
// */
|
||||
// protected void removeListable(Listable elt) {
|
||||
// _modCount++;
|
||||
// _size--;
|
||||
// if(_head.next() == elt && _head.prev() == elt) {
|
||||
// _head.setNext(null);
|
||||
// _head.setPrev(null);
|
||||
// }
|
||||
// if(_head.next() == elt) {
|
||||
// _head.setNext(elt.next());
|
||||
// }
|
||||
// if(_head.prev() == elt) {
|
||||
// _head.setPrev(elt.prev());
|
||||
// }
|
||||
// _list.removeListable(elt);
|
||||
// broadcastListableRemoved(elt);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Test to see if my underlying list has been modified
|
||||
// * by some other process. If it has, throws a
|
||||
// * {@link ConcurrentModificationException}, otherwise
|
||||
// * quietly returns.
|
||||
// *
|
||||
// * @throws ConcurrentModificationException
|
||||
// */
|
||||
// protected void checkForComod() throws ConcurrentModificationException {
|
||||
// if(_modCount != _list._modCount) {
|
||||
// throw new ConcurrentModificationException();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //--- protected attributes ---------------------------------------
|
||||
//
|
||||
// /** My underlying list */
|
||||
// protected CursorableLinkedList _list = null;
|
||||
//
|
||||
// /** The element in my underlying list preceding the first element in my list. */
|
||||
// protected Listable _pre = null;
|
||||
//
|
||||
// /** The element in my underlying list following the last element in my list. */
|
||||
// protected Listable _post = null;
|
||||
//
|
||||
//}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/list/NodeCachingLinkedList.java,v 1.1 2003/12/11 00:18:06 scolebourne Exp $
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/list/NodeCachingLinkedList.java,v 1.2 2003/12/24 01:15:40 scolebourne Exp $
|
||||
* ====================================================================
|
||||
*
|
||||
* The Apache Software License, Version 1.1
|
||||
|
@ -64,12 +64,21 @@ import java.io.Serializable;
|
|||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A linked list implementation that caches the nodes used internally to prevent
|
||||
* unnecessary object creates and deletion. This results in a performance
|
||||
* improvement for long-lived lists which both add and remove.
|
||||
* A <code>List</code> implementation that stores a cache of internal Node objects
|
||||
* in an effort to reduce wasteful object creation.
|
||||
* <p>
|
||||
* A linked list creates one Node for each item of data added. This can result in
|
||||
* a lot of object creation and garbage collection. This implementation seeks to
|
||||
* avoid that by maintaining a store of cached nodes.
|
||||
* <p>
|
||||
* This implementation is suitable for long-lived lists where both add and remove
|
||||
* are used. Short-lived lists, or lists which only grow will have worse performance
|
||||
* using this class.
|
||||
* <p>
|
||||
* <b>Note that this implementation is not synchronized.</b>
|
||||
*
|
||||
* @since Commons Collections 3.0
|
||||
* @version $Revision: 1.1 $ $Date: 2003/12/11 00:18:06 $
|
||||
* @version $Revision: 1.2 $ $Date: 2003/12/24 01:15:40 $
|
||||
*
|
||||
* @author Jeff Varszegi
|
||||
* @author Rich Dougherty
|
||||
|
@ -135,6 +144,8 @@ public class NodeCachingLinkedList extends AbstractLinkedList implements Seriali
|
|||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the maximum size of the cache.
|
||||
*
|
||||
* @return the maximum cache size
|
||||
*/
|
||||
protected int getMaximumCacheSize() {
|
||||
return maximumCacheSize;
|
||||
|
@ -142,6 +153,8 @@ public class NodeCachingLinkedList extends AbstractLinkedList implements Seriali
|
|||
|
||||
/**
|
||||
* Sets the maximum size of the cache.
|
||||
*
|
||||
* @param maximumCacheSize the new maximum cache size
|
||||
*/
|
||||
protected void setMaximumCacheSize(int maximumCacheSize) {
|
||||
this.maximumCacheSize = maximumCacheSize;
|
||||
|
@ -163,7 +176,7 @@ public class NodeCachingLinkedList extends AbstractLinkedList implements Seriali
|
|||
* {@link #cacheSize} is decreased accordingly. The node that is returned
|
||||
* will have <code>null</code> values for next, previous and element.
|
||||
*
|
||||
* @return A node, or <code>null</code> if there are no nodes in the cache.
|
||||
* @return a node, or <code>null</code> if there are no nodes in the cache.
|
||||
*/
|
||||
protected Node getNodeFromCache() {
|
||||
if (cacheSize == 0) {
|
||||
|
@ -177,20 +190,27 @@ public class NodeCachingLinkedList extends AbstractLinkedList implements Seriali
|
|||
return cachedNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the cache is full.
|
||||
*
|
||||
* @return true if the cache is full
|
||||
*/
|
||||
protected boolean isCacheFull() {
|
||||
return cacheSize >= maximumCacheSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a node to the cache, if the cache isn't full. The node's contents
|
||||
* are cleared to so they can be garbage collected.
|
||||
* Adds a node to the cache, if the cache isn't full.
|
||||
* The node's contents are cleared to so they can be garbage collected.
|
||||
*
|
||||
* @param node the node to add to the cache
|
||||
*/
|
||||
protected void addNodeToCache(Node node) {
|
||||
if (isCacheFull()) {
|
||||
// Don't cache the node.
|
||||
// don't cache the node.
|
||||
return;
|
||||
}
|
||||
// Clear the node's contents and add it to the cache.
|
||||
// clear the node's contents and add it to the cache.
|
||||
Node nextCachedNode = firstCachedNode;
|
||||
node.previous = null;
|
||||
node.next = nextCachedNode;
|
||||
|
@ -201,47 +221,39 @@ public class NodeCachingLinkedList extends AbstractLinkedList implements Seriali
|
|||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Create a node, getting it from the cache if possible.
|
||||
*/
|
||||
protected Node createHeaderNode() {
|
||||
Node cachedNode = getNodeFromCache();
|
||||
if (cachedNode == null) {
|
||||
return super.createHeaderNode();
|
||||
} else {
|
||||
return cachedNode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new node with the specified properties, using a cached Node
|
||||
* if possible.
|
||||
* Creates a new node, either by reusing one from the cache or creating
|
||||
* a new one.
|
||||
*
|
||||
* @param previous node to precede the new node
|
||||
* @param next node to follow the new node
|
||||
* @param value value of the new node
|
||||
* @return the newly created node
|
||||
*/
|
||||
protected Node createNode(Node previous, Node next, Object value) {
|
||||
protected Node createNode(Object value) {
|
||||
Node cachedNode = getNodeFromCache();
|
||||
if (cachedNode == null) {
|
||||
return super.createNode(previous, next, value);
|
||||
return super.createNode(value);
|
||||
} else {
|
||||
cachedNode.next = next;
|
||||
cachedNode.previous = previous;
|
||||
cachedNode.value = value;
|
||||
return cachedNode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the superclass' implementation then calls
|
||||
* <code>addNodeToCache</code> on the node which has
|
||||
* been removed.
|
||||
* Removes the node from the list, storing it in the cache for reuse
|
||||
* if the cache is not yet full.
|
||||
*
|
||||
* @param node the node to remove
|
||||
*/
|
||||
protected void removeNode(Node node) {
|
||||
super.removeNode(node);
|
||||
addNodeToCache(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the nodes from the list, storing as many as required in the
|
||||
* cache for reuse.
|
||||
*
|
||||
* @param node the node to remove
|
||||
*/
|
||||
protected void removeAllNodes() {
|
||||
// Add the removed nodes to the cache, then remove the rest.
|
||||
// We can add them to the cache before removing them, since
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/list/TestAll.java,v 1.2 2003/12/11 00:18:06 scolebourne Exp $
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/list/TestAll.java,v 1.3 2003/12/24 01:15:40 scolebourne Exp $
|
||||
* ====================================================================
|
||||
*
|
||||
* The Apache Software License, Version 1.1
|
||||
|
@ -65,7 +65,7 @@ import junit.framework.TestSuite;
|
|||
* Entry point for tests.
|
||||
*
|
||||
* @since Commons Collections 3.0
|
||||
* @version $Revision: 1.2 $ $Date: 2003/12/11 00:18:06 $
|
||||
* @version $Revision: 1.3 $ $Date: 2003/12/24 01:15:40 $
|
||||
*
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
|
@ -83,6 +83,7 @@ public class TestAll extends TestCase {
|
|||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite();
|
||||
|
||||
suite.addTest(TestCursorableLinkedList.suite());
|
||||
suite.addTest(TestNodeCachingLinkedList.suite());
|
||||
|
||||
suite.addTest(TestFixedSizeList.suite());
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue