KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > collections > list > AbstractLinkedList


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.commons.collections.list;
17
18 import java.io.IOException JavaDoc;
19 import java.io.ObjectInputStream JavaDoc;
20 import java.io.ObjectOutputStream JavaDoc;
21 import java.lang.reflect.Array JavaDoc;
22 import java.util.AbstractList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.ConcurrentModificationException JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.ListIterator JavaDoc;
28 import java.util.NoSuchElementException JavaDoc;
29
30 import org.apache.commons.collections.OrderedIterator;
31
32 /**
33  * An abstract implementation of a linked list which provides numerous points for
34  * subclasses to override.
35  * <p>
36  * Overridable methods are provided to change the storage node and to change how
37  * nodes are added to and removed. Hopefully, all you need for unusual subclasses
38  * is here.
39  *
40  * @since Commons Collections 3.0
41  * @version $Revision: 1.9 $ $Date: 2004/04/20 23:33:54 $
42  *
43  * @author Rich Dougherty
44  * @author Phil Steitz
45  * @author Stephen Colebourne
46  */

47 public abstract class AbstractLinkedList implements List JavaDoc {
48
49     /*
50      * Implementation notes:
51      * - a standard circular doubly-linked list
52      * - a marker node is stored to mark the start and the end of the list
53      * - node creation and removal always occurs through createNode() and
54      * removeNode().
55      * - a modification count is kept, with the same semantics as
56      * {@link java.util.LinkedList}.
57      * - respects {@link AbstractList#modCount}
58      */

59
60     /**
61      * A {@link Node} which indicates the start and end of the list and does not
62      * hold a value. The value of <code>next</code> is the first item in the
63      * list. The value of of <code>previous</code> is the last item in the list.
64      */

65     protected transient Node header;
66     /** The size of the list */
67     protected transient int size;
68     /** Modification count for iterators */
69     protected transient int modCount;
70
71     /**
72      * Constructor that does nothing intended for deserialization.
73      * <p>
74      * If this constructor is used by a serializable subclass then the init()
75      * method must be called.
76      */

77     protected AbstractLinkedList() {
78         super();
79     }
80
81     /**
82      * Constructs a list copying data from the specified collection.
83      *
84      * @param coll the collection to copy
85      */

86     protected AbstractLinkedList(Collection JavaDoc coll) {
87         super();
88         init();
89         addAll(coll);
90     }
91
92     /**
93      * The equivalent of a default constructor, broken out so it can be called
94      * by any constructor and by <code>readObject</code>.
95      * Subclasses which override this method should make sure they call super,
96      * so the list is initialised properly.
97      */

98     protected void init() {
99         header = createHeaderNode();
100     }
101
102     //-----------------------------------------------------------------------
103
public int size() {
104         return size;
105     }
106
107     public boolean isEmpty() {
108         return (size() == 0);
109     }
110
111     public Object JavaDoc get(int index) {
112         Node node = getNode(index, false);
113         return node.getValue();
114     }
115
116     //-----------------------------------------------------------------------
117
public Iterator JavaDoc iterator() {
118         return listIterator();
119     }
120
121     public ListIterator JavaDoc listIterator() {
122         return new LinkedListIterator(this, 0);
123     }
124
125     public ListIterator JavaDoc listIterator(int fromIndex) {
126         return new LinkedListIterator(this, fromIndex);
127     }
128
129     //-----------------------------------------------------------------------
130
public int indexOf(Object JavaDoc value) {
131         int i = 0;
132         for (Node node = header.next; node != header; node = node.next) {
133             if (isEqualValue(node.getValue(), value)) {
134                 return i;
135             }
136             i++;
137         }
138         return -1;
139     }
140
141     public int lastIndexOf(Object JavaDoc value) {
142         int i = size - 1;
143         for (Node node = header.previous; node != header; node = node.previous) {
144             if (isEqualValue(node.getValue(), value)) {
145                 return i;
146             }
147             i--;
148         }
149         return -1;
150     }
151
152     public boolean contains(Object JavaDoc value) {
153         return indexOf(value) != -1;
154     }
155
156     public boolean containsAll(Collection JavaDoc coll) {
157         Iterator JavaDoc it = coll.iterator();
158         while (it.hasNext()) {
159             if (contains(it.next()) == false) {
160                 return false;
161             }
162         }
163         return true;
164     }
165     
166     //-----------------------------------------------------------------------
167
public Object JavaDoc[] toArray() {
168         return toArray(new Object JavaDoc[size]);
169     }
170
171     public Object JavaDoc[] toArray(Object JavaDoc[] array) {
172         // Extend the array if needed
173
if (array.length < size) {
174             Class JavaDoc componentType = array.getClass().getComponentType();
175             array = (Object JavaDoc[]) Array.newInstance(componentType, size);
176         }
177         // Copy the values into the array
178
int i = 0;
179         for (Node node = header.next; node != header; node = node.next, i++) {
180             array[i] = node.getValue();
181         }
182         // Set the value after the last value to null
183
if (array.length > size) {
184             array[size] = null;
185         }
186         return array;
187     }
188
189     /**
190      * Gets a sublist of the main list.
191      *
192      * @param fromIndexInclusive the index to start from
193      * @param toIndexExclusive the index to end at
194      * @return the new sublist
195      */

196     public List JavaDoc subList(int fromIndexInclusive, int toIndexExclusive) {
197         return new LinkedSubList(this, fromIndexInclusive, toIndexExclusive);
198     }
199     
200     //-----------------------------------------------------------------------
201
public boolean add(Object JavaDoc value) {
202         addLast(value);
203         return true;
204     }
205     
206     public void add(int index, Object JavaDoc value) {
207         Node node = getNode(index, true);
208         addNodeBefore(node, value);
209     }
210     
211     public boolean addAll(Collection JavaDoc coll) {
212         return addAll(size, coll);
213     }
214
215     public boolean addAll(int index, Collection JavaDoc coll) {
216         Node node = getNode(index, true);
217         for (Iterator JavaDoc itr = coll.iterator(); itr.hasNext();) {
218             Object JavaDoc value = itr.next();
219             addNodeBefore(node, value);
220         }
221         return true;
222     }
223
224     //-----------------------------------------------------------------------
225
public Object JavaDoc remove(int index) {
226         Node node = getNode(index, false);
227         Object JavaDoc oldValue = node.getValue();
228         removeNode(node);
229         return oldValue;
230     }
231
232     public boolean remove(Object JavaDoc value) {
233         for (Node node = header.next; node != header; node = node.next) {
234             if (isEqualValue(node.getValue(), value)) {
235                 removeNode(node);
236                 return true;
237             }
238         }
239         return false;
240     }
241
242     public boolean removeAll(Collection JavaDoc coll) {
243         boolean modified = false;
244         Iterator JavaDoc it = iterator();
245         while (it.hasNext()) {
246             if (coll.contains(it.next())) {
247                 it.remove();
248                 modified = true;
249             }
250         }
251         return modified;
252     }
253
254     //-----------------------------------------------------------------------
255
public boolean retainAll(Collection JavaDoc coll) {
256         boolean modified = false;
257         Iterator JavaDoc it = iterator();
258         while (it.hasNext()) {
259             if (coll.contains(it.next()) == false) {
260                 it.remove();
261                 modified = true;
262             }
263         }
264         return modified;
265     }
266
267     public Object JavaDoc set(int index, Object JavaDoc value) {
268         Node node = getNode(index, false);
269         Object JavaDoc oldValue = node.getValue();
270         updateNode(node, value);
271         return oldValue;
272     }
273
274     public void clear() {
275         removeAllNodes();
276     }
277     
278     //-----------------------------------------------------------------------
279
public Object JavaDoc getFirst() {
280         Node node = header.next;
281         if (node == header) {
282             throw new NoSuchElementException JavaDoc();
283         }
284         return node.getValue();
285     }
286
287     public Object JavaDoc getLast() {
288         Node node = header.previous;
289         if (node == header) {
290             throw new NoSuchElementException JavaDoc();
291         }
292         return node.getValue();
293     }
294
295     public boolean addFirst(Object JavaDoc o) {
296         addNodeAfter(header, o);
297         return true;
298     }
299
300     public boolean addLast(Object JavaDoc o) {
301         addNodeBefore(header, o);
302         return true;
303     }
304
305     public Object JavaDoc removeFirst() {
306         Node node = header.next;
307         if (node == header) {
308             throw new NoSuchElementException JavaDoc();
309         }
310         Object JavaDoc oldValue = node.getValue();
311         removeNode(node);
312         return oldValue;
313     }
314
315     public Object JavaDoc removeLast() {
316         Node node = header.previous;
317         if (node == header) {
318             throw new NoSuchElementException JavaDoc();
319         }
320         Object JavaDoc oldValue = node.getValue();
321         removeNode(node);
322         return oldValue;
323     }
324
325     //-----------------------------------------------------------------------
326
public boolean equals(Object JavaDoc obj) {
327         if (obj == this) {
328             return true;
329         }
330         if (obj instanceof List JavaDoc == false) {
331             return false;
332         }
333         List JavaDoc other = (List JavaDoc) obj;
334         if (other.size() != size()) {
335             return false;
336         }
337         ListIterator JavaDoc it1 = listIterator();
338         ListIterator JavaDoc it2 = other.listIterator();
339         while (it1.hasNext() && it2.hasNext()) {
340             Object JavaDoc o1 = it1.next();
341             Object JavaDoc o2 = it2.next();
342             if (!(o1 == null ? o2 == null : o1.equals(o2)))
343                 return false;
344         }
345         return !(it1.hasNext() || it2.hasNext());
346     }
347
348     public int hashCode() {
349         int hashCode = 1;
350         Iterator JavaDoc it = iterator();
351         while (it.hasNext()) {
352             Object JavaDoc obj = it.next();
353             hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
354         }
355         return hashCode;
356     }
357
358     public String JavaDoc toString() {
359         if (size() == 0) {
360             return "[]";
361         }
362         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(16 * size());
363         buf.append("[");
364
365         Iterator JavaDoc it = iterator();
366         boolean hasNext = it.hasNext();
367         while (hasNext) {
368             Object JavaDoc value = it.next();
369             buf.append(value == this ? "(this Collection)" : value);
370             hasNext = it.hasNext();
371             if (hasNext) {
372                 buf.append(", ");
373             }
374         }
375         buf.append("]");
376         return buf.toString();
377     }
378
379     //-----------------------------------------------------------------------
380
/**
381      * Compares two values for equals.
382      * This implementation uses the equals method.
383      * Subclasses can override this to match differently.
384      *
385      * @param value1 the first value to compare, may be null
386      * @param value2 the second value to compare, may be null
387      * @return true if equal
388      */

389     protected boolean isEqualValue(Object JavaDoc value1, Object JavaDoc value2) {
390         return (value1 == value2 || (value1 == null ? false : value1.equals(value2)));
391     }
392     
393     /**
394      * Updates the node with a new value.
395      * This implementation sets the value on the node.
396      * Subclasses can override this to record the change.
397      *
398      * @param node node to update
399      * @param value new value of the node
400      */

401     protected void updateNode(Node node, Object JavaDoc value) {
402         node.setValue(value);
403     }
404
405     /**
406      * Creates a new node with previous, next and element all set to null.
407      * This implementation creates a new empty Node.
408      * Subclasses can override this to create a different class.
409      *
410      * @return newly created node
411      */

412     protected Node createHeaderNode() {
413         return new Node();
414     }
415
416     /**
417      * Creates a new node with the specified properties.
418      * This implementation creates a new Node with data.
419      * Subclasses can override this to create a different class.
420      *
421      * @param value value of the new node
422      */

423     protected Node createNode(Object JavaDoc value) {
424         return new Node(value);
425     }
426
427     /**
428      * Creates a new node with the specified object as its
429      * <code>value</code> and inserts it before <code>node</code>.
430      * <p>
431      * This implementation uses {@link #createNode(Object)} and
432      * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}.
433      *
434      * @param node node to insert before
435      * @param value value of the newly added node
436      * @throws NullPointerException if <code>node</code> is null
437      */

438     protected void addNodeBefore(Node node, Object JavaDoc value) {
439         Node newNode = createNode(value);
440         addNode(newNode, node);
441     }
442
443     /**
444      * Creates a new node with the specified object as its
445      * <code>value</code> and inserts it after <code>node</code>.
446      * <p>
447      * This implementation uses {@link #createNode(Object)} and
448      * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}.
449      *
450      * @param node node to insert after
451      * @param value value of the newly added node
452      * @throws NullPointerException if <code>node</code> is null
453      */

454     protected void addNodeAfter(Node node, Object JavaDoc value) {
455         Node newNode = createNode(value);
456         addNode(newNode, node.next);
457     }
458
459     /**
460      * Inserts a new node into the list.
461      *
462      * @param nodeToInsert new node to insert
463      * @param insertBeforeNode node to insert before
464      * @throws NullPointerException if either node is null
465      */

466     protected void addNode(Node nodeToInsert, Node insertBeforeNode) {
467         nodeToInsert.next = insertBeforeNode;
468         nodeToInsert.previous = insertBeforeNode.previous;
469         insertBeforeNode.previous.next = nodeToInsert;
470         insertBeforeNode.previous = nodeToInsert;
471         size++;
472         modCount++;
473     }
474
475     /**
476      * Removes the specified node from the list.
477      *
478      * @param node the node to remove
479      * @throws NullPointerException if <code>node</code> is null
480      */

481     protected void removeNode(Node node) {
482         node.previous.next = node.next;
483         node.next.previous = node.previous;
484         size--;
485         modCount++;
486     }
487
488     /**
489      * Removes all nodes by resetting the circular list marker.
490      */

491     protected void removeAllNodes() {
492         header.next = header;
493         header.previous = header;
494         size = 0;
495         modCount++;
496     }
497
498     /**
499      * Gets the node at a particular index.
500      *
501      * @param index the index, starting from 0
502      * @param endMarkerAllowed whether or not the end marker can be returned if
503      * startIndex is set to the list's size
504      * @throws IndexOutOfBoundsException if the index is less than 0; equal to
505      * the size of the list and endMakerAllowed is false; or greater than the
506      * size of the list
507      */

508     protected Node getNode(int index, boolean endMarkerAllowed) throws IndexOutOfBoundsException JavaDoc {
509         // Check the index is within the bounds
510
if (index < 0) {
511             throw new IndexOutOfBoundsException JavaDoc("Couldn't get the node: " +
512                     "index (" + index + ") less than zero.");
513         }
514         if (!endMarkerAllowed && index == size) {
515             throw new IndexOutOfBoundsException JavaDoc("Couldn't get the node: " +
516                     "index (" + index + ") is the size of the list.");
517         }
518         if (index > size) {
519             throw new IndexOutOfBoundsException JavaDoc("Couldn't get the node: " +
520                     "index (" + index + ") greater than the size of the " +
521                     "list (" + size + ").");
522         }
523         // Search the list and get the node
524
Node node;
525         if (index < (size / 2)) {
526             // Search forwards
527
node = header.next;
528             for (int currentIndex = 0; currentIndex < index; currentIndex++) {
529                 node = node.next;
530             }
531         } else {
532             // Search backwards
533
node = header;
534             for (int currentIndex = size; currentIndex > index; currentIndex--) {
535                 node = node.previous;
536             }
537         }
538         return node;
539     }
540
541     //-----------------------------------------------------------------------
542
/**
543      * Creates an iterator for the sublist.
544      *
545      * @param subList the sublist to get an iterator for
546      */

547     protected Iterator JavaDoc createSubListIterator(LinkedSubList subList) {
548         return createSubListListIterator(subList, 0);
549     }
550
551     /**
552      * Creates a list iterator for the sublist.
553      *
554      * @param subList the sublist to get an iterator for
555      * @param fromIndex the index to start from, relative to the sublist
556      */

557     protected ListIterator JavaDoc createSubListListIterator(LinkedSubList subList, int fromIndex) {
558         return new LinkedSubListIterator(subList, fromIndex);
559     }
560
561     //-----------------------------------------------------------------------
562
/**
563      * Serializes the data held in this object to the stream specified.
564      * <p>
565      * The first serializable subclass must call this method from
566      * <code>writeObject</code>.
567      */

568     protected void doWriteObject(ObjectOutputStream JavaDoc outputStream) throws IOException JavaDoc {
569         // Write the size so we know how many nodes to read back
570
outputStream.writeInt(size());
571         for (Iterator JavaDoc itr = iterator(); itr.hasNext();) {
572             outputStream.writeObject(itr.next());
573         }
574     }
575
576     /**
577      * Deserializes the data held in this object to the stream specified.
578      * <p>
579      * The first serializable subclass must call this method from
580      * <code>readObject</code>.
581      */

582     protected void doReadObject(ObjectInputStream JavaDoc inputStream) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
583         init();
584         int size = inputStream.readInt();
585         for (int i = 0; i < size; i++) {
586             add(inputStream.readObject());
587         }
588     }
589
590     //-----------------------------------------------------------------------
591
/**
592      * A node within the linked list.
593      * <p>
594      * From Commons Collections 3.1, all access to the <code>value</code> property
595      * is via the methods on this class.
596      */

597     protected static class Node {
598
599         /** A pointer to the node before this node */
600         protected Node previous;
601         /** A pointer to the node after this node */
602         protected Node next;
603         /** The object contained within this node */
604         protected Object JavaDoc value;
605
606         /**
607          * Constructs a new header node.
608          */

609         protected Node() {
610             super();
611             previous = this;
612             next = this;
613         }
614
615         /**
616          * Constructs a new node.
617          *
618          * @param value the value to store
619          */

620         protected Node(Object JavaDoc value) {
621             super();
622             this.value = value;
623         }
624         
625         /**
626          * Constructs a new node.
627          *
628          * @param previous the previous node in the list
629          * @param next the next node in the list
630          * @param value the value to store
631          */

632         protected Node(Node previous, Node next, Object JavaDoc value) {
633             super();
634             this.previous = previous;
635             this.next = next;
636             this.value = value;
637         }
638         
639         /**
640          * Gets the value of the node.
641          *
642          * @return the value
643          * @since Commons Collections 3.1
644          */

645         protected Object JavaDoc getValue() {
646             return value;
647         }
648         
649         /**
650          * Sets the value of the node.
651          *
652          * @param value the value
653          * @since Commons Collections 3.1
654          */

655         protected void setValue(Object JavaDoc value) {
656             this.value = value;
657         }
658         
659         /**
660          * Gets the previous node.
661          *
662          * @return the previous node
663          * @since Commons Collections 3.1
664          */

665         protected Node getPreviousNode() {
666             return previous;
667         }
668         
669         /**
670          * Sets the previous node.
671          *
672          * @param previous the previous node
673          * @since Commons Collections 3.1
674          */

675         protected void setPreviousNode(Node previous) {
676             this.previous = previous;
677         }
678         
679         /**
680          * Gets the next node.
681          *
682          * @return the next node
683          * @since Commons Collections 3.1
684          */

685         protected Node getNextNode() {
686             return next;
687         }
688         
689         /**
690          * Sets the next node.
691          *
692          * @param next the next node
693          * @since Commons Collections 3.1
694          */

695         protected void setNextNode(Node next) {
696             this.next = next;
697         }
698     }
699
700     //-----------------------------------------------------------------------
701
/**
702      * A list iterator over the linked list.
703      */

704     protected static class LinkedListIterator implements ListIterator JavaDoc, OrderedIterator {
705         
706         /** The parent list */
707         protected final AbstractLinkedList parent;
708
709         /**
710          * The node that will be returned by {@link #next()}. If this is equal
711          * to {@link AbstractLinkedList#header} then there are no more values to return.
712          */

713         protected Node next;
714
715         /**
716          * The index of {@link #next}.
717          */

718         protected int nextIndex;
719
720         /**
721          * The last node that was returned by {@link #next()} or {@link
722          * #previous()}. Set to <code>null</code> if {@link #next()} or {@link
723          * #previous()} haven't been called, or if the node has been removed
724          * with {@link #remove()} or a new node added with {@link #add(Object)}.
725          * Should be accessed through {@link #getLastNodeReturned()} to enforce
726          * this behaviour.
727          */

728         protected Node current;
729
730         /**
731          * The modification count that the list is expected to have. If the list
732          * doesn't have this count, then a
733          * {@link java.util.ConcurrentModificationException} may be thrown by
734          * the operations.
735          */

736         protected int expectedModCount;
737
738         /**
739          * Create a ListIterator for a list.
740          *
741          * @param parent the parent list
742          * @param fromIndex the index to start at
743          */

744         protected LinkedListIterator(AbstractLinkedList parent, int fromIndex) throws IndexOutOfBoundsException JavaDoc {
745             super();
746             this.parent = parent;
747             this.expectedModCount = parent.modCount;
748             this.next = parent.getNode(fromIndex, true);
749             this.nextIndex = fromIndex;
750         }
751
752         /**
753          * Checks the modification count of the list is the value that this
754          * object expects.
755          *
756          * @throws ConcurrentModificationException If the list's modification
757          * count isn't the value that was expected.
758          */

759         protected void checkModCount() {
760             if (parent.modCount != expectedModCount) {
761                 throw new ConcurrentModificationException JavaDoc();
762             }
763         }
764
765         /**
766          * Gets the last node returned.
767          *
768          * @throws IllegalStateException If {@link #next()} or
769          * {@link #previous()} haven't been called, or if the node has been removed
770          * with {@link #remove()} or a new node added with {@link #add(Object)}.
771          */

772         protected Node getLastNodeReturned() throws IllegalStateException JavaDoc {
773             if (current == null) {
774                 throw new IllegalStateException JavaDoc();
775             }
776             return current;
777         }
778
779         public boolean hasNext() {
780             return next != parent.header;
781         }
782
783         public Object JavaDoc next() {
784             checkModCount();
785             if (!hasNext()) {
786                 throw new NoSuchElementException JavaDoc("No element at index " + nextIndex + ".");
787             }
788             Object JavaDoc value = next.getValue();
789             current = next;
790             next = next.next;
791             nextIndex++;
792             return value;
793         }
794
795         public boolean hasPrevious() {
796             return next.previous != parent.header;
797         }
798
799         public Object JavaDoc previous() {
800             checkModCount();
801             if (!hasPrevious()) {
802                 throw new NoSuchElementException JavaDoc("Already at start of list.");
803             }
804             next = next.previous;
805             Object JavaDoc value = next.getValue();
806             current = next;
807             nextIndex--;
808             return value;
809         }
810
811         public int nextIndex() {
812             return nextIndex;
813         }
814
815         public int previousIndex() {
816             // not normally overridden, as relative to nextIndex()
817
return nextIndex() - 1;
818         }
819
820         public void remove() {
821             checkModCount();
822             parent.removeNode(getLastNodeReturned());
823             current = null;
824             nextIndex--;
825             expectedModCount++;
826         }
827
828         public void set(Object JavaDoc obj) {
829             checkModCount();
830             getLastNodeReturned().setValue(obj);
831         }
832
833         public void add(Object JavaDoc obj) {
834             checkModCount();
835             parent.addNodeBefore(next, obj);
836             current = null;
837             nextIndex++;
838             expectedModCount++;
839         }
840
841     }
842
843     //-----------------------------------------------------------------------
844
/**
845      * A list iterator over the linked sub list.
846      */

847     protected static class LinkedSubListIterator extends LinkedListIterator {
848         
849         /** The parent list */
850         protected final LinkedSubList sub;
851         
852         protected LinkedSubListIterator(LinkedSubList sub, int startIndex) {
853             super(sub.parent, startIndex + sub.offset);
854             this.sub = sub;
855         }
856
857         public boolean hasNext() {
858             return (nextIndex() < sub.size);
859         }
860
861         public boolean hasPrevious() {
862             return (previousIndex() >= 0);
863         }
864
865         public int nextIndex() {
866             return (super.nextIndex() - sub.offset);
867         }
868
869         public void add(Object JavaDoc obj) {
870             super.add(obj);
871             sub.expectedModCount = parent.modCount;
872             sub.size++;
873         }
874         
875         public void remove() {
876             super.remove();
877             sub.expectedModCount = parent.modCount;
878             sub.size--;
879         }
880     }
881     
882     //-----------------------------------------------------------------------
883
/**
884      * The sublist implementation for AbstractLinkedList.
885      */

886     protected static class LinkedSubList extends AbstractList JavaDoc {
887         /** The main list */
888         private AbstractLinkedList parent;
889         /** Offset from the main list */
890         private int offset;
891         /** Sublist size */
892         private int size;
893         /** Sublist modCount */
894         private int expectedModCount;
895
896         protected LinkedSubList(AbstractLinkedList parent, int fromIndex, int toIndex) {
897             if (fromIndex < 0) {
898                 throw new IndexOutOfBoundsException JavaDoc("fromIndex = " + fromIndex);
899             }
900             if (toIndex > parent.size()) {
901                 throw new IndexOutOfBoundsException JavaDoc("toIndex = " + toIndex);
902             }
903             if (fromIndex > toIndex) {
904                 throw new IllegalArgumentException JavaDoc("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
905             }
906             this.parent = parent;
907             this.offset = fromIndex;
908             this.size = toIndex - fromIndex;
909             this.expectedModCount = parent.modCount;
910         }
911
912         public int size() {
913             checkModCount();
914             return size;
915         }
916
917         public Object JavaDoc get(int index) {
918             rangeCheck(index, size);
919             checkModCount();
920             return parent.get(index + offset);
921         }
922
923         public void add(int index, Object JavaDoc obj) {
924             rangeCheck(index, size + 1);
925             checkModCount();
926             parent.add(index + offset, obj);
927             expectedModCount = parent.modCount;
928             size++;
929             LinkedSubList.this.modCount++;
930         }
931
932         public Object JavaDoc remove(int index) {
933             rangeCheck(index, size);
934             checkModCount();
935             Object JavaDoc result = parent.remove(index + offset);
936             expectedModCount = parent.modCount;
937             size--;
938             LinkedSubList.this.modCount++;
939             return result;
940         }
941
942         public boolean addAll(Collection JavaDoc coll) {
943             return addAll(size, coll);
944         }
945
946         public boolean addAll(int index, Collection JavaDoc coll) {
947             rangeCheck(index, size + 1);
948             int cSize = coll.size();
949             if (cSize == 0) {
950                 return false;
951             }
952
953             checkModCount();
954             parent.addAll(offset + index, coll);
955             expectedModCount = parent.modCount;
956             size += cSize;
957             LinkedSubList.this.modCount++;
958             return true;
959         }
960
961         public Object JavaDoc set(int index, Object JavaDoc obj) {
962             rangeCheck(index, size);
963             checkModCount();
964             return parent.set(index + offset, obj);
965         }
966
967         public void clear() {
968             checkModCount();
969             Iterator JavaDoc it = iterator();
970             while (it.hasNext()) {
971                 it.next();
972                 it.remove();
973             }
974         }
975
976         public Iterator JavaDoc iterator() {
977             checkModCount();
978             return parent.createSubListIterator(this);
979         }
980
981         public ListIterator JavaDoc listIterator(final int index) {
982             rangeCheck(index, size + 1);
983             checkModCount();
984             return parent.createSubListListIterator(this, index);
985         }
986
987         public List JavaDoc subList(int fromIndexInclusive, int toIndexExclusive) {
988             return new LinkedSubList(parent, fromIndexInclusive + offset, toIndexExclusive + offset);
989         }
990
991         protected void rangeCheck(int index, int beyond) {
992             if (index < 0 || index >= beyond) {
993                 throw new IndexOutOfBoundsException JavaDoc("Index '" + index + "' out of bounds for size '" + size + "'");
994             }
995         }
996
997         protected void checkModCount() {
998             if (parent.modCount != expectedModCount) {
999                 throw new ConcurrentModificationException JavaDoc();
1000            }
1001        }
1002    }
1003    
1004}
1005
Popular Tags