1. /*
  2. * Copyright 2002-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;
  17. import java.io.IOException;
  18. import java.io.ObjectInputStream;
  19. import java.io.ObjectOutputStream;
  20. import java.io.Serializable;
  21. import java.lang.reflect.Array;
  22. import java.util.ArrayList;
  23. import java.util.Collection;
  24. import java.util.ConcurrentModificationException;
  25. import java.util.Iterator;
  26. import java.util.List;
  27. import java.util.ListIterator;
  28. import java.util.NoSuchElementException;
  29. import java.lang.ref.WeakReference;
  30. /**
  31. * A doubly-linked list implementation of the {@link List} interface,
  32. * supporting a {@link ListIterator} that allows concurrent modifications
  33. * to the underlying list.
  34. * <p>
  35. * Implements all of the optional {@link List} operations, the
  36. * stack/queue/dequeue operations available in {@link java.util.LinkedList}
  37. * and supports a {@link ListIterator} that allows concurrent modifications
  38. * to the underlying list (see {@link #cursor}).
  39. * <p>
  40. * <b>Note that this implementation is not synchronized.</b>
  41. *
  42. * @deprecated Use new version in list subpackage, which has been rewritten
  43. * and now returns the cursor from the listIterator method. Will be removed in v4.0
  44. * @see java.util.LinkedList
  45. * @since Commons Collections 1.0
  46. * @version $Revision: 1.23 $ $Date: 2004/02/18 01:15:42 $
  47. *
  48. * @author Rodney Waldhoff
  49. * @author Janek Bogucki
  50. * @author Simon Kitching
  51. */
  52. public class CursorableLinkedList implements List, Serializable {
  53. /** Ensure serialization compatibility */
  54. private static final long serialVersionUID = 8836393098519411393L;
  55. //--- public methods ---------------------------------------------
  56. /**
  57. * Appends the specified element to the end of this list.
  58. *
  59. * @param o element to be appended to this list.
  60. * @return <tt>true</tt>
  61. */
  62. public boolean add(Object o) {
  63. insertListable(_head.prev(),null,o);
  64. return true;
  65. }
  66. /**
  67. * Inserts the specified element at the specified position in this list.
  68. * Shifts the element currently at that position (if any) and any subsequent
  69. * elements to the right (adds one to their indices).
  70. *
  71. * @param index index at which the specified element is to be inserted.
  72. * @param element element to be inserted.
  73. *
  74. * @throws ClassCastException if the class of the specified element
  75. * prevents it from being added to this list.
  76. * @throws IllegalArgumentException if some aspect of the specified
  77. * element prevents it from being added to this list.
  78. * @throws IndexOutOfBoundsException if the index is out of range
  79. * (index < 0 || index > size()).
  80. */
  81. public void add(int index, Object element) {
  82. if(index == _size) {
  83. add(element);
  84. } else {
  85. if(index < 0 || index > _size) {
  86. throw new IndexOutOfBoundsException(String.valueOf(index) + " < 0 or " + String.valueOf(index) + " > " + _size);
  87. }
  88. Listable succ = (isEmpty() ? null : getListableAt(index));
  89. Listable pred = (null == succ ? null : succ.prev());
  90. insertListable(pred,succ,element);
  91. }
  92. }
  93. /**
  94. * Appends all of the elements in the specified collection to the end of
  95. * this list, in the order that they are returned by the specified
  96. * {@link Collection}'s {@link Iterator}. The behavior of this operation is
  97. * unspecified if the specified collection is modified while
  98. * the operation is in progress. (Note that this will occur if the
  99. * specified collection is this list, and it's nonempty.)
  100. *
  101. * @param c collection whose elements are to be added to this list.
  102. * @return <tt>true</tt> if this list changed as a result of the call.
  103. *
  104. * @throws ClassCastException if the class of an element in the specified
  105. * collection prevents it from being added to this list.
  106. * @throws IllegalArgumentException if some aspect of an element in the
  107. * specified collection prevents it from being added to this
  108. * list.
  109. */
  110. public boolean addAll(Collection c) {
  111. if(c.isEmpty()) {
  112. return false;
  113. }
  114. Iterator it = c.iterator();
  115. while(it.hasNext()) {
  116. insertListable(_head.prev(),null,it.next());
  117. }
  118. return true;
  119. }
  120. /**
  121. * Inserts all of the elements in the specified collection into this
  122. * list at the specified position. Shifts the element currently at
  123. * that position (if any) and any subsequent elements to the right
  124. * (increases their indices). The new elements will appear in this
  125. * list in the order that they are returned by the specified
  126. * {@link Collection}'s {@link Iterator}. The behavior of this operation is
  127. * unspecified if the specified collection is modified while the
  128. * operation is in progress. (Note that this will occur if the specified
  129. * collection is this list, and it's nonempty.)
  130. *
  131. * @param index index at which to insert first element from the specified
  132. * collection.
  133. * @param c elements to be inserted into this list.
  134. * @return <tt>true</tt> if this list changed as a result of the call.
  135. *
  136. * @throws ClassCastException if the class of one of elements of the
  137. * specified collection prevents it from being added to this
  138. * list.
  139. * @throws IllegalArgumentException if some aspect of one of elements of
  140. * the specified collection prevents it from being added to
  141. * this list.
  142. * @throws IndexOutOfBoundsException if the index is out of range (index
  143. * < 0 || index > size()).
  144. */
  145. public boolean addAll(int index, Collection c) {
  146. if(c.isEmpty()) {
  147. return false;
  148. } else if(_size == index || _size == 0) {
  149. return addAll(c);
  150. } else {
  151. Listable succ = getListableAt(index);
  152. Listable pred = (null == succ) ? null : succ.prev();
  153. Iterator it = c.iterator();
  154. while(it.hasNext()) {
  155. pred = insertListable(pred,succ,it.next());
  156. }
  157. return true;
  158. }
  159. }
  160. /**
  161. * Inserts the specified element at the beginning of this list.
  162. * (Equivalent to {@link #add(int,java.lang.Object) <tt>add(0,o)</tt>}).
  163. *
  164. * @param o element to be prepended to this list.
  165. * @return <tt>true</tt>
  166. */
  167. public boolean addFirst(Object o) {
  168. insertListable(null,_head.next(),o);
  169. return true;
  170. }
  171. /**
  172. * Inserts the specified element at the end of this list.
  173. * (Equivalent to {@link #add(java.lang.Object)}).
  174. *
  175. * @param o element to be appended to this list.
  176. * @return <tt>true</tt>
  177. */
  178. public boolean addLast(Object o) {
  179. insertListable(_head.prev(),null,o);
  180. return true;
  181. }
  182. /**
  183. * Removes all of the elements from this list. This
  184. * list will be empty after this call returns (unless
  185. * it throws an exception).
  186. */
  187. public void clear() {
  188. /*
  189. // this is the quick way, but would force us
  190. // to break all the cursors
  191. _modCount++;
  192. _head.setNext(null);
  193. _head.setPrev(null);
  194. _size = 0;
  195. */
  196. Iterator it = iterator();
  197. while(it.hasNext()) {
  198. it.next();
  199. it.remove();
  200. }
  201. }
  202. /**
  203. * Returns <tt>true</tt> if this list contains the specified element.
  204. * More formally, returns <tt>true</tt> if and only if this list contains
  205. * at least one element <tt>e</tt> such that
  206. * <tt>(o==null ? e==null : o.equals(e))</tt>.
  207. *
  208. * @param o element whose presence in this list is to be tested.
  209. * @return <tt>true</tt> if this list contains the specified element.
  210. */
  211. public boolean contains(Object o) {
  212. for(Listable elt = _head.next(), past = null; null != elt && past != _head.prev(); elt = (past = elt).next()) {
  213. if((null == o && null == elt.value()) ||
  214. (o != null && o.equals(elt.value()))) {
  215. return true;
  216. }
  217. }
  218. return false;
  219. }
  220. /**
  221. * Returns <tt>true</tt> if this list contains all of the elements of the
  222. * specified collection.
  223. *
  224. * @param c collection to be checked for containment in this list.
  225. * @return <tt>true</tt> if this list contains all of the elements of the
  226. * specified collection.
  227. */
  228. public boolean containsAll(Collection c) {
  229. Iterator it = c.iterator();
  230. while(it.hasNext()) {
  231. if(!this.contains(it.next())) {
  232. return false;
  233. }
  234. }
  235. return true;
  236. }
  237. /**
  238. * Returns a {@link ListIterator} for iterating through the
  239. * elements of this list. Unlike {@link #iterator}, a cursor
  240. * is not bothered by concurrent modifications to the
  241. * underlying list.
  242. * <p>
  243. * Specifically, when elements are added to the list before or
  244. * after the cursor, the cursor simply picks them up automatically.
  245. * When the "current" (i.e., last returned by {@link ListIterator#next}
  246. * or {@link ListIterator#previous}) element of the list is removed,
  247. * the cursor automatically adjusts to the change (invalidating the
  248. * last returned value--i.e., it cannot be removed).
  249. * <p>
  250. * Note that the returned {@link ListIterator} does not support the
  251. * {@link ListIterator#nextIndex} and {@link ListIterator#previousIndex}
  252. * methods (they throw {@link UnsupportedOperationException} when invoked.
  253. * <p>
  254. * Historical Note: In previous versions of this class, the object
  255. * returned from this method was required to be explicitly closed. This
  256. * is no longer necessary.
  257. *
  258. * @see #cursor(int)
  259. * @see #listIterator
  260. * @see CursorableLinkedList.Cursor
  261. */
  262. public CursorableLinkedList.Cursor cursor() {
  263. return new Cursor(0);
  264. }
  265. /**
  266. * Returns a {@link ListIterator} for iterating through the
  267. * elements of this list, initialized such that
  268. * {@link ListIterator#next} will return the element at
  269. * the specified index (if any) and {@link ListIterator#previous}
  270. * will return the element immediately preceding it (if any).
  271. * Unlike {@link #iterator}, a cursor
  272. * is not bothered by concurrent modifications to the
  273. * underlying list.
  274. *
  275. * @see #cursor
  276. * @see #listIterator(int)
  277. * @see CursorableLinkedList.Cursor
  278. * @throws IndexOutOfBoundsException if the index is out of range (index
  279. * < 0 || index > size()).
  280. */
  281. public CursorableLinkedList.Cursor cursor(int i) {
  282. return new Cursor(i);
  283. }
  284. /**
  285. * Compares the specified object with this list for equality. Returns
  286. * <tt>true</tt> if and only if the specified object is also a list, both
  287. * lists have the same size, and all corresponding pairs of elements in
  288. * the two lists are <i>equal</i>. (Two elements <tt>e1</tt> and
  289. * <tt>e2</tt> are <i>equal</i> if <tt>(e1==null ? e2==null :
  290. * e1.equals(e2))</tt>.) In other words, two lists are defined to be
  291. * equal if they contain the same elements in the same order. This
  292. * definition ensures that the equals method works properly across
  293. * different implementations of the <tt>List</tt> interface.
  294. *
  295. * @param o the object to be compared for equality with this list.
  296. * @return <tt>true</tt> if the specified object is equal to this list.
  297. */
  298. public boolean equals(Object o) {
  299. if(o == this) {
  300. return true;
  301. } else if(!(o instanceof List)) {
  302. return false;
  303. }
  304. Iterator it = ((List)o).listIterator();
  305. for(Listable elt = _head.next(), past = null; null != elt && past != _head.prev(); elt = (past = elt).next()) {
  306. if(!it.hasNext() || (null == elt.value() ? null != it.next() : !(elt.value().equals(it.next()))) ) {
  307. return false;
  308. }
  309. }
  310. return !it.hasNext();
  311. }
  312. /**
  313. * Returns the element at the specified position in this list.
  314. *
  315. * @param index index of element to return.
  316. * @return the element at the specified position in this list.
  317. *
  318. * @throws IndexOutOfBoundsException if the index is out of range (index
  319. * < 0 || index >= size()).
  320. */
  321. public Object get(int index) {
  322. return getListableAt(index).value();
  323. }
  324. /**
  325. * Returns the element at the beginning of this list.
  326. */
  327. public Object getFirst() {
  328. try {
  329. return _head.next().value();
  330. } catch(NullPointerException e) {
  331. throw new NoSuchElementException();
  332. }
  333. }
  334. /**
  335. * Returns the element at the end of this list.
  336. */
  337. public Object getLast() {
  338. try {
  339. return _head.prev().value();
  340. } catch(NullPointerException e) {
  341. throw new NoSuchElementException();
  342. }
  343. }
  344. /**
  345. * Returns the hash code value for this list. The hash code of a list
  346. * is defined to be the result of the following calculation:
  347. * <pre>
  348. * hashCode = 1;
  349. * Iterator i = list.iterator();
  350. * while (i.hasNext()) {
  351. * Object obj = i.next();
  352. * hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
  353. * }
  354. * </pre>
  355. * This ensures that <tt>list1.equals(list2)</tt> implies that
  356. * <tt>list1.hashCode()==list2.hashCode()</tt> for any two lists,
  357. * <tt>list1</tt> and <tt>list2</tt>, as required by the general
  358. * contract of <tt>Object.hashCode</tt>.
  359. *
  360. * @return the hash code value for this list.
  361. * @see Object#hashCode()
  362. * @see Object#equals(Object)
  363. * @see #equals(Object)
  364. */
  365. public int hashCode() {
  366. int hash = 1;
  367. for(Listable elt = _head.next(), past = null; null != elt && past != _head.prev(); elt = (past = elt).next()) {
  368. hash = 31*hash + (null == elt.value() ? 0 : elt.value().hashCode());
  369. }
  370. return hash;
  371. }
  372. /**
  373. * Returns the index in this list of the first occurrence of the specified
  374. * element, or -1 if this list does not contain this element.
  375. * More formally, returns the lowest index <tt>i</tt> such that
  376. * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
  377. * or -1 if there is no such index.
  378. *
  379. * @param o element to search for.
  380. * @return the index in this list of the first occurrence of the specified
  381. * element, or -1 if this list does not contain this element.
  382. */
  383. public int indexOf(Object o) {
  384. int ndx = 0;
  385. // perform the null check outside of the loop to save checking every
  386. // single time through the loop.
  387. if (null == o) {
  388. for(Listable elt = _head.next(), past = null; null != elt && past != _head.prev(); elt = (past = elt).next()) {
  389. if (null == elt.value()) {
  390. return ndx;
  391. }
  392. ndx++;
  393. }
  394. } else {
  395. for(Listable elt = _head.next(), past = null; null != elt && past != _head.prev(); elt = (past = elt).next()) {
  396. if (o.equals(elt.value())) {
  397. return ndx;
  398. }
  399. ndx++;
  400. }
  401. }
  402. return -1;
  403. }
  404. /**
  405. * Returns <tt>true</tt> if this list contains no elements.
  406. * @return <tt>true</tt> if this list contains no elements.
  407. */
  408. public boolean isEmpty() {
  409. return(0 == _size);
  410. }
  411. /**
  412. * Returns a fail-fast iterator.
  413. * @see List#iterator
  414. */
  415. public Iterator iterator() {
  416. return listIterator(0);
  417. }
  418. /**
  419. * Returns the index in this list of the last occurrence of the specified
  420. * element, or -1 if this list does not contain this element.
  421. * More formally, returns the highest index <tt>i</tt> such that
  422. * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
  423. * or -1 if there is no such index.
  424. *
  425. * @param o element to search for.
  426. * @return the index in this list of the last occurrence of the specified
  427. * element, or -1 if this list does not contain this element.
  428. */
  429. public int lastIndexOf(Object o) {
  430. int ndx = _size-1;
  431. // perform the null check outside of the loop to save checking every
  432. // single time through the loop.
  433. if (null == o) {
  434. for(Listable elt = _head.prev(), past = null; null != elt && past != _head.next(); elt = (past = elt).prev()) {
  435. if (null == elt.value()) {
  436. return ndx;
  437. }
  438. ndx--;
  439. }
  440. } else {
  441. for(Listable elt = _head.prev(), past = null; null != elt && past != _head.next(); elt = (past = elt).prev()) {
  442. if (o.equals(elt.value())) {
  443. return ndx;
  444. }
  445. ndx--;
  446. }
  447. }
  448. return -1;
  449. }
  450. /**
  451. * Returns a fail-fast ListIterator.
  452. * @see List#listIterator
  453. */
  454. public ListIterator listIterator() {
  455. return listIterator(0);
  456. }
  457. /**
  458. * Returns a fail-fast ListIterator.
  459. * @see List#listIterator(int)
  460. */
  461. public ListIterator listIterator(int index) {
  462. if(index<0 || index > _size) {
  463. throw new IndexOutOfBoundsException(index + " < 0 or > " + _size);
  464. }
  465. return new ListIter(index);
  466. }
  467. /**
  468. * Removes the first occurrence in this list of the specified element.
  469. * If this list does not contain the element, it is
  470. * unchanged. More formally, removes the element with the lowest index i
  471. * such that <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> (if
  472. * such an element exists).
  473. *
  474. * @param o element to be removed from this list, if present.
  475. * @return <tt>true</tt> if this list contained the specified element.
  476. */
  477. public boolean remove(Object o) {
  478. for(Listable elt = _head.next(), past = null; null != elt && past != _head.prev(); elt = (past = elt).next()) {
  479. if(null == o && null == elt.value()) {
  480. removeListable(elt);
  481. return true;
  482. } else if(o != null && o.equals(elt.value())) {
  483. removeListable(elt);
  484. return true;
  485. }
  486. }
  487. return false;
  488. }
  489. /**
  490. * Removes the element at the specified position in this list (optional
  491. * operation). Shifts any subsequent elements to the left (subtracts one
  492. * from their indices). Returns the element that was removed from the
  493. * list.
  494. *
  495. * @param index the index of the element to removed.
  496. * @return the element previously at the specified position.
  497. *
  498. * @throws IndexOutOfBoundsException if the index is out of range (index
  499. * < 0 || index >= size()).
  500. */
  501. public Object remove(int index) {
  502. Listable elt = getListableAt(index);
  503. Object ret = elt.value();
  504. removeListable(elt);
  505. return ret;
  506. }
  507. /**
  508. * Removes from this list all the elements that are contained in the
  509. * specified collection.
  510. *
  511. * @param c collection that defines which elements will be removed from
  512. * this list.
  513. * @return <tt>true</tt> if this list changed as a result of the call.
  514. */
  515. public boolean removeAll(Collection c) {
  516. if(0 == c.size() || 0 == _size) {
  517. return false;
  518. } else {
  519. boolean changed = false;
  520. Iterator it = iterator();
  521. while(it.hasNext()) {
  522. if(c.contains(it.next())) {
  523. it.remove();
  524. changed = true;
  525. }
  526. }
  527. return changed;
  528. }
  529. }
  530. /**
  531. * Removes the first element of this list, if any.
  532. */
  533. public Object removeFirst() {
  534. if(_head.next() != null) {
  535. Object val = _head.next().value();
  536. removeListable(_head.next());
  537. return val;
  538. } else {
  539. throw new NoSuchElementException();
  540. }
  541. }
  542. /**
  543. * Removes the last element of this list, if any.
  544. */
  545. public Object removeLast() {
  546. if(_head.prev() != null) {
  547. Object val = _head.prev().value();
  548. removeListable(_head.prev());
  549. return val;
  550. } else {
  551. throw new NoSuchElementException();
  552. }
  553. }
  554. /**
  555. * Retains only the elements in this list that are contained in the
  556. * specified collection. In other words, removes
  557. * from this list all the elements that are not contained in the specified
  558. * collection.
  559. *
  560. * @param c collection that defines which elements this set will retain.
  561. *
  562. * @return <tt>true</tt> if this list changed as a result of the call.
  563. */
  564. public boolean retainAll(Collection c) {
  565. boolean changed = false;
  566. Iterator it = iterator();
  567. while(it.hasNext()) {
  568. if(!c.contains(it.next())) {
  569. it.remove();
  570. changed = true;
  571. }
  572. }
  573. return changed;
  574. }
  575. /**
  576. * Replaces the element at the specified position in this list with the
  577. * specified element.
  578. *
  579. * @param index index of element to replace.
  580. * @param element element to be stored at the specified position.
  581. * @return the element previously at the specified position.
  582. *
  583. * @throws ClassCastException if the class of the specified element
  584. * prevents it from being added to this list.
  585. * @throws IllegalArgumentException if some aspect of the specified
  586. * element prevents it from being added to this list.
  587. * @throws IndexOutOfBoundsException if the index is out of range
  588. * (index < 0 || index >= size()).
  589. */
  590. public Object set(int index, Object element) {
  591. Listable elt = getListableAt(index);
  592. Object val = elt.setValue(element);
  593. broadcastListableChanged(elt);
  594. return val;
  595. }
  596. /**
  597. * Returns the number of elements in this list.
  598. * @return the number of elements in this list.
  599. */
  600. public int size() {
  601. return _size;
  602. }
  603. /**
  604. * Returns an array containing all of the elements in this list in proper
  605. * sequence. Obeys the general contract of the {@link Collection#toArray} method.
  606. *
  607. * @return an array containing all of the elements in this list in proper
  608. * sequence.
  609. */
  610. public Object[] toArray() {
  611. Object[] array = new Object[_size];
  612. int i = 0;
  613. for(Listable elt = _head.next(), past = null; null != elt && past != _head.prev(); elt = (past = elt).next()) {
  614. array[i++] = elt.value();
  615. }
  616. return array;
  617. }
  618. /**
  619. * Returns an array containing all of the elements in this list in proper
  620. * sequence; the runtime type of the returned array is that of the
  621. * specified array. Obeys the general contract of the
  622. * {@link Collection#toArray} method.
  623. *
  624. * @param a the array into which the elements of this list are to
  625. * be stored, if it is big enough; otherwise, a new array of the
  626. * same runtime type is allocated for this purpose.
  627. * @return an array containing the elements of this list.
  628. * @exception ArrayStoreException
  629. * if the runtime type of the specified array
  630. * is not a supertype of the runtime type of every element in
  631. * this list.
  632. */
  633. public Object[] toArray(Object a[]) {
  634. if(a.length < _size) {
  635. a = (Object[])Array.newInstance(a.getClass().getComponentType(), _size);
  636. }
  637. int i = 0;
  638. for(Listable elt = _head.next(), past = null; null != elt && past != _head.prev(); elt = (past = elt).next()) {
  639. a[i++] = elt.value();
  640. }
  641. if(a.length > _size) {
  642. a[_size] = null; // should we null out the rest of the array also? java.util.LinkedList doesn't
  643. }
  644. return a;
  645. }
  646. /**
  647. * Returns a {@link String} representation of this list, suitable for debugging.
  648. * @return a {@link String} representation of this list, suitable for debugging.
  649. */
  650. public String toString() {
  651. StringBuffer buf = new StringBuffer();
  652. buf.append("[");
  653. for(Listable elt = _head.next(), past = null; null != elt && past != _head.prev(); elt = (past = elt).next()) {
  654. if(_head.next() != elt) {
  655. buf.append(", ");
  656. }
  657. buf.append(elt.value());
  658. }
  659. buf.append("]");
  660. return buf.toString();
  661. }
  662. /**
  663. * Returns a fail-fast sublist.
  664. * @see List#subList(int,int)
  665. */
  666. public List subList(int i, int j) {
  667. if(i < 0 || j > _size || i > j) {
  668. throw new IndexOutOfBoundsException();
  669. } else if(i == 0 && j == _size) {
  670. return this;
  671. } else {
  672. return new CursorableSubList(this,i,j);
  673. }
  674. }
  675. //--- protected methods ------------------------------------------
  676. /**
  677. * Inserts a new <i>value</i> into my
  678. * list, after the specified <i>before</i> element, and before the
  679. * specified <i>after</i> element
  680. *
  681. * @return the newly created
  682. * {@link org.apache.commons.collections.CursorableLinkedList.Listable}
  683. */
  684. protected Listable insertListable(Listable before, Listable after, Object value) {
  685. _modCount++;
  686. _size++;
  687. Listable elt = new Listable(before,after,value);
  688. if(null != before) {
  689. before.setNext(elt);
  690. } else {
  691. _head.setNext(elt);
  692. }
  693. if(null != after) {
  694. after.setPrev(elt);
  695. } else {
  696. _head.setPrev(elt);
  697. }
  698. broadcastListableInserted(elt);
  699. return elt;
  700. }
  701. /**
  702. * Removes the given
  703. * {@link org.apache.commons.collections.CursorableLinkedList.Listable}
  704. * from my list.
  705. */
  706. protected void removeListable(Listable elt) {
  707. _modCount++;
  708. _size--;
  709. if(_head.next() == elt) {
  710. _head.setNext(elt.next());
  711. }
  712. if(null != elt.next()) {
  713. elt.next().setPrev(elt.prev());
  714. }
  715. if(_head.prev() == elt) {
  716. _head.setPrev(elt.prev());
  717. }
  718. if(null != elt.prev()) {
  719. elt.prev().setNext(elt.next());
  720. }
  721. broadcastListableRemoved(elt);
  722. }
  723. /**
  724. * Returns the
  725. * {@link org.apache.commons.collections.CursorableLinkedList.Listable}
  726. * at the specified index.
  727. *
  728. * @throws IndexOutOfBoundsException if index is less than zero or
  729. * greater than or equal to the size of this list.
  730. */
  731. protected Listable getListableAt(int index) {
  732. if(index < 0 || index >= _size) {
  733. throw new IndexOutOfBoundsException(String.valueOf(index) + " < 0 or " + String.valueOf(index) + " >= " + _size);
  734. }
  735. if(index <=_size2) {
  736. Listable elt = _head.next();
  737. for(int i = 0; i < index; i++) {
  738. elt = elt.next();
  739. }
  740. return elt;
  741. } else {
  742. Listable elt = _head.prev();
  743. for(int i = (_size-1); i > index; i--) {
  744. elt = elt.prev();
  745. }
  746. return elt;
  747. }
  748. }
  749. /**
  750. * Registers a {@link CursorableLinkedList.Cursor} to be notified
  751. * of changes to this list.
  752. */
  753. protected void registerCursor(Cursor cur) {
  754. // We take this opportunity to clean the _cursors list
  755. // of WeakReference objects to garbage-collected cursors.
  756. for (Iterator it = _cursors.iterator(); it.hasNext(); ) {
  757. WeakReference ref = (WeakReference) it.next();
  758. if (ref.get() == null) {
  759. it.remove();
  760. }
  761. }
  762. _cursors.add( new WeakReference(cur) );
  763. }
  764. /**
  765. * Removes a {@link CursorableLinkedList.Cursor} from
  766. * the set of cursors to be notified of changes to this list.
  767. */
  768. protected void unregisterCursor(Cursor cur) {
  769. for (Iterator it = _cursors.iterator(); it.hasNext(); ) {
  770. WeakReference ref = (WeakReference) it.next();
  771. Cursor cursor = (Cursor) ref.get();
  772. if (cursor == null) {
  773. // some other unrelated cursor object has been
  774. // garbage-collected; let's take the opportunity to
  775. // clean up the cursors list anyway..
  776. it.remove();
  777. } else if (cursor == cur) {
  778. ref.clear();
  779. it.remove();
  780. break;
  781. }
  782. }
  783. }
  784. /**
  785. * Informs all of my registered cursors that they are now
  786. * invalid.
  787. */
  788. protected void invalidateCursors() {
  789. Iterator it = _cursors.iterator();
  790. while (it.hasNext()) {
  791. WeakReference ref = (WeakReference) it.next();
  792. Cursor cursor = (Cursor) ref.get();
  793. if (cursor != null) {
  794. // cursor is null if object has been garbage-collected
  795. cursor.invalidate();
  796. ref.clear();
  797. }
  798. it.remove();
  799. }
  800. }
  801. /**
  802. * Informs all of my registered cursors that the specified
  803. * element was changed.
  804. * @see #set(int,java.lang.Object)
  805. */
  806. protected void broadcastListableChanged(Listable elt) {
  807. Iterator it = _cursors.iterator();
  808. while (it.hasNext()) {
  809. WeakReference ref = (WeakReference) it.next();
  810. Cursor cursor = (Cursor) ref.get();
  811. if (cursor == null) {
  812. it.remove(); // clean up list
  813. } else {
  814. cursor.listableChanged(elt);
  815. }
  816. }
  817. }
  818. /**
  819. * Informs all of my registered cursors that the specified
  820. * element was just removed from my list.
  821. */
  822. protected void broadcastListableRemoved(Listable elt) {
  823. Iterator it = _cursors.iterator();
  824. while (it.hasNext()) {
  825. WeakReference ref = (WeakReference) it.next();
  826. Cursor cursor = (Cursor) ref.get();
  827. if (cursor == null) {
  828. it.remove(); // clean up list
  829. } else {
  830. cursor.listableRemoved(elt);
  831. }
  832. }
  833. }
  834. /**
  835. * Informs all of my registered cursors that the specified
  836. * element was just added to my list.
  837. */
  838. protected void broadcastListableInserted(Listable elt) {
  839. Iterator it = _cursors.iterator();
  840. while (it.hasNext()) {
  841. WeakReference ref = (WeakReference) it.next();
  842. Cursor cursor = (Cursor) ref.get();
  843. if (cursor == null) {
  844. it.remove(); // clean up list
  845. } else {
  846. cursor.listableInserted(elt);
  847. }
  848. }
  849. }
  850. private void writeObject(ObjectOutputStream out) throws IOException {
  851. out.defaultWriteObject();
  852. out.writeInt(_size);
  853. Listable cur = _head.next();
  854. while (cur != null) {
  855. out.writeObject(cur.value());
  856. cur = cur.next();
  857. }
  858. }
  859. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  860. in.defaultReadObject();
  861. _size = 0;
  862. _modCount = 0;
  863. _cursors = new ArrayList();
  864. _head = new Listable(null,null,null);
  865. int size = in.readInt();
  866. for (int i=0;i<size;i++) {
  867. this.add(in.readObject());
  868. }
  869. }
  870. //--- protected attributes ---------------------------------------
  871. /** The number of elements in me. */
  872. protected transient int _size = 0;
  873. /**
  874. * A sentry node.
  875. * <p>
  876. * <tt>_head.next()</tt> points to the first element in the list,
  877. * <tt>_head.prev()</tt> to the last. Note that it is possible for
  878. * <tt>_head.next().prev()</tt> and <tt>_head.prev().next()</tt> to be
  879. * non-null, as when I am a sublist for some larger list.
  880. * Use <tt>== _head.next()</tt> and <tt>== _head.prev()</tt> to determine
  881. * if a given
  882. * {@link org.apache.commons.collections.CursorableLinkedList.Listable}
  883. * is the first or last element in the list.
  884. */
  885. protected transient Listable _head = new Listable(null,null,null);
  886. /** Tracks the number of structural modifications to me. */
  887. protected transient int _modCount = 0;
  888. /**
  889. * A list of the currently {@link CursorableLinkedList.Cursor}s currently
  890. * open in this list.
  891. */
  892. protected transient List _cursors = new ArrayList();
  893. //--- inner classes ----------------------------------------------
  894. static class Listable implements Serializable {
  895. private Listable _prev = null;
  896. private Listable _next = null;
  897. private Object _val = null;
  898. Listable(Listable prev, Listable next, Object val) {
  899. _prev = prev;
  900. _next = next;
  901. _val = val;
  902. }
  903. Listable next() {
  904. return _next;
  905. }
  906. Listable prev() {
  907. return _prev;
  908. }
  909. Object value() {
  910. return _val;
  911. }
  912. void setNext(Listable next) {
  913. _next = next;
  914. }
  915. void setPrev(Listable prev) {
  916. _prev = prev;
  917. }
  918. Object setValue(Object val) {
  919. Object temp = _val;
  920. _val = val;
  921. return temp;
  922. }
  923. }
  924. class ListIter implements ListIterator {
  925. Listable _cur = null;
  926. Listable _lastReturned = null;
  927. int _expectedModCount = _modCount;
  928. int _nextIndex = 0;
  929. ListIter(int index) {
  930. if(index == 0) {
  931. _cur = new Listable(null,_head.next(),null);
  932. _nextIndex = 0;
  933. } else if(index == _size) {
  934. _cur = new Listable(_head.prev(),null,null);
  935. _nextIndex = _size;
  936. } else {
  937. Listable temp = getListableAt(index);
  938. _cur = new Listable(temp.prev(),temp,null);
  939. _nextIndex = index;
  940. }
  941. }
  942. public Object previous() {
  943. checkForComod();
  944. if(!hasPrevious()) {
  945. throw new NoSuchElementException();
  946. } else {
  947. Object ret = _cur.prev().value();
  948. _lastReturned = _cur.prev();
  949. _cur.setNext(_cur.prev());
  950. _cur.setPrev(_cur.prev().prev());
  951. _nextIndex--;
  952. return ret;
  953. }
  954. }
  955. public boolean hasNext() {
  956. checkForComod();
  957. return(null != _cur.next() && _cur.prev() != _head.prev());
  958. }
  959. public Object next() {
  960. checkForComod();
  961. if(!hasNext()) {
  962. throw new NoSuchElementException();
  963. } else {
  964. Object ret = _cur.next().value();
  965. _lastReturned = _cur.next();
  966. _cur.setPrev(_cur.next());
  967. _cur.setNext(_cur.next().next());
  968. _nextIndex++;
  969. return ret;
  970. }
  971. }
  972. public int previousIndex() {
  973. checkForComod();
  974. if(!hasPrevious()) {
  975. return -1;
  976. }
  977. return _nextIndex-1;
  978. }
  979. public boolean hasPrevious() {
  980. checkForComod();
  981. return(null != _cur.prev() && _cur.next() != _head.next());
  982. }
  983. public void set(Object o) {
  984. checkForComod();
  985. try {
  986. _lastReturned.setValue(o);
  987. } catch(NullPointerException e) {
  988. throw new IllegalStateException();
  989. }
  990. }
  991. public int nextIndex() {
  992. checkForComod();
  993. if(!hasNext()) {
  994. return size();
  995. }
  996. return _nextIndex;
  997. }
  998. public void remove() {
  999. checkForComod();
  1000. if(null == _lastReturned) {
  1001. throw new IllegalStateException();
  1002. } else {
  1003. _cur.setNext(_lastReturned == _head.prev() ? null : _lastReturned.next());
  1004. _cur.setPrev(_lastReturned == _head.next() ? null : _lastReturned.prev());
  1005. removeListable(_lastReturned);
  1006. _lastReturned = null;
  1007. _nextIndex--;
  1008. _expectedModCount++;
  1009. }
  1010. }
  1011. public void add(Object o) {
  1012. checkForComod();
  1013. _cur.setPrev(insertListable(_cur.prev(),_cur.next(),o));
  1014. _lastReturned = null;
  1015. _nextIndex++;
  1016. _expectedModCount++;
  1017. }
  1018. protected void checkForComod() {
  1019. if(_expectedModCount != _modCount) {
  1020. throw new ConcurrentModificationException();
  1021. }
  1022. }
  1023. }
  1024. public class Cursor extends ListIter implements ListIterator {
  1025. boolean _valid = false;
  1026. Cursor(int index) {
  1027. super(index);
  1028. _valid = true;
  1029. registerCursor(this);
  1030. }
  1031. public int previousIndex() {
  1032. throw new UnsupportedOperationException();
  1033. }
  1034. public int nextIndex() {
  1035. throw new UnsupportedOperationException();
  1036. }
  1037. public void add(Object o) {
  1038. checkForComod();
  1039. Listable elt = insertListable(_cur.prev(),_cur.next(),o);
  1040. _cur.setPrev(elt);
  1041. _cur.setNext(elt.next());
  1042. _lastReturned = null;
  1043. _nextIndex++;
  1044. _expectedModCount++;
  1045. }
  1046. protected void listableRemoved(Listable elt) {
  1047. if(null == _head.prev()) {
  1048. _cur.setNext(null);
  1049. } else if(_cur.next() == elt) {
  1050. _cur.setNext(elt.next());
  1051. }
  1052. if(null == _head.next()) {
  1053. _cur.setPrev(null);
  1054. } else if(_cur.prev() == elt) {
  1055. _cur.setPrev(elt.prev());
  1056. }
  1057. if(_lastReturned == elt) {
  1058. _lastReturned = null;
  1059. }
  1060. }
  1061. protected void listableInserted(Listable elt) {
  1062. if(null == _cur.next() && null == _cur.prev()) {
  1063. _cur.setNext(elt);
  1064. } else if(_cur.prev() == elt.prev()) {
  1065. _cur.setNext(elt);
  1066. }
  1067. if(_cur.next() == elt.next()) {
  1068. _cur.setPrev(elt);
  1069. }
  1070. if(_lastReturned == elt) {
  1071. _lastReturned = null;
  1072. }
  1073. }
  1074. protected void listableChanged(Listable elt) {
  1075. if(_lastReturned == elt) {
  1076. _lastReturned = null;
  1077. }
  1078. }
  1079. protected void checkForComod() {
  1080. if(!_valid) {
  1081. throw new ConcurrentModificationException();
  1082. }
  1083. }
  1084. protected void invalidate() {
  1085. _valid = false;
  1086. }
  1087. /**
  1088. * Mark this cursor as no longer being needed. Any resources
  1089. * associated with this cursor are immediately released.
  1090. * In previous versions of this class, it was mandatory to close
  1091. * all cursor objects to avoid memory leaks. It is <i>no longer</i>
  1092. * necessary to call this close method; an instance of this class
  1093. * can now be treated exactly like a normal iterator.
  1094. */
  1095. public void close() {
  1096. if(_valid) {
  1097. _valid = false;
  1098. unregisterCursor(this);
  1099. }
  1100. }
  1101. }
  1102. }
  1103. class CursorableSubList extends CursorableLinkedList implements List {
  1104. //--- constructors -----------------------------------------------
  1105. CursorableSubList(CursorableLinkedList list, int from, int to) {
  1106. if(0 > from || list.size() < to) {
  1107. throw new IndexOutOfBoundsException();
  1108. } else if(from > to) {
  1109. throw new IllegalArgumentException();
  1110. }
  1111. _list = list;
  1112. if(from < list.size()) {
  1113. _head.setNext(_list.getListableAt(from));
  1114. _pre = (null == _head.next()) ? null : _head.next().prev();
  1115. } else {
  1116. _pre = _list.getListableAt(from-1);
  1117. }
  1118. if(from == to) {
  1119. _head.setNext(null);
  1120. _head.setPrev(null);
  1121. if(to < list.size()) {
  1122. _post = _list.getListableAt(to);
  1123. } else {
  1124. _post = null;
  1125. }
  1126. } else {
  1127. _head.setPrev(_list.getListableAt(to-1));
  1128. _post = _head.prev().next();
  1129. }
  1130. _size = to - from;
  1131. _modCount = _list._modCount;
  1132. }
  1133. //--- public methods ------------------------------------------
  1134. public void clear() {
  1135. checkForComod();
  1136. Iterator it = iterator();
  1137. while(it.hasNext()) {
  1138. it.next();
  1139. it.remove();
  1140. }
  1141. }
  1142. public Iterator iterator() {
  1143. checkForComod();
  1144. return super.iterator();
  1145. }
  1146. public int size() {
  1147. checkForComod();
  1148. return super.size();
  1149. }
  1150. public boolean isEmpty() {
  1151. checkForComod();
  1152. return super.isEmpty();
  1153. }
  1154. public Object[] toArray() {
  1155. checkForComod();
  1156. return super.toArray();
  1157. }
  1158. public Object[] toArray(Object a[]) {
  1159. checkForComod();
  1160. return super.toArray(a);
  1161. }
  1162. public boolean contains(Object o) {
  1163. checkForComod();
  1164. return super.contains(o);
  1165. }
  1166. public boolean remove(Object o) {
  1167. checkForComod();
  1168. return super.remove(o);
  1169. }
  1170. public Object removeFirst() {
  1171. checkForComod();
  1172. return super.removeFirst();
  1173. }
  1174. public Object removeLast() {
  1175. checkForComod();
  1176. return super.removeLast();
  1177. }
  1178. public boolean addAll(Collection c) {
  1179. checkForComod();
  1180. return super.addAll(c);
  1181. }
  1182. public boolean add(Object o) {
  1183. checkForComod();
  1184. return super.add(o);
  1185. }
  1186. public boolean addFirst(Object o) {
  1187. checkForComod();
  1188. return super.addFirst(o);
  1189. }
  1190. public boolean addLast(Object o) {
  1191. checkForComod();
  1192. return super.addLast(o);
  1193. }
  1194. public boolean removeAll(Collection c) {
  1195. checkForComod();
  1196. return super.removeAll(c);
  1197. }
  1198. public boolean containsAll(Collection c) {
  1199. checkForComod();
  1200. return super.containsAll(c);
  1201. }
  1202. public boolean addAll(int index, Collection c) {
  1203. checkForComod();
  1204. return super.addAll(index,c);
  1205. }
  1206. public int hashCode() {
  1207. checkForComod();
  1208. return super.hashCode();
  1209. }
  1210. public boolean retainAll(Collection c) {
  1211. checkForComod();
  1212. return super.retainAll(c);
  1213. }
  1214. public Object set(int index, Object element) {
  1215. checkForComod();
  1216. return super.set(index,element);
  1217. }
  1218. public boolean equals(Object o) {
  1219. checkForComod();
  1220. return super.equals(o);
  1221. }
  1222. public Object get(int index) {
  1223. checkForComod();
  1224. return super.get(index);
  1225. }
  1226. public Object getFirst() {
  1227. checkForComod();
  1228. return super.getFirst();
  1229. }
  1230. public Object getLast() {
  1231. checkForComod();
  1232. return super.getLast();
  1233. }
  1234. public void add(int index, Object element) {
  1235. checkForComod();
  1236. super.add(index,element);
  1237. }
  1238. public ListIterator listIterator(int index) {
  1239. checkForComod();
  1240. return super.listIterator(index);
  1241. }
  1242. public Object remove(int index) {
  1243. checkForComod();
  1244. return super.remove(index);
  1245. }
  1246. public int indexOf(Object o) {
  1247. checkForComod();
  1248. return super.indexOf(o);
  1249. }
  1250. public int lastIndexOf(Object o) {
  1251. checkForComod();
  1252. return super.lastIndexOf(o);
  1253. }
  1254. public ListIterator listIterator() {
  1255. checkForComod();
  1256. return super.listIterator();
  1257. }
  1258. public List subList(int fromIndex, int toIndex) {
  1259. checkForComod();
  1260. return super.subList(fromIndex,toIndex);
  1261. }
  1262. //--- protected methods ------------------------------------------
  1263. /**
  1264. * Inserts a new <i>value</i> into my
  1265. * list, after the specified <i>before</i> element, and before the
  1266. * specified <i>after</i> element
  1267. *
  1268. * @return the newly created {@link CursorableLinkedList.Listable}
  1269. */
  1270. protected Listable insertListable(Listable before, Listable after, Object value) {
  1271. _modCount++;
  1272. _size++;
  1273. Listable elt = _list.insertListable((null == before ? _pre : before), (null == after ? _post : after),value);
  1274. if(null == _head.next()) {
  1275. _head.setNext(elt);
  1276. _head.setPrev(elt);
  1277. }
  1278. if(before == _head.prev()) {
  1279. _head.setPrev(elt);
  1280. }
  1281. if(after == _head.next()) {
  1282. _head.setNext(elt);
  1283. }
  1284. broadcastListableInserted(elt);
  1285. return elt;
  1286. }
  1287. /**
  1288. * Removes the given {@link CursorableLinkedList.Listable} from my list.
  1289. */
  1290. protected void removeListable(Listable elt) {
  1291. _modCount++;
  1292. _size--;
  1293. if(_head.next() == elt && _head.prev() == elt) {
  1294. _head.setNext(null);
  1295. _head.setPrev(null);
  1296. }
  1297. if(_head.next() == elt) {
  1298. _head.setNext(elt.next());
  1299. }
  1300. if(_head.prev() == elt) {
  1301. _head.setPrev(elt.prev());
  1302. }
  1303. _list.removeListable(elt);
  1304. broadcastListableRemoved(elt);
  1305. }
  1306. /**
  1307. * Test to see if my underlying list has been modified
  1308. * by some other process. If it has, throws a
  1309. * {@link ConcurrentModificationException}, otherwise
  1310. * quietly returns.
  1311. *
  1312. * @throws ConcurrentModificationException
  1313. */
  1314. protected void checkForComod() throws ConcurrentModificationException {
  1315. if(_modCount != _list._modCount) {
  1316. throw new ConcurrentModificationException();
  1317. }
  1318. }
  1319. //--- protected attributes ---------------------------------------
  1320. /** My underlying list */
  1321. protected CursorableLinkedList _list = null;
  1322. /** The element in my underlying list preceding the first element in my list. */
  1323. protected Listable _pre = null;
  1324. /** The element in my underlying list following the last element in my list. */
  1325. protected Listable _post = null;
  1326. }