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. import java.io.IOException;
  18. import java.io.ObjectInputStream;
  19. import java.io.ObjectOutputStream;
  20. import java.lang.reflect.Array;
  21. import java.util.AbstractList;
  22. import java.util.Collection;
  23. import java.util.ConcurrentModificationException;
  24. import java.util.Iterator;
  25. import java.util.List;
  26. import java.util.ListIterator;
  27. import java.util.NoSuchElementException;
  28. import org.apache.commons.collections.OrderedIterator;
  29. /**
  30. * An abstract implementation of a linked list which provides numerous points for
  31. * subclasses to override.
  32. * <p>
  33. * Overridable methods are provided to change the storage node and to change how
  34. * nodes are added to and removed. Hopefully, all you need for unusual subclasses
  35. * is here.
  36. *
  37. * @since Commons Collections 3.0
  38. * @version $Revision: 1.9 $ $Date: 2004/04/20 23:33:54 $
  39. *
  40. * @author Rich Dougherty
  41. * @author Phil Steitz
  42. * @author Stephen Colebourne
  43. */
  44. public abstract class AbstractLinkedList implements List {
  45. /*
  46. * Implementation notes:
  47. * - a standard circular doubly-linked list
  48. * - a marker node is stored to mark the start and the end of the list
  49. * - node creation and removal always occurs through createNode() and
  50. * removeNode().
  51. * - a modification count is kept, with the same semantics as
  52. * {@link java.util.LinkedList}.
  53. * - respects {@link AbstractList#modCount}
  54. */
  55. /**
  56. * A {@link Node} which indicates the start and end of the list and does not
  57. * hold a value. The value of <code>next</code> is the first item in the
  58. * list. The value of of <code>previous</code> is the last item in the list.
  59. */
  60. protected transient Node header;
  61. /** The size of the list */
  62. protected transient int size;
  63. /** Modification count for iterators */
  64. protected transient int modCount;
  65. /**
  66. * Constructor that does nothing intended for deserialization.
  67. * <p>
  68. * If this constructor is used by a serializable subclass then the init()
  69. * method must be called.
  70. */
  71. protected AbstractLinkedList() {
  72. super();
  73. }
  74. /**
  75. * Constructs a list copying data from the specified collection.
  76. *
  77. * @param coll the collection to copy
  78. */
  79. protected AbstractLinkedList(Collection coll) {
  80. super();
  81. init();
  82. addAll(coll);
  83. }
  84. /**
  85. * The equivalent of a default constructor, broken out so it can be called
  86. * by any constructor and by <code>readObject</code>.
  87. * Subclasses which override this method should make sure they call super,
  88. * so the list is initialised properly.
  89. */
  90. protected void init() {
  91. header = createHeaderNode();
  92. }
  93. //-----------------------------------------------------------------------
  94. public int size() {
  95. return size;
  96. }
  97. public boolean isEmpty() {
  98. return (size() == 0);
  99. }
  100. public Object get(int index) {
  101. Node node = getNode(index, false);
  102. return node.getValue();
  103. }
  104. //-----------------------------------------------------------------------
  105. public Iterator iterator() {
  106. return listIterator();
  107. }
  108. public ListIterator listIterator() {
  109. return new LinkedListIterator(this, 0);
  110. }
  111. public ListIterator listIterator(int fromIndex) {
  112. return new LinkedListIterator(this, fromIndex);
  113. }
  114. //-----------------------------------------------------------------------
  115. public int indexOf(Object value) {
  116. int i = 0;
  117. for (Node node = header.next; node != header; node = node.next) {
  118. if (isEqualValue(node.getValue(), value)) {
  119. return i;
  120. }
  121. i++;
  122. }
  123. return -1;
  124. }
  125. public int lastIndexOf(Object value) {
  126. int i = size - 1;
  127. for (Node node = header.previous; node != header; node = node.previous) {
  128. if (isEqualValue(node.getValue(), value)) {
  129. return i;
  130. }
  131. i--;
  132. }
  133. return -1;
  134. }
  135. public boolean contains(Object value) {
  136. return indexOf(value) != -1;
  137. }
  138. public boolean containsAll(Collection coll) {
  139. Iterator it = coll.iterator();
  140. while (it.hasNext()) {
  141. if (contains(it.next()) == false) {
  142. return false;
  143. }
  144. }
  145. return true;
  146. }
  147. //-----------------------------------------------------------------------
  148. public Object[] toArray() {
  149. return toArray(new Object[size]);
  150. }
  151. public Object[] toArray(Object[] array) {
  152. // Extend the array if needed
  153. if (array.length < size) {
  154. Class componentType = array.getClass().getComponentType();
  155. array = (Object[]) Array.newInstance(componentType, size);
  156. }
  157. // Copy the values into the array
  158. int i = 0;
  159. for (Node node = header.next; node != header; node = node.next, i++) {
  160. array[i] = node.getValue();
  161. }
  162. // Set the value after the last value to null
  163. if (array.length > size) {
  164. array[size] = null;
  165. }
  166. return array;
  167. }
  168. /**
  169. * Gets a sublist of the main list.
  170. *
  171. * @param fromIndexInclusive the index to start from
  172. * @param toIndexExclusive the index to end at
  173. * @return the new sublist
  174. */
  175. public List subList(int fromIndexInclusive, int toIndexExclusive) {
  176. return new LinkedSubList(this, fromIndexInclusive, toIndexExclusive);
  177. }
  178. //-----------------------------------------------------------------------
  179. public boolean add(Object value) {
  180. addLast(value);
  181. return true;
  182. }
  183. public void add(int index, Object value) {
  184. Node node = getNode(index, true);
  185. addNodeBefore(node, value);
  186. }
  187. public boolean addAll(Collection coll) {
  188. return addAll(size, coll);
  189. }
  190. public boolean addAll(int index, Collection coll) {
  191. Node node = getNode(index, true);
  192. for (Iterator itr = coll.iterator(); itr.hasNext();) {
  193. Object value = itr.next();
  194. addNodeBefore(node, value);
  195. }
  196. return true;
  197. }
  198. //-----------------------------------------------------------------------
  199. public Object remove(int index) {
  200. Node node = getNode(index, false);
  201. Object oldValue = node.getValue();
  202. removeNode(node);
  203. return oldValue;
  204. }
  205. public boolean remove(Object value) {
  206. for (Node node = header.next; node != header; node = node.next) {
  207. if (isEqualValue(node.getValue(), value)) {
  208. removeNode(node);
  209. return true;
  210. }
  211. }
  212. return false;
  213. }
  214. public boolean removeAll(Collection coll) {
  215. boolean modified = false;
  216. Iterator it = iterator();
  217. while (it.hasNext()) {
  218. if (coll.contains(it.next())) {
  219. it.remove();
  220. modified = true;
  221. }
  222. }
  223. return modified;
  224. }
  225. //-----------------------------------------------------------------------
  226. public boolean retainAll(Collection coll) {
  227. boolean modified = false;
  228. Iterator it = iterator();
  229. while (it.hasNext()) {
  230. if (coll.contains(it.next()) == false) {
  231. it.remove();
  232. modified = true;
  233. }
  234. }
  235. return modified;
  236. }
  237. public Object set(int index, Object value) {
  238. Node node = getNode(index, false);
  239. Object oldValue = node.getValue();
  240. updateNode(node, value);
  241. return oldValue;
  242. }
  243. public void clear() {
  244. removeAllNodes();
  245. }
  246. //-----------------------------------------------------------------------
  247. public Object getFirst() {
  248. Node node = header.next;
  249. if (node == header) {
  250. throw new NoSuchElementException();
  251. }
  252. return node.getValue();
  253. }
  254. public Object getLast() {
  255. Node node = header.previous;
  256. if (node == header) {
  257. throw new NoSuchElementException();
  258. }
  259. return node.getValue();
  260. }
  261. public boolean addFirst(Object o) {
  262. addNodeAfter(header, o);
  263. return true;
  264. }
  265. public boolean addLast(Object o) {
  266. addNodeBefore(header, o);
  267. return true;
  268. }
  269. public Object removeFirst() {
  270. Node node = header.next;
  271. if (node == header) {
  272. throw new NoSuchElementException();
  273. }
  274. Object oldValue = node.getValue();
  275. removeNode(node);
  276. return oldValue;
  277. }
  278. public Object removeLast() {
  279. Node node = header.previous;
  280. if (node == header) {
  281. throw new NoSuchElementException();
  282. }
  283. Object oldValue = node.getValue();
  284. removeNode(node);
  285. return oldValue;
  286. }
  287. //-----------------------------------------------------------------------
  288. public boolean equals(Object obj) {
  289. if (obj == this) {
  290. return true;
  291. }
  292. if (obj instanceof List == false) {
  293. return false;
  294. }
  295. List other = (List) obj;
  296. if (other.size() != size()) {
  297. return false;
  298. }
  299. ListIterator it1 = listIterator();
  300. ListIterator it2 = other.listIterator();
  301. while (it1.hasNext() && it2.hasNext()) {
  302. Object o1 = it1.next();
  303. Object o2 = it2.next();
  304. if (!(o1 == null ? o2 == null : o1.equals(o2)))
  305. return false;
  306. }
  307. return !(it1.hasNext() || it2.hasNext());
  308. }
  309. public int hashCode() {
  310. int hashCode = 1;
  311. Iterator it = iterator();
  312. while (it.hasNext()) {
  313. Object obj = it.next();
  314. hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
  315. }
  316. return hashCode;
  317. }
  318. public String toString() {
  319. if (size() == 0) {
  320. return "[]";
  321. }
  322. StringBuffer buf = new StringBuffer(16 * size());
  323. buf.append("[");
  324. Iterator it = iterator();
  325. boolean hasNext = it.hasNext();
  326. while (hasNext) {
  327. Object value = it.next();
  328. buf.append(value == this ? "(this Collection)" : value);
  329. hasNext = it.hasNext();
  330. if (hasNext) {
  331. buf.append(", ");
  332. }
  333. }
  334. buf.append("]");
  335. return buf.toString();
  336. }
  337. //-----------------------------------------------------------------------
  338. /**
  339. * Compares two values for equals.
  340. * This implementation uses the equals method.
  341. * Subclasses can override this to match differently.
  342. *
  343. * @param value1 the first value to compare, may be null
  344. * @param value2 the second value to compare, may be null
  345. * @return true if equal
  346. */
  347. protected boolean isEqualValue(Object value1, Object value2) {
  348. return (value1 == value2 || (value1 == null ? false : value1.equals(value2)));
  349. }
  350. /**
  351. * Updates the node with a new value.
  352. * This implementation sets the value on the node.
  353. * Subclasses can override this to record the change.
  354. *
  355. * @param node node to update
  356. * @param value new value of the node
  357. */
  358. protected void updateNode(Node node, Object value) {
  359. node.setValue(value);
  360. }
  361. /**
  362. * Creates a new node with previous, next and element all set to null.
  363. * This implementation creates a new empty Node.
  364. * Subclasses can override this to create a different class.
  365. *
  366. * @return newly created node
  367. */
  368. protected Node createHeaderNode() {
  369. return new Node();
  370. }
  371. /**
  372. * Creates a new node with the specified properties.
  373. * This implementation creates a new Node with data.
  374. * Subclasses can override this to create a different class.
  375. *
  376. * @param value value of the new node
  377. */
  378. protected Node createNode(Object value) {
  379. return new Node(value);
  380. }
  381. /**
  382. * Creates a new node with the specified object as its
  383. * <code>value</code> and inserts it before <code>node</code>.
  384. * <p>
  385. * This implementation uses {@link #createNode(Object)} and
  386. * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}.
  387. *
  388. * @param node node to insert before
  389. * @param value value of the newly added node
  390. * @throws NullPointerException if <code>node</code> is null
  391. */
  392. protected void addNodeBefore(Node node, Object value) {
  393. Node newNode = createNode(value);
  394. addNode(newNode, node);
  395. }
  396. /**
  397. * Creates a new node with the specified object as its
  398. * <code>value</code> and inserts it after <code>node</code>.
  399. * <p>
  400. * This implementation uses {@link #createNode(Object)} and
  401. * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}.
  402. *
  403. * @param node node to insert after
  404. * @param value value of the newly added node
  405. * @throws NullPointerException if <code>node</code> is null
  406. */
  407. protected void addNodeAfter(Node node, Object value) {
  408. Node newNode = createNode(value);
  409. addNode(newNode, node.next);
  410. }
  411. /**
  412. * Inserts a new node into the list.
  413. *
  414. * @param nodeToInsert new node to insert
  415. * @param insertBeforeNode node to insert before
  416. * @throws NullPointerException if either node is null
  417. */
  418. protected void addNode(Node nodeToInsert, Node insertBeforeNode) {
  419. nodeToInsert.next = insertBeforeNode;
  420. nodeToInsert.previous = insertBeforeNode.previous;
  421. insertBeforeNode.previous.next = nodeToInsert;
  422. insertBeforeNode.previous = nodeToInsert;
  423. size++;
  424. modCount++;
  425. }
  426. /**
  427. * Removes the specified node from the list.
  428. *
  429. * @param node the node to remove
  430. * @throws NullPointerException if <code>node</code> is null
  431. */
  432. protected void removeNode(Node node) {
  433. node.previous.next = node.next;
  434. node.next.previous = node.previous;
  435. size--;
  436. modCount++;
  437. }
  438. /**
  439. * Removes all nodes by resetting the circular list marker.
  440. */
  441. protected void removeAllNodes() {
  442. header.next = header;
  443. header.previous = header;
  444. size = 0;
  445. modCount++;
  446. }
  447. /**
  448. * Gets the node at a particular index.
  449. *
  450. * @param index the index, starting from 0
  451. * @param endMarkerAllowed whether or not the end marker can be returned if
  452. * startIndex is set to the list's size
  453. * @throws IndexOutOfBoundsException if the index is less than 0; equal to
  454. * the size of the list and endMakerAllowed is false; or greater than the
  455. * size of the list
  456. */
  457. protected Node getNode(int index, boolean endMarkerAllowed) throws IndexOutOfBoundsException {
  458. // Check the index is within the bounds
  459. if (index < 0) {
  460. throw new IndexOutOfBoundsException("Couldn't get the node: " +
  461. "index (" + index + ") less than zero.");
  462. }
  463. if (!endMarkerAllowed && index == size) {
  464. throw new IndexOutOfBoundsException("Couldn't get the node: " +
  465. "index (" + index + ") is the size of the list.");
  466. }
  467. if (index > size) {
  468. throw new IndexOutOfBoundsException("Couldn't get the node: " +
  469. "index (" + index + ") greater than the size of the " +
  470. "list (" + size + ").");
  471. }
  472. // Search the list and get the node
  473. Node node;
  474. if (index < (size / 2)) {
  475. // Search forwards
  476. node = header.next;
  477. for (int currentIndex = 0; currentIndex < index; currentIndex++) {
  478. node = node.next;
  479. }
  480. } else {
  481. // Search backwards
  482. node = header;
  483. for (int currentIndex = size; currentIndex > index; currentIndex--) {
  484. node = node.previous;
  485. }
  486. }
  487. return node;
  488. }
  489. //-----------------------------------------------------------------------
  490. /**
  491. * Creates an iterator for the sublist.
  492. *
  493. * @param subList the sublist to get an iterator for
  494. */
  495. protected Iterator createSubListIterator(LinkedSubList subList) {
  496. return createSubListListIterator(subList, 0);
  497. }
  498. /**
  499. * Creates a list iterator for the sublist.
  500. *
  501. * @param subList the sublist to get an iterator for
  502. * @param fromIndex the index to start from, relative to the sublist
  503. */
  504. protected ListIterator createSubListListIterator(LinkedSubList subList, int fromIndex) {
  505. return new LinkedSubListIterator(subList, fromIndex);
  506. }
  507. //-----------------------------------------------------------------------
  508. /**
  509. * Serializes the data held in this object to the stream specified.
  510. * <p>
  511. * The first serializable subclass must call this method from
  512. * <code>writeObject</code>.
  513. */
  514. protected void doWriteObject(ObjectOutputStream outputStream) throws IOException {
  515. // Write the size so we know how many nodes to read back
  516. outputStream.writeInt(size());
  517. for (Iterator itr = iterator(); itr.hasNext();) {
  518. outputStream.writeObject(itr.next());
  519. }
  520. }
  521. /**
  522. * Deserializes the data held in this object to the stream specified.
  523. * <p>
  524. * The first serializable subclass must call this method from
  525. * <code>readObject</code>.
  526. */
  527. protected void doReadObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
  528. init();
  529. int size = inputStream.readInt();
  530. for (int i = 0; i < size; i++) {
  531. add(inputStream.readObject());
  532. }
  533. }
  534. //-----------------------------------------------------------------------
  535. /**
  536. * A node within the linked list.
  537. * <p>
  538. * From Commons Collections 3.1, all access to the <code>value</code> property
  539. * is via the methods on this class.
  540. */
  541. protected static class Node {
  542. /** A pointer to the node before this node */
  543. protected Node previous;
  544. /** A pointer to the node after this node */
  545. protected Node next;
  546. /** The object contained within this node */
  547. protected Object value;
  548. /**
  549. * Constructs a new header node.
  550. */
  551. protected Node() {
  552. super();
  553. previous = this;
  554. next = this;
  555. }
  556. /**
  557. * Constructs a new node.
  558. *
  559. * @param value the value to store
  560. */
  561. protected Node(Object value) {
  562. super();
  563. this.value = value;
  564. }
  565. /**
  566. * Constructs a new node.
  567. *
  568. * @param previous the previous node in the list
  569. * @param next the next node in the list
  570. * @param value the value to store
  571. */
  572. protected Node(Node previous, Node next, Object value) {
  573. super();
  574. this.previous = previous;
  575. this.next = next;
  576. this.value = value;
  577. }
  578. /**
  579. * Gets the value of the node.
  580. *
  581. * @return the value
  582. * @since Commons Collections 3.1
  583. */
  584. protected Object getValue() {
  585. return value;
  586. }
  587. /**
  588. * Sets the value of the node.
  589. *
  590. * @param value the value
  591. * @since Commons Collections 3.1
  592. */
  593. protected void setValue(Object value) {
  594. this.value = value;
  595. }
  596. /**
  597. * Gets the previous node.
  598. *
  599. * @return the previous node
  600. * @since Commons Collections 3.1
  601. */
  602. protected Node getPreviousNode() {
  603. return previous;
  604. }
  605. /**
  606. * Sets the previous node.
  607. *
  608. * @param previous the previous node
  609. * @since Commons Collections 3.1
  610. */
  611. protected void setPreviousNode(Node previous) {
  612. this.previous = previous;
  613. }
  614. /**
  615. * Gets the next node.
  616. *
  617. * @return the next node
  618. * @since Commons Collections 3.1
  619. */
  620. protected Node getNextNode() {
  621. return next;
  622. }
  623. /**
  624. * Sets the next node.
  625. *
  626. * @param next the next node
  627. * @since Commons Collections 3.1
  628. */
  629. protected void setNextNode(Node next) {
  630. this.next = next;
  631. }
  632. }
  633. //-----------------------------------------------------------------------
  634. /**
  635. * A list iterator over the linked list.
  636. */
  637. protected static class LinkedListIterator implements ListIterator, OrderedIterator {
  638. /** The parent list */
  639. protected final AbstractLinkedList parent;
  640. /**
  641. * The node that will be returned by {@link #next()}. If this is equal
  642. * to {@link AbstractLinkedList#header} then there are no more values to return.
  643. */
  644. protected Node next;
  645. /**
  646. * The index of {@link #next}.
  647. */
  648. protected int nextIndex;
  649. /**
  650. * The last node that was returned by {@link #next()} or {@link
  651. * #previous()}. Set to <code>null</code> if {@link #next()} or {@link
  652. * #previous()} haven't been called, or if the node has been removed
  653. * with {@link #remove()} or a new node added with {@link #add(Object)}.
  654. * Should be accessed through {@link #getLastNodeReturned()} to enforce
  655. * this behaviour.
  656. */
  657. protected Node current;
  658. /**
  659. * The modification count that the list is expected to have. If the list
  660. * doesn't have this count, then a
  661. * {@link java.util.ConcurrentModificationException} may be thrown by
  662. * the operations.
  663. */
  664. protected int expectedModCount;
  665. /**
  666. * Create a ListIterator for a list.
  667. *
  668. * @param parent the parent list
  669. * @param fromIndex the index to start at
  670. */
  671. protected LinkedListIterator(AbstractLinkedList parent, int fromIndex) throws IndexOutOfBoundsException {
  672. super();
  673. this.parent = parent;
  674. this.expectedModCount = parent.modCount;
  675. this.next = parent.getNode(fromIndex, true);
  676. this.nextIndex = fromIndex;
  677. }
  678. /**
  679. * Checks the modification count of the list is the value that this
  680. * object expects.
  681. *
  682. * @throws ConcurrentModificationException If the list's modification
  683. * count isn't the value that was expected.
  684. */
  685. protected void checkModCount() {
  686. if (parent.modCount != expectedModCount) {
  687. throw new ConcurrentModificationException();
  688. }
  689. }
  690. /**
  691. * Gets the last node returned.
  692. *
  693. * @throws IllegalStateException If {@link #next()} or
  694. * {@link #previous()} haven't been called, or if the node has been removed
  695. * with {@link #remove()} or a new node added with {@link #add(Object)}.
  696. */
  697. protected Node getLastNodeReturned() throws IllegalStateException {
  698. if (current == null) {
  699. throw new IllegalStateException();
  700. }
  701. return current;
  702. }
  703. public boolean hasNext() {
  704. return next != parent.header;
  705. }
  706. public Object next() {
  707. checkModCount();
  708. if (!hasNext()) {
  709. throw new NoSuchElementException("No element at index " + nextIndex + ".");
  710. }
  711. Object value = next.getValue();
  712. current = next;
  713. next = next.next;
  714. nextIndex++;
  715. return value;
  716. }
  717. public boolean hasPrevious() {
  718. return next.previous != parent.header;
  719. }
  720. public Object previous() {
  721. checkModCount();
  722. if (!hasPrevious()) {
  723. throw new NoSuchElementException("Already at start of list.");
  724. }
  725. next = next.previous;
  726. Object value = next.getValue();
  727. current = next;
  728. nextIndex--;
  729. return value;
  730. }
  731. public int nextIndex() {
  732. return nextIndex;
  733. }
  734. public int previousIndex() {
  735. // not normally overridden, as relative to nextIndex()
  736. return nextIndex() - 1;
  737. }
  738. public void remove() {
  739. checkModCount();
  740. parent.removeNode(getLastNodeReturned());
  741. current = null;
  742. nextIndex--;
  743. expectedModCount++;
  744. }
  745. public void set(Object obj) {
  746. checkModCount();
  747. getLastNodeReturned().setValue(obj);
  748. }
  749. public void add(Object obj) {
  750. checkModCount();
  751. parent.addNodeBefore(next, obj);
  752. current = null;
  753. nextIndex++;
  754. expectedModCount++;
  755. }
  756. }
  757. //-----------------------------------------------------------------------
  758. /**
  759. * A list iterator over the linked sub list.
  760. */
  761. protected static class LinkedSubListIterator extends LinkedListIterator {
  762. /** The parent list */
  763. protected final LinkedSubList sub;
  764. protected LinkedSubListIterator(LinkedSubList sub, int startIndex) {
  765. super(sub.parent, startIndex + sub.offset);
  766. this.sub = sub;
  767. }
  768. public boolean hasNext() {
  769. return (nextIndex() < sub.size);
  770. }
  771. public boolean hasPrevious() {
  772. return (previousIndex() >= 0);
  773. }
  774. public int nextIndex() {
  775. return (super.nextIndex() - sub.offset);
  776. }
  777. public void add(Object obj) {
  778. super.add(obj);
  779. sub.expectedModCount = parent.modCount;
  780. sub.size++;
  781. }
  782. public void remove() {
  783. super.remove();
  784. sub.expectedModCount = parent.modCount;
  785. sub.size--;
  786. }
  787. }
  788. //-----------------------------------------------------------------------
  789. /**
  790. * The sublist implementation for AbstractLinkedList.
  791. */
  792. protected static class LinkedSubList extends AbstractList {
  793. /** The main list */
  794. private AbstractLinkedList parent;
  795. /** Offset from the main list */
  796. private int offset;
  797. /** Sublist size */
  798. private int size;
  799. /** Sublist modCount */
  800. private int expectedModCount;
  801. protected LinkedSubList(AbstractLinkedList parent, int fromIndex, int toIndex) {
  802. if (fromIndex < 0) {
  803. throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
  804. }
  805. if (toIndex > parent.size()) {
  806. throw new IndexOutOfBoundsException("toIndex = " + toIndex);
  807. }
  808. if (fromIndex > toIndex) {
  809. throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
  810. }
  811. this.parent = parent;
  812. this.offset = fromIndex;
  813. this.size = toIndex - fromIndex;
  814. this.expectedModCount = parent.modCount;
  815. }
  816. public int size() {
  817. checkModCount();
  818. return size;
  819. }
  820. public Object get(int index) {
  821. rangeCheck(index, size);
  822. checkModCount();
  823. return parent.get(index + offset);
  824. }
  825. public void add(int index, Object obj) {
  826. rangeCheck(index, size + 1);
  827. checkModCount();
  828. parent.add(index + offset, obj);
  829. expectedModCount = parent.modCount;
  830. size++;
  831. LinkedSubList.this.modCount++;
  832. }
  833. public Object remove(int index) {
  834. rangeCheck(index, size);
  835. checkModCount();
  836. Object result = parent.remove(index + offset);
  837. expectedModCount = parent.modCount;
  838. size--;
  839. LinkedSubList.this.modCount++;
  840. return result;
  841. }
  842. public boolean addAll(Collection coll) {
  843. return addAll(size, coll);
  844. }
  845. public boolean addAll(int index, Collection coll) {
  846. rangeCheck(index, size + 1);
  847. int cSize = coll.size();
  848. if (cSize == 0) {
  849. return false;
  850. }
  851. checkModCount();
  852. parent.addAll(offset + index, coll);
  853. expectedModCount = parent.modCount;
  854. size += cSize;
  855. LinkedSubList.this.modCount++;
  856. return true;
  857. }
  858. public Object set(int index, Object obj) {
  859. rangeCheck(index, size);
  860. checkModCount();
  861. return parent.set(index + offset, obj);
  862. }
  863. public void clear() {
  864. checkModCount();
  865. Iterator it = iterator();
  866. while (it.hasNext()) {
  867. it.next();
  868. it.remove();
  869. }
  870. }
  871. public Iterator iterator() {
  872. checkModCount();
  873. return parent.createSubListIterator(this);
  874. }
  875. public ListIterator listIterator(final int index) {
  876. rangeCheck(index, size + 1);
  877. checkModCount();
  878. return parent.createSubListListIterator(this, index);
  879. }
  880. public List subList(int fromIndexInclusive, int toIndexExclusive) {
  881. return new LinkedSubList(parent, fromIndexInclusive + offset, toIndexExclusive + offset);
  882. }
  883. protected void rangeCheck(int index, int beyond) {
  884. if (index < 0 || index >= beyond) {
  885. throw new IndexOutOfBoundsException("Index '" + index + "' out of bounds for size '" + size + "'");
  886. }
  887. }
  888. protected void checkModCount() {
  889. if (parent.modCount != expectedModCount) {
  890. throw new ConcurrentModificationException();
  891. }
  892. }
  893. }
  894. }