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;
  17. import java.util.ArrayList;
  18. import java.util.Collection;
  19. import java.util.ConcurrentModificationException;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import java.util.ListIterator;
  23. /**
  24. * <p>A customized implementation of <code>java.util.ArrayList</code> designed
  25. * to operate in a multithreaded environment where the large majority of
  26. * method calls are read-only, instead of structural changes. When operating
  27. * in "fast" mode, read calls are non-synchronized and write calls perform the
  28. * following steps:</p>
  29. * <ul>
  30. * <li>Clone the existing collection
  31. * <li>Perform the modification on the clone
  32. * <li>Replace the existing collection with the (modified) clone
  33. * </ul>
  34. * <p>When first created, objects of this class default to "slow" mode, where
  35. * all accesses of any type are synchronized but no cloning takes place. This
  36. * is appropriate for initially populating the collection, followed by a switch
  37. * to "fast" mode (by calling <code>setFast(true)</code>) after initialization
  38. * is complete.</p>
  39. *
  40. * <p><strong>NOTE</strong>: If you are creating and accessing an
  41. * <code>ArrayList</code> only within a single thread, you should use
  42. * <code>java.util.ArrayList</code> directly (with no synchronization), for
  43. * maximum performance.</p>
  44. *
  45. * <p><strong>NOTE</strong>: <i>This class is not cross-platform.
  46. * Using it may cause unexpected failures on some architectures.</i>
  47. * It suffers from the same problems as the double-checked locking idiom.
  48. * In particular, the instruction that clones the internal collection and the
  49. * instruction that sets the internal reference to the clone can be executed
  50. * or perceived out-of-order. This means that any read operation might fail
  51. * unexpectedly, as it may be reading the state of the internal collection
  52. * before the internal collection is fully formed.
  53. * For more information on the double-checked locking idiom, see the
  54. * <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">
  55. * Double-Checked Locking Idiom Is Broken Declaration</a>.</p>
  56. *
  57. * @since Commons Collections 1.0
  58. * @version $Revision: 1.15 $ $Date: 2004/02/18 01:15:42 $
  59. *
  60. * @author Craig R. McClanahan
  61. */
  62. public class FastArrayList extends ArrayList {
  63. // ----------------------------------------------------------- Constructors
  64. /**
  65. * Construct a an empty list.
  66. */
  67. public FastArrayList() {
  68. super();
  69. this.list = new ArrayList();
  70. }
  71. /**
  72. * Construct an empty list with the specified capacity.
  73. *
  74. * @param capacity The initial capacity of the empty list
  75. */
  76. public FastArrayList(int capacity) {
  77. super();
  78. this.list = new ArrayList(capacity);
  79. }
  80. /**
  81. * Construct a list containing the elements of the specified collection,
  82. * in the order they are returned by the collection's iterator.
  83. *
  84. * @param collection The collection whose elements initialize the contents
  85. * of this list
  86. */
  87. public FastArrayList(Collection collection) {
  88. super();
  89. this.list = new ArrayList(collection);
  90. }
  91. // ----------------------------------------------------- Instance Variables
  92. /**
  93. * The underlying list we are managing.
  94. */
  95. protected ArrayList list = null;
  96. // ------------------------------------------------------------- Properties
  97. /**
  98. * Are we operating in "fast" mode?
  99. */
  100. protected boolean fast = false;
  101. /**
  102. * Returns true if this list is operating in fast mode.
  103. *
  104. * @return true if this list is operating in fast mode
  105. */
  106. public boolean getFast() {
  107. return (this.fast);
  108. }
  109. /**
  110. * Sets whether this list will operate in fast mode.
  111. *
  112. * @param fast true if the list should operate in fast mode
  113. */
  114. public void setFast(boolean fast) {
  115. this.fast = fast;
  116. }
  117. // --------------------------------------------------------- Public Methods
  118. /**
  119. * Appends the specified element to the end of this list.
  120. *
  121. * @param element The element to be appended
  122. */
  123. public boolean add(Object element) {
  124. if (fast) {
  125. synchronized (this) {
  126. ArrayList temp = (ArrayList) list.clone();
  127. boolean result = temp.add(element);
  128. list = temp;
  129. return (result);
  130. }
  131. } else {
  132. synchronized (list) {
  133. return (list.add(element));
  134. }
  135. }
  136. }
  137. /**
  138. * Insert the specified element at the specified position in this list,
  139. * and shift all remaining elements up one position.
  140. *
  141. * @param index Index at which to insert this element
  142. * @param element The element to be inserted
  143. *
  144. * @exception IndexOutOfBoundsException if the index is out of range
  145. */
  146. public void add(int index, Object element) {
  147. if (fast) {
  148. synchronized (this) {
  149. ArrayList temp = (ArrayList) list.clone();
  150. temp.add(index, element);
  151. list = temp;
  152. }
  153. } else {
  154. synchronized (list) {
  155. list.add(index, element);
  156. }
  157. }
  158. }
  159. /**
  160. * Append all of the elements in the specified Collection to the end
  161. * of this list, in the order that they are returned by the specified
  162. * Collection's Iterator.
  163. *
  164. * @param collection The collection to be appended
  165. */
  166. public boolean addAll(Collection collection) {
  167. if (fast) {
  168. synchronized (this) {
  169. ArrayList temp = (ArrayList) list.clone();
  170. boolean result = temp.addAll(collection);
  171. list = temp;
  172. return (result);
  173. }
  174. } else {
  175. synchronized (list) {
  176. return (list.addAll(collection));
  177. }
  178. }
  179. }
  180. /**
  181. * Insert all of the elements in the specified Collection at the specified
  182. * position in this list, and shift any previous elements upwards as
  183. * needed.
  184. *
  185. * @param index Index at which insertion takes place
  186. * @param collection The collection to be added
  187. *
  188. * @exception IndexOutOfBoundsException if the index is out of range
  189. */
  190. public boolean addAll(int index, Collection collection) {
  191. if (fast) {
  192. synchronized (this) {
  193. ArrayList temp = (ArrayList) list.clone();
  194. boolean result = temp.addAll(index, collection);
  195. list = temp;
  196. return (result);
  197. }
  198. } else {
  199. synchronized (list) {
  200. return (list.addAll(index, collection));
  201. }
  202. }
  203. }
  204. /**
  205. * Remove all of the elements from this list. The list will be empty
  206. * after this call returns.
  207. *
  208. * @exception UnsupportedOperationException if <code>clear()</code>
  209. * is not supported by this list
  210. */
  211. public void clear() {
  212. if (fast) {
  213. synchronized (this) {
  214. ArrayList temp = (ArrayList) list.clone();
  215. temp.clear();
  216. list = temp;
  217. }
  218. } else {
  219. synchronized (list) {
  220. list.clear();
  221. }
  222. }
  223. }
  224. /**
  225. * Return a shallow copy of this <code>FastArrayList</code> instance.
  226. * The elements themselves are not copied.
  227. */
  228. public Object clone() {
  229. FastArrayList results = null;
  230. if (fast) {
  231. results = new FastArrayList(list);
  232. } else {
  233. synchronized (list) {
  234. results = new FastArrayList(list);
  235. }
  236. }
  237. results.setFast(getFast());
  238. return (results);
  239. }
  240. /**
  241. * Return <code>true</code> if this list contains the specified element.
  242. *
  243. * @param element The element to test for
  244. */
  245. public boolean contains(Object element) {
  246. if (fast) {
  247. return (list.contains(element));
  248. } else {
  249. synchronized (list) {
  250. return (list.contains(element));
  251. }
  252. }
  253. }
  254. /**
  255. * Return <code>true</code> if this list contains all of the elements
  256. * in the specified Collection.
  257. *
  258. * @param collection Collection whose elements are to be checked
  259. */
  260. public boolean containsAll(Collection collection) {
  261. if (fast) {
  262. return (list.containsAll(collection));
  263. } else {
  264. synchronized (list) {
  265. return (list.containsAll(collection));
  266. }
  267. }
  268. }
  269. /**
  270. * Increase the capacity of this <code>ArrayList</code> instance, if
  271. * necessary, to ensure that it can hold at least the number of elements
  272. * specified by the minimum capacity argument.
  273. *
  274. * @param capacity The new minimum capacity
  275. */
  276. public void ensureCapacity(int capacity) {
  277. if (fast) {
  278. synchronized (this) {
  279. ArrayList temp = (ArrayList) list.clone();
  280. temp.ensureCapacity(capacity);
  281. list = temp;
  282. }
  283. } else {
  284. synchronized (list) {
  285. list.ensureCapacity(capacity);
  286. }
  287. }
  288. }
  289. /**
  290. * Compare the specified object with this list for equality. This
  291. * implementation uses exactly the code that is used to define the
  292. * list equals function in the documentation for the
  293. * <code>List.equals</code> method.
  294. *
  295. * @param o Object to be compared to this list
  296. */
  297. public boolean equals(Object o) {
  298. // Simple tests that require no synchronization
  299. if (o == this)
  300. return (true);
  301. else if (!(o instanceof List))
  302. return (false);
  303. List lo = (List) o;
  304. // Compare the sets of elements for equality
  305. if (fast) {
  306. ListIterator li1 = list.listIterator();
  307. ListIterator li2 = lo.listIterator();
  308. while (li1.hasNext() && li2.hasNext()) {
  309. Object o1 = li1.next();
  310. Object o2 = li2.next();
  311. if (!(o1 == null ? o2 == null : o1.equals(o2)))
  312. return (false);
  313. }
  314. return (!(li1.hasNext() || li2.hasNext()));
  315. } else {
  316. synchronized (list) {
  317. ListIterator li1 = list.listIterator();
  318. ListIterator li2 = lo.listIterator();
  319. while (li1.hasNext() && li2.hasNext()) {
  320. Object o1 = li1.next();
  321. Object o2 = li2.next();
  322. if (!(o1 == null ? o2 == null : o1.equals(o2)))
  323. return (false);
  324. }
  325. return (!(li1.hasNext() || li2.hasNext()));
  326. }
  327. }
  328. }
  329. /**
  330. * Return the element at the specified position in the list.
  331. *
  332. * @param index The index of the element to return
  333. *
  334. * @exception IndexOutOfBoundsException if the index is out of range
  335. */
  336. public Object get(int index) {
  337. if (fast) {
  338. return (list.get(index));
  339. } else {
  340. synchronized (list) {
  341. return (list.get(index));
  342. }
  343. }
  344. }
  345. /**
  346. * Return the hash code value for this list. This implementation uses
  347. * exactly the code that is used to define the list hash function in the
  348. * documentation for the <code>List.hashCode</code> method.
  349. */
  350. public int hashCode() {
  351. if (fast) {
  352. int hashCode = 1;
  353. java.util.Iterator i = list.iterator();
  354. while (i.hasNext()) {
  355. Object o = i.next();
  356. hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
  357. }
  358. return (hashCode);
  359. } else {
  360. synchronized (list) {
  361. int hashCode = 1;
  362. java.util.Iterator i = list.iterator();
  363. while (i.hasNext()) {
  364. Object o = i.next();
  365. hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
  366. }
  367. return (hashCode);
  368. }
  369. }
  370. }
  371. /**
  372. * Search for the first occurrence of the given argument, testing
  373. * for equality using the <code>equals()</code> method, and return
  374. * the corresponding index, or -1 if the object is not found.
  375. *
  376. * @param element The element to search for
  377. */
  378. public int indexOf(Object element) {
  379. if (fast) {
  380. return (list.indexOf(element));
  381. } else {
  382. synchronized (list) {
  383. return (list.indexOf(element));
  384. }
  385. }
  386. }
  387. /**
  388. * Test if this list has no elements.
  389. */
  390. public boolean isEmpty() {
  391. if (fast) {
  392. return (list.isEmpty());
  393. } else {
  394. synchronized (list) {
  395. return (list.isEmpty());
  396. }
  397. }
  398. }
  399. /**
  400. * Return an iterator over the elements in this list in proper sequence.
  401. * <br><br>
  402. * <strong>IMPLEMENTATION NOTE</strong> - If the list is operating in fast
  403. * mode, an Iterator is returned, and a structural modification to the
  404. * list is made, then the Iterator will continue over the previous contents
  405. * of the list (at the time that the Iterator was created), rather than
  406. * failing due to concurrent modifications.
  407. */
  408. public Iterator iterator() {
  409. if (fast) {
  410. return new ListIter(0);
  411. } else {
  412. return list.iterator();
  413. }
  414. }
  415. /**
  416. * Search for the last occurrence of the given argument, testing
  417. * for equality using the <code>equals()</code> method, and return
  418. * the corresponding index, or -1 if the object is not found.
  419. *
  420. * @param element The element to search for
  421. */
  422. public int lastIndexOf(Object element) {
  423. if (fast) {
  424. return (list.lastIndexOf(element));
  425. } else {
  426. synchronized (list) {
  427. return (list.lastIndexOf(element));
  428. }
  429. }
  430. }
  431. /**
  432. * Return an iterator of the elements of this list, in proper sequence.
  433. * See the implementation note on <code>iterator()</code>.
  434. */
  435. public ListIterator listIterator() {
  436. if (fast) {
  437. return new ListIter(0);
  438. } else {
  439. return list.listIterator();
  440. }
  441. }
  442. /**
  443. * Return an iterator of the elements of this list, in proper sequence,
  444. * starting at the specified position.
  445. * See the implementation note on <code>iterator()</code>.
  446. *
  447. * @param index The starting position of the iterator to return
  448. *
  449. * @exception IndexOutOfBoundsException if the index is out of range
  450. */
  451. public ListIterator listIterator(int index) {
  452. if (fast) {
  453. return new ListIter(index);
  454. } else {
  455. return list.listIterator(index);
  456. }
  457. }
  458. /**
  459. * Remove the element at the specified position in the list, and shift
  460. * any subsequent elements down one position.
  461. *
  462. * @param index Index of the element to be removed
  463. *
  464. * @exception IndexOutOfBoundsException if the index is out of range
  465. */
  466. public Object remove(int index) {
  467. if (fast) {
  468. synchronized (this) {
  469. ArrayList temp = (ArrayList) list.clone();
  470. Object result = temp.remove(index);
  471. list = temp;
  472. return (result);
  473. }
  474. } else {
  475. synchronized (list) {
  476. return (list.remove(index));
  477. }
  478. }
  479. }
  480. /**
  481. * Remove the first occurrence of the specified element from the list,
  482. * and shift any subsequent elements down one position.
  483. *
  484. * @param element Element to be removed
  485. */
  486. public boolean remove(Object element) {
  487. if (fast) {
  488. synchronized (this) {
  489. ArrayList temp = (ArrayList) list.clone();
  490. boolean result = temp.remove(element);
  491. list = temp;
  492. return (result);
  493. }
  494. } else {
  495. synchronized (list) {
  496. return (list.remove(element));
  497. }
  498. }
  499. }
  500. /**
  501. * Remove from this collection all of its elements that are contained
  502. * in the specified collection.
  503. *
  504. * @param collection Collection containing elements to be removed
  505. *
  506. * @exception UnsupportedOperationException if this optional operation
  507. * is not supported by this list
  508. */
  509. public boolean removeAll(Collection collection) {
  510. if (fast) {
  511. synchronized (this) {
  512. ArrayList temp = (ArrayList) list.clone();
  513. boolean result = temp.removeAll(collection);
  514. list = temp;
  515. return (result);
  516. }
  517. } else {
  518. synchronized (list) {
  519. return (list.removeAll(collection));
  520. }
  521. }
  522. }
  523. /**
  524. * Remove from this collection all of its elements except those that are
  525. * contained in the specified collection.
  526. *
  527. * @param collection Collection containing elements to be retained
  528. *
  529. * @exception UnsupportedOperationException if this optional operation
  530. * is not supported by this list
  531. */
  532. public boolean retainAll(Collection collection) {
  533. if (fast) {
  534. synchronized (this) {
  535. ArrayList temp = (ArrayList) list.clone();
  536. boolean result = temp.retainAll(collection);
  537. list = temp;
  538. return (result);
  539. }
  540. } else {
  541. synchronized (list) {
  542. return (list.retainAll(collection));
  543. }
  544. }
  545. }
  546. /**
  547. * Replace the element at the specified position in this list with
  548. * the specified element. Returns the previous object at that position.
  549. * <br><br>
  550. * <strong>IMPLEMENTATION NOTE</strong> - This operation is specifically
  551. * documented to not be a structural change, so it is safe to be performed
  552. * without cloning.
  553. *
  554. * @param index Index of the element to replace
  555. * @param element The new element to be stored
  556. *
  557. * @exception IndexOutOfBoundsException if the index is out of range
  558. */
  559. public Object set(int index, Object element) {
  560. if (fast) {
  561. return (list.set(index, element));
  562. } else {
  563. synchronized (list) {
  564. return (list.set(index, element));
  565. }
  566. }
  567. }
  568. /**
  569. * Return the number of elements in this list.
  570. */
  571. public int size() {
  572. if (fast) {
  573. return (list.size());
  574. } else {
  575. synchronized (list) {
  576. return (list.size());
  577. }
  578. }
  579. }
  580. /**
  581. * Return a view of the portion of this list between fromIndex
  582. * (inclusive) and toIndex (exclusive). The returned list is backed
  583. * by this list, so non-structural changes in the returned list are
  584. * reflected in this list. The returned list supports
  585. * all of the optional list operations supported by this list.
  586. *
  587. * @param fromIndex The starting index of the sublist view
  588. * @param toIndex The index after the end of the sublist view
  589. *
  590. * @exception IndexOutOfBoundsException if an index is out of range
  591. */
  592. public List subList(int fromIndex, int toIndex) {
  593. if (fast) {
  594. return new SubList(fromIndex, toIndex);
  595. } else {
  596. return list.subList(fromIndex, toIndex);
  597. }
  598. }
  599. /**
  600. * Return an array containing all of the elements in this list in the
  601. * correct order.
  602. */
  603. public Object[] toArray() {
  604. if (fast) {
  605. return (list.toArray());
  606. } else {
  607. synchronized (list) {
  608. return (list.toArray());
  609. }
  610. }
  611. }
  612. /**
  613. * Return an array containing all of the elements in this list in the
  614. * correct order. The runtime type of the returned array is that of
  615. * the specified array. If the list fits in the specified array, it is
  616. * returned therein. Otherwise, a new array is allocated with the
  617. * runtime type of the specified array, and the size of this list.
  618. *
  619. * @param array Array defining the element type of the returned list
  620. *
  621. * @exception ArrayStoreException if the runtime type of <code>array</code>
  622. * is not a supertype of the runtime type of every element in this list
  623. */
  624. public Object[] toArray(Object array[]) {
  625. if (fast) {
  626. return (list.toArray(array));
  627. } else {
  628. synchronized (list) {
  629. return (list.toArray(array));
  630. }
  631. }
  632. }
  633. /**
  634. * Return a String representation of this object.
  635. */
  636. public String toString() {
  637. StringBuffer sb = new StringBuffer("FastArrayList[");
  638. sb.append(list.toString());
  639. sb.append("]");
  640. return (sb.toString());
  641. }
  642. /**
  643. * Trim the capacity of this <code>ArrayList</code> instance to be the
  644. * list's current size. An application can use this operation to minimize
  645. * the storage of an <code>ArrayList</code> instance.
  646. */
  647. public void trimToSize() {
  648. if (fast) {
  649. synchronized (this) {
  650. ArrayList temp = (ArrayList) list.clone();
  651. temp.trimToSize();
  652. list = temp;
  653. }
  654. } else {
  655. synchronized (list) {
  656. list.trimToSize();
  657. }
  658. }
  659. }
  660. private class SubList implements List {
  661. private int first;
  662. private int last;
  663. private List expected;
  664. public SubList(int first, int last) {
  665. this.first = first;
  666. this.last = last;
  667. this.expected = list;
  668. }
  669. private List get(List l) {
  670. if (list != expected) {
  671. throw new ConcurrentModificationException();
  672. }
  673. return l.subList(first, last);
  674. }
  675. public void clear() {
  676. if (fast) {
  677. synchronized (FastArrayList.this) {
  678. ArrayList temp = (ArrayList) list.clone();
  679. get(temp).clear();
  680. last = first;
  681. list = temp;
  682. expected = temp;
  683. }
  684. } else {
  685. synchronized (list) {
  686. get(expected).clear();
  687. }
  688. }
  689. }
  690. public boolean remove(Object o) {
  691. if (fast) {
  692. synchronized (FastArrayList.this) {
  693. ArrayList temp = (ArrayList) list.clone();
  694. boolean r = get(temp).remove(o);
  695. if (r) last--;
  696. list = temp;
  697. expected = temp;
  698. return r;
  699. }
  700. } else {
  701. synchronized (list) {
  702. return get(expected).remove(o);
  703. }
  704. }
  705. }
  706. public boolean removeAll(Collection o) {
  707. if (fast) {
  708. synchronized (FastArrayList.this) {
  709. ArrayList temp = (ArrayList) list.clone();
  710. List sub = get(temp);
  711. boolean r = sub.removeAll(o);
  712. if (r) last = first + sub.size();
  713. list = temp;
  714. expected = temp;
  715. return r;
  716. }
  717. } else {
  718. synchronized (list) {
  719. return get(expected).removeAll(o);
  720. }
  721. }
  722. }
  723. public boolean retainAll(Collection o) {
  724. if (fast) {
  725. synchronized (FastArrayList.this) {
  726. ArrayList temp = (ArrayList) list.clone();
  727. List sub = get(temp);
  728. boolean r = sub.retainAll(o);
  729. if (r) last = first + sub.size();
  730. list = temp;
  731. expected = temp;
  732. return r;
  733. }
  734. } else {
  735. synchronized (list) {
  736. return get(expected).retainAll(o);
  737. }
  738. }
  739. }
  740. public int size() {
  741. if (fast) {
  742. return get(expected).size();
  743. } else {
  744. synchronized (list) {
  745. return get(expected).size();
  746. }
  747. }
  748. }
  749. public boolean isEmpty() {
  750. if (fast) {
  751. return get(expected).isEmpty();
  752. } else {
  753. synchronized (list) {
  754. return get(expected).isEmpty();
  755. }
  756. }
  757. }
  758. public boolean contains(Object o) {
  759. if (fast) {
  760. return get(expected).contains(o);
  761. } else {
  762. synchronized (list) {
  763. return get(expected).contains(o);
  764. }
  765. }
  766. }
  767. public boolean containsAll(Collection o) {
  768. if (fast) {
  769. return get(expected).containsAll(o);
  770. } else {
  771. synchronized (list) {
  772. return get(expected).containsAll(o);
  773. }
  774. }
  775. }
  776. public Object[] toArray(Object[] o) {
  777. if (fast) {
  778. return get(expected).toArray(o);
  779. } else {
  780. synchronized (list) {
  781. return get(expected).toArray(o);
  782. }
  783. }
  784. }
  785. public Object[] toArray() {
  786. if (fast) {
  787. return get(expected).toArray();
  788. } else {
  789. synchronized (list) {
  790. return get(expected).toArray();
  791. }
  792. }
  793. }
  794. public boolean equals(Object o) {
  795. if (o == this) return true;
  796. if (fast) {
  797. return get(expected).equals(o);
  798. } else {
  799. synchronized (list) {
  800. return get(expected).equals(o);
  801. }
  802. }
  803. }
  804. public int hashCode() {
  805. if (fast) {
  806. return get(expected).hashCode();
  807. } else {
  808. synchronized (list) {
  809. return get(expected).hashCode();
  810. }
  811. }
  812. }
  813. public boolean add(Object o) {
  814. if (fast) {
  815. synchronized (FastArrayList.this) {
  816. ArrayList temp = (ArrayList) list.clone();
  817. boolean r = get(temp).add(o);
  818. if (r) last++;
  819. list = temp;
  820. expected = temp;
  821. return r;
  822. }
  823. } else {
  824. synchronized (list) {
  825. return get(expected).add(o);
  826. }
  827. }
  828. }
  829. public boolean addAll(Collection o) {
  830. if (fast) {
  831. synchronized (FastArrayList.this) {
  832. ArrayList temp = (ArrayList) list.clone();
  833. boolean r = get(temp).addAll(o);
  834. if (r) last += o.size();
  835. list = temp;
  836. expected = temp;
  837. return r;
  838. }
  839. } else {
  840. synchronized (list) {
  841. return get(expected).addAll(o);
  842. }
  843. }
  844. }
  845. public void add(int i, Object o) {
  846. if (fast) {
  847. synchronized (FastArrayList.this) {
  848. ArrayList temp = (ArrayList) list.clone();
  849. get(temp).add(i, o);
  850. last++;
  851. list = temp;
  852. expected = temp;
  853. }
  854. } else {
  855. synchronized (list) {
  856. get(expected).add(i, o);
  857. }
  858. }
  859. }
  860. public boolean addAll(int i, Collection o) {
  861. if (fast) {
  862. synchronized (FastArrayList.this) {
  863. ArrayList temp = (ArrayList) list.clone();
  864. boolean r = get(temp).addAll(i, o);
  865. list = temp;
  866. if (r) last += o.size();
  867. expected = temp;
  868. return r;
  869. }
  870. } else {
  871. synchronized (list) {
  872. return get(expected).addAll(i, o);
  873. }
  874. }
  875. }
  876. public Object remove(int i) {
  877. if (fast) {
  878. synchronized (FastArrayList.this) {
  879. ArrayList temp = (ArrayList) list.clone();
  880. Object o = get(temp).remove(i);
  881. last--;
  882. list = temp;
  883. expected = temp;
  884. return o;
  885. }
  886. } else {
  887. synchronized (list) {
  888. return get(expected).remove(i);
  889. }
  890. }
  891. }
  892. public Object set(int i, Object a) {
  893. if (fast) {
  894. synchronized (FastArrayList.this) {
  895. ArrayList temp = (ArrayList) list.clone();
  896. Object o = get(temp).set(i, a);
  897. list = temp;
  898. expected = temp;
  899. return o;
  900. }
  901. } else {
  902. synchronized (list) {
  903. return get(expected).set(i, a);
  904. }
  905. }
  906. }
  907. public Iterator iterator() {
  908. return new SubListIter(0);
  909. }
  910. public ListIterator listIterator() {
  911. return new SubListIter(0);
  912. }
  913. public ListIterator listIterator(int i) {
  914. return new SubListIter(i);
  915. }
  916. public Object get(int i) {
  917. if (fast) {
  918. return get(expected).get(i);
  919. } else {
  920. synchronized (list) {
  921. return get(expected).get(i);
  922. }
  923. }
  924. }
  925. public int indexOf(Object o) {
  926. if (fast) {
  927. return get(expected).indexOf(o);
  928. } else {
  929. synchronized (list) {
  930. return get(expected).indexOf(o);
  931. }
  932. }
  933. }
  934. public int lastIndexOf(Object o) {
  935. if (fast) {
  936. return get(expected).lastIndexOf(o);
  937. } else {
  938. synchronized (list) {
  939. return get(expected).lastIndexOf(o);
  940. }
  941. }
  942. }
  943. public List subList(int f, int l) {
  944. if (list != expected) {
  945. throw new ConcurrentModificationException();
  946. }
  947. return new SubList(first + f, f + l);
  948. }
  949. private class SubListIter implements ListIterator {
  950. private List expected;
  951. private ListIterator iter;
  952. private int lastReturnedIndex = -1;
  953. public SubListIter(int i) {
  954. this.expected = list;
  955. this.iter = SubList.this.get(expected).listIterator(i);
  956. }
  957. private void checkMod() {
  958. if (list != expected) {
  959. throw new ConcurrentModificationException();
  960. }
  961. }
  962. List get() {
  963. return SubList.this.get(expected);
  964. }
  965. public boolean hasNext() {
  966. checkMod();
  967. return iter.hasNext();
  968. }
  969. public Object next() {
  970. checkMod();
  971. lastReturnedIndex = iter.nextIndex();
  972. return iter.next();
  973. }
  974. public boolean hasPrevious() {
  975. checkMod();
  976. return iter.hasPrevious();
  977. }
  978. public Object previous() {
  979. checkMod();
  980. lastReturnedIndex = iter.previousIndex();
  981. return iter.previous();
  982. }
  983. public int previousIndex() {
  984. checkMod();
  985. return iter.previousIndex();
  986. }
  987. public int nextIndex() {
  988. checkMod();
  989. return iter.nextIndex();
  990. }
  991. public void remove() {
  992. checkMod();
  993. if (lastReturnedIndex < 0) {
  994. throw new IllegalStateException();
  995. }
  996. get().remove(lastReturnedIndex);
  997. last--;
  998. expected = list;
  999. iter = get().listIterator(previousIndex());
  1000. lastReturnedIndex = -1;
  1001. }
  1002. public void set(Object o) {
  1003. checkMod();
  1004. if (lastReturnedIndex < 0) {
  1005. throw new IllegalStateException();
  1006. }
  1007. get().set(lastReturnedIndex, o);
  1008. expected = list;
  1009. iter = get().listIterator(previousIndex() + 1);
  1010. }
  1011. public void add(Object o) {
  1012. checkMod();
  1013. int i = nextIndex();
  1014. get().add(i, o);
  1015. last++;
  1016. iter = get().listIterator(i + 1);
  1017. lastReturnedIndex = 1;
  1018. }
  1019. }
  1020. }
  1021. private class ListIter implements ListIterator {
  1022. private List expected;
  1023. private ListIterator iter;
  1024. private int lastReturnedIndex = -1;
  1025. public ListIter(int i) {
  1026. this.expected = list;
  1027. this.iter = get().listIterator(i);
  1028. }
  1029. private void checkMod() {
  1030. if (list != expected) {
  1031. throw new ConcurrentModificationException();
  1032. }
  1033. }
  1034. List get() {
  1035. return expected;
  1036. }
  1037. public boolean hasNext() {
  1038. checkMod();
  1039. return iter.hasNext();
  1040. }
  1041. public Object next() {
  1042. checkMod();
  1043. lastReturnedIndex = iter.nextIndex();
  1044. return iter.next();
  1045. }
  1046. public boolean hasPrevious() {
  1047. checkMod();
  1048. return iter.hasPrevious();
  1049. }
  1050. public Object previous() {
  1051. checkMod();
  1052. lastReturnedIndex = iter.previousIndex();
  1053. return iter.previous();
  1054. }
  1055. public int previousIndex() {
  1056. checkMod();
  1057. return iter.previousIndex();
  1058. }
  1059. public int nextIndex() {
  1060. checkMod();
  1061. return iter.nextIndex();
  1062. }
  1063. public void remove() {
  1064. checkMod();
  1065. if (lastReturnedIndex < 0) {
  1066. throw new IllegalStateException();
  1067. }
  1068. get().remove(lastReturnedIndex);
  1069. expected = list;
  1070. iter = get().listIterator(previousIndex());
  1071. lastReturnedIndex = -1;
  1072. }
  1073. public void set(Object o) {
  1074. checkMod();
  1075. if (lastReturnedIndex < 0) {
  1076. throw new IllegalStateException();
  1077. }
  1078. get().set(lastReturnedIndex, o);
  1079. expected = list;
  1080. iter = get().listIterator(previousIndex() + 1);
  1081. }
  1082. public void add(Object o) {
  1083. checkMod();
  1084. int i = nextIndex();
  1085. get().add(i, o);
  1086. iter = get().listIterator(i + 1);
  1087. lastReturnedIndex = -1;
  1088. }
  1089. }
  1090. }