PageRenderTime 28ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/Java.NET/JavApi Commons collections (Apache Port)/org.apache.commons.collections.list.CursorableLinkedList.cs

https://github.com/gadfly/nofs
C# | 679 lines | 314 code | 45 blank | 320 comment | 46 complexity | 513941e1feac76e1b03b12a88eab5d10 MD5 | raw file
  1. /*
  2. * Licensed under the Apache License, Version 2.0 (the "License");
  3. * you may not use this file except in compliance with the License.
  4. * You may obtain a copy of the License at
  5. *
  6. * http://www.apache.org/licenses/LICENSE-2.0
  7. *
  8. * Unless required by applicable law or agreed to in writing, software
  9. * distributed under the License is distributed on an "AS IS" BASIS,
  10. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. * See the License for the specific language governing permissions and
  12. * limitations under the License.
  13. *
  14. */
  15. using System;
  16. using java = biz.ritter.javapi;
  17. namespace org.apache.commons.collections.list
  18. {
  19. /**
  20. * A <code>List</code> implementation with a <code>ListIterator</code> that
  21. * allows concurrent modifications to the underlying list.
  22. * <p>
  23. * This implementation supports all of the optional {@link List} operations.
  24. * It extends <code>AbstractLinkedList</code> and thus provides the
  25. * stack/queue/dequeue operations available in {@link java.util.LinkedList}.
  26. * <p>
  27. * The main feature of this class is the ability to modify the list and the
  28. * iterator at the same time. Both the {@link #listIterator()} and {@link #cursor()}
  29. * methods provides access to a <code>Cursor</code> instance which extends
  30. * <code>ListIterator</code>. The cursor allows changes to the list concurrent
  31. * with changes to the iterator. Note that the {@link #iterator()} method and
  32. * sublists do <b>not</b> provide this cursor behaviour.
  33. * <p>
  34. * The <code>Cursor</code> class is provided partly for backwards compatibility
  35. * and partly because it allows the cursor to be directly closed. Closing the
  36. * cursor is optional because references are held via a <code>WeakReference</code>.
  37. * For most purposes, simply modify the iterator and list at will, and then let
  38. * the garbage collector to the rest.
  39. * <p>
  40. * <b>Note that this implementation is not synchronized.</b>
  41. *
  42. * @see java.util.LinkedList
  43. * @since Commons Collections 1.0
  44. * @version $Revision$ $Date$
  45. *
  46. * @author Rodney Waldhoff
  47. * @author Janek Bogucki
  48. * @author Simon Kitching
  49. * @author Stephen Colebourne
  50. */
  51. [Serializable]
  52. public class CursorableLinkedList : AbstractLinkedList, java.io.Serializable
  53. {
  54. /** Ensure serialization compatibility */
  55. private static readonly long serialVersionUID = 8836393098519411393L;
  56. /** A list of the cursor currently open on this list */
  57. [NonSerialized]
  58. protected java.util.List<Object> cursors = new java.util.ArrayList<Object>();
  59. //-----------------------------------------------------------------------
  60. /**
  61. * Constructor that creates.
  62. */
  63. public CursorableLinkedList()
  64. : base()
  65. {
  66. init(); // must call init() as use super();
  67. }
  68. /**
  69. * Constructor that copies the specified collection
  70. *
  71. * @param coll the collection to copy
  72. */
  73. public CursorableLinkedList(java.util.Collection<Object> coll)
  74. : base(coll)
  75. {
  76. }
  77. /**
  78. * The equivalent of a default constructor called
  79. * by any constructor and by <code>readObject</code>.
  80. */
  81. protected override void init()
  82. {
  83. base.init();
  84. cursors = new java.util.ArrayList<Object>();
  85. }
  86. //-----------------------------------------------------------------------
  87. /**
  88. * Returns an iterator that does <b>not</b> support concurrent modification.
  89. * <p>
  90. * If the underlying list is modified while iterating using this iterator
  91. * a ConcurrentModificationException will occur.
  92. * The cursor behaviour is available via {@link #listIterator()}.
  93. *
  94. * @return a new iterator that does <b>not</b> support concurrent modification
  95. */
  96. public override java.util.Iterator<Object> iterator()
  97. {
  98. return base.listIterator(0);
  99. }
  100. /**
  101. * Returns a cursor iterator that allows changes to the underlying list in parallel.
  102. * <p>
  103. * The cursor enables iteration and list changes to occur in any order without
  104. * invalidating the iterator (from one thread). When elements are added to the
  105. * list, an event is fired to all active cursors enabling them to adjust to the
  106. * change in the list.
  107. * <p>
  108. * When the "current" (i.e., last returned by {@link ListIterator#next}
  109. * or {@link ListIterator#previous}) element of the list is removed,
  110. * the cursor automatically adjusts to the change (invalidating the
  111. * last returned value such that it cannot be removed).
  112. *
  113. * @return a new cursor iterator
  114. */
  115. public override java.util.ListIterator<Object> listIterator()
  116. {
  117. return cursor(0);
  118. }
  119. /**
  120. * Returns a cursor iterator that allows changes to the underlying list in parallel.
  121. * <p>
  122. * The cursor enables iteration and list changes to occur in any order without
  123. * invalidating the iterator (from one thread). When elements are added to the
  124. * list, an event is fired to all active cursors enabling them to adjust to the
  125. * change in the list.
  126. * <p>
  127. * When the "current" (i.e., last returned by {@link ListIterator#next}
  128. * or {@link ListIterator#previous}) element of the list is removed,
  129. * the cursor automatically adjusts to the change (invalidating the
  130. * last returned value such that it cannot be removed).
  131. *
  132. * @param fromIndex the index to start from
  133. * @return a new cursor iterator
  134. */
  135. public override java.util.ListIterator<Object> listIterator(int fromIndex)
  136. {
  137. return cursor(fromIndex);
  138. }
  139. /**
  140. * Returns a {@link Cursor} for iterating through the elements of this list.
  141. * <p>
  142. * A <code>Cursor</code> is a <code>ListIterator</code> with an additional
  143. * <code>close()</code> method. Calling this method immediately discards the
  144. * references to the cursor. If it is not called, then the garbage collector
  145. * will still remove the reference as it is held via a <code>WeakReference</code>.
  146. * <p>
  147. * The cursor enables iteration and list changes to occur in any order without
  148. * invalidating the iterator (from one thread). When elements are added to the
  149. * list, an event is fired to all active cursors enabling them to adjust to the
  150. * change in the list.
  151. * <p>
  152. * When the "current" (i.e., last returned by {@link ListIterator#next}
  153. * or {@link ListIterator#previous}) element of the list is removed,
  154. * the cursor automatically adjusts to the change (invalidating the
  155. * last returned value such that it cannot be removed).
  156. * <p>
  157. * The {@link #listIterator()} method returns the same as this method, and can
  158. * be cast to a <code>Cursor</code> if the <code>close</code> method is required.
  159. *
  160. * @return a new cursor iterator
  161. */
  162. public virtual CursorableLinkedList.Cursor cursor()
  163. {
  164. return cursor(0);
  165. }
  166. /**
  167. * Returns a {@link Cursor} for iterating through the elements of this list
  168. * starting from a specified index.
  169. * <p>
  170. * A <code>Cursor</code> is a <code>ListIterator</code> with an additional
  171. * <code>close()</code> method. Calling this method immediately discards the
  172. * references to the cursor. If it is not called, then the garbage collector
  173. * will still remove the reference as it is held via a <code>WeakReference</code>.
  174. * <p>
  175. * The cursor enables iteration and list changes to occur in any order without
  176. * invalidating the iterator (from one thread). When elements are added to the
  177. * list, an event is fired to all active cursors enabling them to adjust to the
  178. * change in the list.
  179. * <p>
  180. * When the "current" (i.e., last returned by {@link ListIterator#next}
  181. * or {@link ListIterator#previous}) element of the list is removed,
  182. * the cursor automatically adjusts to the change (invalidating the
  183. * last returned value such that it cannot be removed).
  184. * <p>
  185. * The {@link #listIterator(int)} method returns the same as this method, and can
  186. * be cast to a <code>Cursor</code> if the <code>close</code> method is required.
  187. *
  188. * @param fromIndex the index to start from
  189. * @return a new cursor iterator
  190. * @throws IndexOutOfBoundsException if the index is out of range
  191. * (index &lt; 0 || index &gt; size()).
  192. */
  193. public virtual CursorableLinkedList.Cursor cursor(int fromIndex)
  194. {
  195. Cursor cursor = new Cursor(this, fromIndex);
  196. registerCursor(cursor);
  197. return cursor;
  198. }
  199. //-----------------------------------------------------------------------
  200. /**
  201. * Updates the node with a new value.
  202. * This implementation sets the value on the node.
  203. * Subclasses can override this to record the change.
  204. *
  205. * @param node node to update
  206. * @param value new value of the node
  207. */
  208. protected override void updateNode(Node node, Object value)
  209. {
  210. base.updateNode(node, value);
  211. broadcastNodeChanged(node);
  212. }
  213. /**
  214. * Inserts a new node into the list.
  215. *
  216. * @param nodeToInsert new node to insert
  217. * @param insertBeforeNode node to insert before
  218. * @throws NullPointerException if either node is null
  219. */
  220. protected override void addNode(Node nodeToInsert, Node insertBeforeNode)
  221. {
  222. base.addNode(nodeToInsert, insertBeforeNode);
  223. broadcastNodeInserted(nodeToInsert);
  224. }
  225. /**
  226. * Removes the specified node from the list.
  227. *
  228. * @param node the node to remove
  229. * @throws NullPointerException if <code>node</code> is null
  230. */
  231. protected internal override void removeNode(Node node)
  232. {
  233. base.removeNode(node);
  234. broadcastNodeRemoved(node);
  235. }
  236. /**
  237. * Removes all nodes by iteration.
  238. */
  239. protected override void removeAllNodes()
  240. {
  241. if (size() > 0)
  242. {
  243. // superclass implementation would break all the iterators
  244. java.util.Iterator<Object> it = iterator();
  245. while (it.hasNext())
  246. {
  247. it.next();
  248. it.remove();
  249. }
  250. }
  251. }
  252. //-----------------------------------------------------------------------
  253. /**
  254. * Registers a cursor to be notified of changes to this list.
  255. *
  256. * @param cursor the cursor to register
  257. */
  258. protected virtual void registerCursor(Cursor cursor)
  259. {
  260. // We take this opportunity to clean the cursors list
  261. // of WeakReference objects to garbage-collected cursors.
  262. for (java.util.Iterator<Object> it = cursors.iterator(); it.hasNext(); )
  263. {
  264. java.lang.refj.WeakReference<Object> refJ = (java.lang.refj.WeakReference<Object>)it.next();
  265. if (refJ.get() == null)
  266. {
  267. it.remove();
  268. }
  269. }
  270. cursors.add(new java.lang.refj.WeakReference<Object>(cursor));
  271. }
  272. /**
  273. * Deregisters a cursor from the list to be notified of changes.
  274. *
  275. * @param cursor the cursor to deregister
  276. */
  277. protected virtual void unregisterCursor(Cursor cursor)
  278. {
  279. for (java.util.Iterator<Object> it = cursors.iterator(); it.hasNext(); )
  280. {
  281. java.lang.refj.WeakReference<Object> refJ = (java.lang.refj.WeakReference<Object>)it.next();
  282. Cursor cur = (Cursor)refJ.get();
  283. if (cur == null)
  284. {
  285. // some other unrelated cursor object has been
  286. // garbage-collected; let's take the opportunity to
  287. // clean up the cursors list anyway..
  288. it.remove();
  289. }
  290. else if (cur == cursor)
  291. {
  292. refJ.clear();
  293. it.remove();
  294. break;
  295. }
  296. }
  297. }
  298. //-----------------------------------------------------------------------
  299. /**
  300. * Informs all of my registered cursors that the specified
  301. * element was changed.
  302. *
  303. * @param node the node that was changed
  304. */
  305. protected virtual void broadcastNodeChanged(Node node)
  306. {
  307. java.util.Iterator<Object> it = cursors.iterator();
  308. while (it.hasNext())
  309. {
  310. java.lang.refj.WeakReference<Object> refJ = (java.lang.refj.WeakReference<Object>)it.next();
  311. Cursor cursor = (Cursor)refJ.get();
  312. if (cursor == null)
  313. {
  314. it.remove(); // clean up list
  315. }
  316. else
  317. {
  318. cursor.nodeChanged(node);
  319. }
  320. }
  321. }
  322. /**
  323. * Informs all of my registered cursors that the specified
  324. * element was just removed from my list.
  325. *
  326. * @param node the node that was changed
  327. */
  328. protected virtual void broadcastNodeRemoved(Node node)
  329. {
  330. java.util.Iterator<Object> it = cursors.iterator();
  331. while (it.hasNext())
  332. {
  333. java.lang.refj.WeakReference<Object> refJ = (java.lang.refj.WeakReference<Object>)it.next();
  334. Cursor cursor = (Cursor)refJ.get();
  335. if (cursor == null)
  336. {
  337. it.remove(); // clean up list
  338. }
  339. else
  340. {
  341. cursor.nodeRemoved(node);
  342. }
  343. }
  344. }
  345. /**
  346. * Informs all of my registered cursors that the specified
  347. * element was just added to my list.
  348. *
  349. * @param node the node that was changed
  350. */
  351. protected virtual void broadcastNodeInserted(Node node)
  352. {
  353. java.util.Iterator<Object> it = cursors.iterator();
  354. while (it.hasNext())
  355. {
  356. java.lang.refj.WeakReference<Object> refJ = (java.lang.refj.WeakReference<Object>)it.next();
  357. Cursor cursor = (Cursor)refJ.get();
  358. if (cursor == null)
  359. {
  360. it.remove(); // clean up list
  361. }
  362. else
  363. {
  364. cursor.nodeInserted(node);
  365. }
  366. }
  367. }
  368. //-----------------------------------------------------------------------
  369. /**
  370. * Serializes the data held in this object to the stream specified.
  371. */
  372. private void writeObject(java.io.ObjectOutputStream outJ)
  373. {//throws IOException {
  374. outJ.defaultWriteObject();
  375. doWriteObject(outJ);
  376. }
  377. /**
  378. * Deserializes the data held in this object to the stream specified.
  379. */
  380. private void readObject(java.io.ObjectInputStream inJ)
  381. {//throws IOException, ClassNotFoundException {
  382. inJ.defaultReadObject();
  383. doReadObject(inJ);
  384. }
  385. //-----------------------------------------------------------------------
  386. /**
  387. * Creates a list iterator for the sublist.
  388. *
  389. * @param subList the sublist to get an iterator for
  390. * @param fromIndex the index to start from, relative to the sublist
  391. */
  392. protected internal override java.util.ListIterator<Object> createSubListListIterator(LinkedSubList subList, int fromIndex)
  393. {
  394. SubCursor cursor = new SubCursor(subList, fromIndex);
  395. registerCursor(cursor);
  396. return cursor;
  397. }
  398. //-----------------------------------------------------------------------
  399. /**
  400. * An extended <code>ListIterator</code> that allows concurrent changes to
  401. * the underlying list.
  402. */
  403. //! Why doesn't AbstractLinkedList.LinkedListIterator not work??? - Subclass Public... adding for work!
  404. public class Cursor : /*AbstractLinkedList.*/PublicLinkedListIterator
  405. {
  406. /** Is the cursor valid (not closed) */
  407. bool valid = true;
  408. /** Is the next index valid */
  409. bool nextIndexValid = true;
  410. /** Flag to indicate if the current element was removed by another object. */
  411. bool currentRemovedByAnother = false;
  412. /**
  413. * Constructs a new cursor.
  414. *
  415. * @param index the index to start from
  416. */
  417. protected internal Cursor(CursorableLinkedList parent, int index)
  418. : base(parent, index)
  419. {
  420. valid = true;
  421. }
  422. /**
  423. * Removes the item last returned by this iterator.
  424. * <p>
  425. * There may have been subsequent alterations to the list
  426. * since you obtained this item, however you can still remove it.
  427. * You can even remove it if the item is no longer in the main list.
  428. * However, you can't call this method on the same iterator more
  429. * than once without calling next() or previous().
  430. *
  431. * @throws IllegalStateException if there is no item to remove
  432. */
  433. public override void remove()
  434. {
  435. // overridden, as the nodeRemoved() method updates the iterator
  436. // state in the parent.removeNode() call below
  437. if (current == null && currentRemovedByAnother)
  438. {
  439. // quietly ignore, as the last returned node was removed
  440. // by the list or some other iterator
  441. // by ignoring it, we keep this iterator independent from
  442. // other changes as much as possible
  443. }
  444. else
  445. {
  446. checkModCount();
  447. parent.removeNode(getLastNodeReturned());
  448. }
  449. currentRemovedByAnother = false;
  450. }
  451. /**
  452. * Adds an object to the list.
  453. * The object added here will be the new 'previous' in the iterator.
  454. *
  455. * @param obj the object to add
  456. */
  457. public override void add(Object obj)
  458. {
  459. // overridden, as the nodeInserted() method updates the iterator state
  460. base.add(obj);
  461. // matches the (next.previous == node) clause in nodeInserted()
  462. // thus next gets changed - reset it again here
  463. nextJ = nextJ.next;
  464. }
  465. // set is not overridden, as it works ok
  466. // note that we want it to throw an exception if the element being
  467. // set has been removed from the real list (compare this with the
  468. // remove method where we silently ignore this case)
  469. /**
  470. * Gets the index of the next element to be returned.
  471. *
  472. * @return the next index
  473. */
  474. public override int nextIndex()
  475. {
  476. if (nextIndexValid == false)
  477. {
  478. if (nextJ == parent.header)
  479. {
  480. nextIndexJ = parent.size();
  481. }
  482. else
  483. {
  484. int pos = 0;
  485. Node temp = parent.header.next;
  486. while (temp != nextJ)
  487. {
  488. pos++;
  489. temp = temp.next;
  490. }
  491. nextIndexJ = pos;
  492. }
  493. nextIndexValid = true;
  494. }
  495. return nextIndexJ;
  496. }
  497. /**
  498. * Handle event from the list when a node has changed.
  499. *
  500. * @param node the node that changed
  501. */
  502. protected internal virtual void nodeChanged(Node node)
  503. {
  504. // do nothing
  505. }
  506. /**
  507. * Handle event from the list when a node has been removed.
  508. *
  509. * @param node the node that was removed
  510. */
  511. protected internal virtual void nodeRemoved(Node node)
  512. {
  513. if (node == nextJ && node == current)
  514. {
  515. // state where next() followed by previous()
  516. nextJ = node.next;
  517. current = null;
  518. currentRemovedByAnother = true;
  519. }
  520. else if (node == nextJ)
  521. {
  522. // state where next() not followed by previous()
  523. // and we are matching next node
  524. nextJ = node.next;
  525. currentRemovedByAnother = false;
  526. }
  527. else if (node == current)
  528. {
  529. // state where next() not followed by previous()
  530. // and we are matching current (last returned) node
  531. current = null;
  532. currentRemovedByAnother = true;
  533. nextIndexJ--;
  534. }
  535. else
  536. {
  537. nextIndexValid = false;
  538. currentRemovedByAnother = false;
  539. }
  540. }
  541. /**
  542. * Handle event from the list when a node has been added.
  543. *
  544. * @param node the node that was added
  545. */
  546. protected internal virtual void nodeInserted(Node node)
  547. {
  548. if (node.previous == current)
  549. {
  550. nextJ = node;
  551. }
  552. else if (nextJ.previous == node)
  553. {
  554. nextJ = node;
  555. }
  556. else
  557. {
  558. nextIndexValid = false;
  559. }
  560. }
  561. /**
  562. * Override superclass modCount check, and replace it with our valid flag.
  563. */
  564. protected override void checkModCount()
  565. {
  566. if (!valid)
  567. {
  568. throw new java.util.ConcurrentModificationException("Cursor closed");
  569. }
  570. }
  571. /**
  572. * Mark this cursor as no longer being needed. Any resources
  573. * associated with this cursor are immediately released.
  574. * In previous versions of this class, it was mandatory to close
  575. * all cursor objects to avoid memory leaks. It is <i>no longer</i>
  576. * necessary to call this close method; an instance of this class
  577. * can now be treated exactly like a normal iterator.
  578. */
  579. public virtual void close()
  580. {
  581. if (valid)
  582. {
  583. ((CursorableLinkedList)parent).unregisterCursor(this);
  584. valid = false;
  585. }
  586. }
  587. }
  588. //-----------------------------------------------------------------------
  589. /**
  590. * A cursor for the sublist based on LinkedSubListIterator.
  591. *
  592. * @since Commons Collections 3.2
  593. */
  594. protected internal class SubCursor : Cursor
  595. {
  596. /** The parent list */
  597. protected readonly LinkedSubList sub;
  598. /**
  599. * Constructs a new cursor.
  600. *
  601. * @param index the index to start from
  602. */
  603. protected internal SubCursor(LinkedSubList sub, int index)
  604. : base((CursorableLinkedList)sub.parent, index + sub.offset)
  605. {
  606. this.sub = sub;
  607. }
  608. public override bool hasNext()
  609. {
  610. return (nextIndex() < sub.sizeJ);
  611. }
  612. public override bool hasPrevious()
  613. {
  614. return (previousIndex() >= 0);
  615. }
  616. public override int nextIndex()
  617. {
  618. return (base.nextIndex() - sub.offset);
  619. }
  620. public override void add(Object obj)
  621. {
  622. base.add(obj);
  623. sub.expectedModCount = parent.modCount;
  624. sub.sizeJ++;
  625. }
  626. public override void remove()
  627. {
  628. base.remove();
  629. sub.expectedModCount = parent.modCount;
  630. sub.sizeJ--;
  631. }
  632. }
  633. }
  634. }