CursorableLinkedList.java

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

  18. import java.io.IOException;
  19. import java.io.ObjectInputStream;
  20. import java.io.ObjectOutputStream;
  21. import java.io.Serializable;
  22. import java.lang.ref.WeakReference;
  23. import java.util.ArrayList;
  24. import java.util.Collection;
  25. import java.util.ConcurrentModificationException;
  26. import java.util.Iterator;
  27. import java.util.List;
  28. import java.util.ListIterator;

  29. /**
  30.  * A {@code List} implementation with a {@code ListIterator} that
  31.  * allows concurrent modifications to the underlying list.
  32.  * <p>
  33.  * This implementation supports all of the optional {@link List} operations.
  34.  * It extends {@code AbstractLinkedList} and thus provides the
  35.  * stack/queue/dequeue operations available in {@link java.util.LinkedList}.
  36.  * </p>
  37.  * <p>
  38.  * The main feature of this class is the ability to modify the list and the
  39.  * iterator at the same time. Both the {@link #listIterator()} and {@link #cursor()}
  40.  * methods provides access to a {@code Cursor} instance which extends
  41.  * {@code ListIterator}. The cursor allows changes to the list concurrent
  42.  * with changes to the iterator. Note that the {@link #iterator()} method and
  43.  * sublists do <strong>not</strong> provide this cursor behavior.
  44.  * </p>
  45.  * <p>
  46.  * The {@code Cursor} class is provided partly for backwards compatibility
  47.  * and partly because it allows the cursor to be directly closed. Closing the
  48.  * cursor is optional because references are held via a {@code WeakReference}.
  49.  * For most purposes, simply modify the iterator and list at will, and then let
  50.  * the garbage collector to the rest.
  51.  * </p>
  52.  * <p>
  53.  * <strong>Note that this implementation is not synchronized.</strong>
  54.  * </p>
  55.  *
  56.  * @param <E> the type of the elements in the list.
  57.  * @see java.util.LinkedList
  58.  * @since 1.0
  59.  * @deprecated parent {@link AbstractLinkedList} is source incompatible with List methods added in Java 21
  60.  */
  61. @Deprecated
  62. public class CursorableLinkedList<E> extends AbstractLinkedList<E> implements Serializable {

  63.     /**
  64.      * An extended {@code ListIterator} that allows concurrent changes to
  65.      * the underlying list.
  66.      *
  67.      * @param <E> the type of elements in this cursor.
  68.      */
  69.     public static class Cursor<E> extends AbstractLinkedList.LinkedListIterator<E> {
  70.         /** Is the cursor valid (not closed) */
  71.         boolean valid = true;
  72.         /** Is the next index valid */
  73.         boolean nextIndexValid = true;
  74.         /** Flag to indicate if the current element was removed by another object. */
  75.         boolean currentRemovedByAnother;

  76.         /**
  77.          * Constructs a new cursor.
  78.          *
  79.          * @param parent  the parent list
  80.          * @param index  the index to start from
  81.          */
  82.         protected Cursor(final CursorableLinkedList<E> parent, final int index) {
  83.             super(parent, index);
  84.             valid = true;
  85.         }

  86.         /**
  87.          * Adds an object to the list.
  88.          * The object added here will be the new 'previous' in the iterator.
  89.          *
  90.          * @param obj  the object to add
  91.          */
  92.         @Override
  93.         public void add(final E obj) {
  94.             // overridden, as the nodeInserted() method updates the iterator state
  95.             super.add(obj);
  96.             // matches the (next.previous == node) clause in nodeInserted()
  97.             // thus next gets changed - reset it again here
  98.             next = next.next;
  99.         }

  100.         /**
  101.          * Override superclass modCount check, and replace it with our valid flag.
  102.          */
  103.         @Override
  104.         protected void checkModCount() {
  105.             if (!valid) {
  106.                 throw new ConcurrentModificationException("Cursor closed");
  107.             }
  108.         }

  109.         // set is not overridden, as it works ok
  110.         // note that we want it to throw an exception if the element being
  111.         // set has been removed from the real list (compare this with the
  112.         // remove method where we silently ignore this case)

  113.         /**
  114.          * Mark this cursor as no longer being needed. Any resources
  115.          * associated with this cursor are immediately released.
  116.          * In previous versions of this class, it was mandatory to close
  117.          * all cursor objects to avoid memory leaks. It is <em>no longer</em>
  118.          * necessary to call this close method; an instance of this class
  119.          * can now be treated exactly like a normal iterator.
  120.          */
  121.         public void close() {
  122.             if (valid) {
  123.                 ((CursorableLinkedList<E>) parent).unregisterCursor(this);
  124.                 valid = false;
  125.             }
  126.         }

  127.         /**
  128.          * Gets the index of the next element to be returned.
  129.          *
  130.          * @return the next index
  131.          */
  132.         @Override
  133.         public int nextIndex() {
  134.             if (!nextIndexValid) {
  135.                 if (next == parent.header) {
  136.                     nextIndex = parent.size();
  137.                 } else {
  138.                     int pos = 0;
  139.                     Node<E> temp = parent.header.next;
  140.                     while (temp != next) {
  141.                         pos++;
  142.                         temp = temp.next;
  143.                     }
  144.                     nextIndex = pos;
  145.                 }
  146.                 nextIndexValid = true;
  147.             }
  148.             return nextIndex;
  149.         }

  150.         /**
  151.          * Handle event from the list when a node has changed.
  152.          *
  153.          * @param node  the node that changed
  154.          */
  155.         protected void nodeChanged(final Node<E> node) {
  156.             // do nothing
  157.         }

  158.         /**
  159.          * Handle event from the list when a node has been added.
  160.          *
  161.          * @param node  the node that was added
  162.          */
  163.         protected void nodeInserted(final Node<E> node) {
  164.             if (node.previous == current || next.previous == node) {
  165.                 next = node;
  166.             } else {
  167.                 nextIndexValid = false;
  168.             }
  169.         }

  170.         /**
  171.          * Handle event from the list when a node has been removed.
  172.          *
  173.          * @param node  the node that was removed
  174.          */
  175.         protected void nodeRemoved(final Node<E> node) {
  176.             if (node == next && node == current) {
  177.                 // state where next() followed by previous()
  178.                 next = node.next;
  179.                 current = null;
  180.                 currentRemovedByAnother = true;
  181.             } else if (node == next) {
  182.                 // state where next() not followed by previous()
  183.                 // and we are matching next node
  184.                 next = node.next;
  185.                 currentRemovedByAnother = false;
  186.             } else if (node == current) {
  187.                 // state where next() not followed by previous()
  188.                 // and we are matching current (last returned) node
  189.                 current = null;
  190.                 currentRemovedByAnother = true;
  191.                 nextIndex--;
  192.             } else {
  193.                 nextIndexValid = false;
  194.                 currentRemovedByAnother = false;
  195.             }
  196.         }

  197.         /**
  198.          * Removes the item last returned by this iterator.
  199.          * <p>
  200.          * There may have been subsequent alterations to the list
  201.          * since you obtained this item, however you can still remove it.
  202.          * You can even remove it if the item is no longer in the main list.
  203.          * However, you can't call this method on the same iterator more
  204.          * than once without calling next() or previous().
  205.          *
  206.          * @throws IllegalStateException if there is no item to remove
  207.          */
  208.         @Override
  209.         public void remove() {
  210.             // overridden, as the nodeRemoved() method updates the iterator
  211.             // state in the parent.removeNode() call below
  212.             if (current == null && currentRemovedByAnother) { // NOPMD
  213.                 // quietly ignore, as the last returned node was removed
  214.                 // by the list or some other iterator
  215.                 // by ignoring it, we keep this iterator independent of
  216.                 // other changes as much as possible
  217.             } else {
  218.                 checkModCount();
  219.                 parent.removeNode(getLastNodeReturned());
  220.             }
  221.             currentRemovedByAnother = false;
  222.         }
  223.     }

  224.     /**
  225.      * A cursor for the sublist based on LinkedSubListIterator.
  226.      *
  227.      * @param <E> the type of elements in this cursor.
  228.      * @since 3.2
  229.      */
  230.     protected static class SubCursor<E> extends Cursor<E> {

  231.         /** The parent list */
  232.         protected final LinkedSubList<E> sub;

  233.         /**
  234.          * Constructs a new cursor.
  235.          *
  236.          * @param sub  the sub list
  237.          * @param index  the index to start from
  238.          */
  239.         protected SubCursor(final LinkedSubList<E> sub, final int index) {
  240.             super((CursorableLinkedList<E>) sub.parent, index + sub.offset);
  241.             this.sub = sub;
  242.         }

  243.         @Override
  244.         public void add(final E obj) {
  245.             super.add(obj);
  246.             sub.expectedModCount = parent.modCount;
  247.             sub.size++;
  248.         }

  249.         @Override
  250.         public boolean hasNext() {
  251.             return nextIndex() < sub.size;
  252.         }

  253.         @Override
  254.         public boolean hasPrevious() {
  255.             return previousIndex() >= 0;
  256.         }

  257.         @Override
  258.         public int nextIndex() {
  259.             return super.nextIndex() - sub.offset;
  260.         }

  261.         @Override
  262.         public void remove() {
  263.             super.remove();
  264.             sub.expectedModCount = parent.modCount;
  265.             sub.size--;
  266.         }
  267.     }

  268.     /** Ensure serialization compatibility */
  269.     private static final long serialVersionUID = 8836393098519411393L;

  270.     /** A list of the cursor currently open on this list */
  271.     private transient List<WeakReference<Cursor<E>>> cursors;

  272.     /**
  273.      * Constructor that creates.
  274.      */
  275.     public CursorableLinkedList() {
  276.         init(); // must call init() as use super();
  277.     }

  278.     /**
  279.      * Constructor that copies the specified collection
  280.      *
  281.      * @param coll  the collection to copy
  282.      */
  283.     public CursorableLinkedList(final Collection<? extends E> coll) {
  284.         super(coll);
  285.     }

  286.     /**
  287.      * Inserts a new node into the list.
  288.      *
  289.      * @param nodeToInsert  new node to insert
  290.      * @param insertBeforeNode  node to insert before
  291.      * @throws NullPointerException if either node is null
  292.      */
  293.     @Override
  294.     protected void addNode(final Node<E> nodeToInsert, final Node<E> insertBeforeNode) {
  295.         super.addNode(nodeToInsert, insertBeforeNode);
  296.         broadcastNodeInserted(nodeToInsert);
  297.     }

  298.     /**
  299.      * Informs all of my registered cursors that the specified
  300.      * element was changed.
  301.      *
  302.      * @param node  the node that was changed
  303.      */
  304.     protected void broadcastNodeChanged(final Node<E> node) {
  305.         final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator();
  306.         while (it.hasNext()) {
  307.             final WeakReference<Cursor<E>> ref = it.next();
  308.             final Cursor<E> cursor = ref.get();
  309.             if (cursor == null) {
  310.                 it.remove(); // clean up list
  311.             } else {
  312.                 cursor.nodeChanged(node);
  313.             }
  314.         }
  315.     }

  316.     /**
  317.      * Informs all of my registered cursors that the specified
  318.      * element was just added to my list.
  319.      *
  320.      * @param node  the node that was changed
  321.      */
  322.     protected void broadcastNodeInserted(final Node<E> node) {
  323.         final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator();
  324.         while (it.hasNext()) {
  325.             final WeakReference<Cursor<E>> ref = it.next();
  326.             final Cursor<E> cursor = ref.get();
  327.             if (cursor == null) {
  328.                 it.remove(); // clean up list
  329.             } else {
  330.                 cursor.nodeInserted(node);
  331.             }
  332.         }
  333.     }

  334.     /**
  335.      * Informs all of my registered cursors that the specified
  336.      * element was just removed from my list.
  337.      *
  338.      * @param node  the node that was changed
  339.      */
  340.     protected void broadcastNodeRemoved(final Node<E> node) {
  341.         final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator();
  342.         while (it.hasNext()) {
  343.             final WeakReference<Cursor<E>> ref = it.next();
  344.             final Cursor<E> cursor = ref.get();
  345.             if (cursor == null) {
  346.                 it.remove(); // clean up list
  347.             } else {
  348.                 cursor.nodeRemoved(node);
  349.             }
  350.         }
  351.     }

  352.     /**
  353.      * Creates a list iterator for the sublist.
  354.      *
  355.      * @param subList  the sublist to get an iterator for
  356.      * @param fromIndex  the index to start from, relative to the sublist
  357.      * @return the list iterator for the sublist
  358.      */
  359.     @Override
  360.     protected ListIterator<E> createSubListListIterator(final LinkedSubList<E> subList, final int fromIndex) {
  361.         final SubCursor<E> cursor = new SubCursor<>(subList, fromIndex);
  362.         registerCursor(cursor);
  363.         return cursor;
  364.     }

  365.     /**
  366.      * Returns a {@link Cursor} for iterating through the elements of this list.
  367.      * <p>
  368.      * A {@code Cursor} is a {@code ListIterator} with an additional
  369.      * {@code close()} method. Calling this method immediately discards the
  370.      * references to the cursor. If it is not called, then the garbage collector
  371.      * will still remove the reference as it is held via a {@code WeakReference}.
  372.      * <p>
  373.      * The cursor enables iteration and list changes to occur in any order without
  374.      * invalidating the iterator (from one thread). When elements are added to the
  375.      * list, an event is fired to all active cursors enabling them to adjust to the
  376.      * change in the list.
  377.      * <p>
  378.      * When the "current" (i.e., last returned by {@link ListIterator#next}
  379.      * or {@link ListIterator#previous}) element of the list is removed,
  380.      * the cursor automatically adjusts to the change (invalidating the
  381.      * last returned value such that it cannot be removed).
  382.      * <p>
  383.      * The {@link #listIterator()} method returns the same as this method, and can
  384.      * be cast to a {@code Cursor} if the {@code close} method is required.
  385.      *
  386.      * @return a new cursor iterator
  387.      */
  388.     public CursorableLinkedList.Cursor<E> cursor() {
  389.         return cursor(0);
  390.     }

  391.     /**
  392.      * Returns a {@link Cursor} for iterating through the elements of this list
  393.      * starting from a specified index.
  394.      * <p>
  395.      * A {@code Cursor} is a {@code ListIterator} with an additional
  396.      * {@code close()} method. Calling this method immediately discards the
  397.      * references to the cursor. If it is not called, then the garbage collector
  398.      * will still remove the reference as it is held via a {@code WeakReference}.
  399.      * <p>
  400.      * The cursor enables iteration and list changes to occur in any order without
  401.      * invalidating the iterator (from one thread). When elements are added to the
  402.      * list, an event is fired to all active cursors enabling them to adjust to the
  403.      * change in the list.
  404.      * <p>
  405.      * When the "current" (i.e., last returned by {@link ListIterator#next}
  406.      * or {@link ListIterator#previous}) element of the list is removed,
  407.      * the cursor automatically adjusts to the change (invalidating the
  408.      * last returned value such that it cannot be removed).
  409.      * <p>
  410.      * The {@link #listIterator(int)} method returns the same as this method, and can
  411.      * be cast to a {@code Cursor} if the {@code close} method is required.
  412.      *
  413.      * @param fromIndex  the index to start from
  414.      * @return a new cursor iterator
  415.      * @throws IndexOutOfBoundsException if the index is out of range
  416.      *      (index &lt; 0 || index &gt; size()).
  417.      */
  418.     public CursorableLinkedList.Cursor<E> cursor(final int fromIndex) {
  419.         final Cursor<E> cursor = new Cursor<>(this, fromIndex);
  420.         registerCursor(cursor);
  421.         return cursor;
  422.     }

  423.     /**
  424.      * The equivalent of a default constructor called
  425.      * by any constructor and by {@code readObject}.
  426.      */
  427.     @Override
  428.     protected void init() {
  429.         super.init();
  430.         cursors = new ArrayList<>();
  431.     }

  432.     /**
  433.      * Returns an iterator that does <strong>not</strong> support concurrent modification.
  434.      * <p>
  435.      * If the underlying list is modified while iterating using this iterator
  436.      * a ConcurrentModificationException will occur.
  437.      * The cursor behavior is available via {@link #listIterator()}.
  438.      *
  439.      * @return a new iterator that does <strong>not</strong> support concurrent modification
  440.      */
  441.     @Override
  442.     public Iterator<E> iterator() {
  443.         return super.listIterator(0);
  444.     }

  445.     /**
  446.      * Returns a cursor iterator that allows changes to the underlying list in parallel.
  447.      * <p>
  448.      * The cursor enables iteration and list changes to occur in any order without
  449.      * invalidating the iterator (from one thread). When elements are added to the
  450.      * list, an event is fired to all active cursors enabling them to adjust to the
  451.      * change in the list.
  452.      * <p>
  453.      * When the "current" (i.e., last returned by {@link ListIterator#next}
  454.      * or {@link ListIterator#previous}) element of the list is removed,
  455.      * the cursor automatically adjusts to the change (invalidating the
  456.      * last returned value such that it cannot be removed).
  457.      *
  458.      * @return a new cursor iterator
  459.      */
  460.     @Override
  461.     public ListIterator<E> listIterator() {
  462.         return cursor(0);
  463.     }

  464.     /**
  465.      * Returns a cursor iterator that allows changes to the underlying list in parallel.
  466.      * <p>
  467.      * The cursor enables iteration and list changes to occur in any order without
  468.      * invalidating the iterator (from one thread). When elements are added to the
  469.      * list, an event is fired to all active cursors enabling them to adjust to the
  470.      * change in the list.
  471.      * <p>
  472.      * When the "current" (i.e., last returned by {@link ListIterator#next}
  473.      * or {@link ListIterator#previous}) element of the list is removed,
  474.      * the cursor automatically adjusts to the change (invalidating the
  475.      * last returned value such that it cannot be removed).
  476.      *
  477.      * @param fromIndex  the index to start from
  478.      * @return a new cursor iterator
  479.      */
  480.     @Override
  481.     public ListIterator<E> listIterator(final int fromIndex) {
  482.         return cursor(fromIndex);
  483.     }

  484.     /**
  485.      * Deserializes the data held in this object to the stream specified.
  486.      *
  487.      * @param in  the input stream
  488.      * @throws IOException if an error occurs while reading from the stream
  489.      * @throws ClassNotFoundException if an object read from the stream cannot be loaded
  490.      */
  491.     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
  492.         in.defaultReadObject();
  493.         doReadObject(in);
  494.     }

  495.     /**
  496.      * Registers a cursor to be notified of changes to this list.
  497.      *
  498.      * @param cursor  the cursor to register
  499.      */
  500.     protected void registerCursor(final Cursor<E> cursor) {
  501.         // We take this opportunity to clean the cursors list
  502.         // of WeakReference objects to garbage-collected cursors.
  503.         cursors.removeIf(ref -> ref.get() == null);
  504.         cursors.add(new WeakReference<>(cursor));
  505.     }

  506.     /**
  507.      * Removes all nodes by iteration.
  508.      */
  509.     @Override
  510.     protected void removeAllNodes() {
  511.         if (!isEmpty()) {
  512.             // superclass implementation would break all the iterators
  513.             final Iterator<E> it = iterator();
  514.             while (it.hasNext()) {
  515.                 it.next();
  516.                 it.remove();
  517.             }
  518.         }
  519.     }

  520.     /**
  521.      * Removes the specified node from the list.
  522.      *
  523.      * @param node  the node to remove
  524.      * @throws NullPointerException if {@code node} is null
  525.      */
  526.     @Override
  527.     protected void removeNode(final Node<E> node) {
  528.         super.removeNode(node);
  529.         broadcastNodeRemoved(node);
  530.     }

  531.     /**
  532.      * Deregisters a cursor from the list to be notified of changes.
  533.      *
  534.      * @param cursor  the cursor to deregister
  535.      */
  536.     protected void unregisterCursor(final Cursor<E> cursor) {
  537.         for (final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator(); it.hasNext();) {
  538.             final WeakReference<Cursor<E>> ref = it.next();
  539.             final Cursor<E> cur = ref.get();
  540.             if (cur == null) {
  541.                 // some other unrelated cursor object has been
  542.                 // garbage-collected; let's take the opportunity to
  543.                 // clean up the cursors list anyway.
  544.                 it.remove();
  545.             } else if (cur == cursor) {
  546.                 ref.clear();
  547.                 it.remove();
  548.                 break;
  549.             }
  550.         }
  551.     }

  552.     /**
  553.      * Updates the node with a new value.
  554.      * This implementation sets the value on the node.
  555.      * Subclasses can override this to record the change.
  556.      *
  557.      * @param node  node to update
  558.      * @param value  new value of the node
  559.      */
  560.     @Override
  561.     protected void updateNode(final Node<E> node, final E value) {
  562.         super.updateNode(node, value);
  563.         broadcastNodeChanged(node);
  564.     }

  565.     /**
  566.      * Serializes this object to an ObjectOutputStream.
  567.      *
  568.      * @param out the target ObjectOutputStream.
  569.      * @throws IOException thrown when an I/O errors occur writing to the target stream.
  570.      */
  571.     private void writeObject(final ObjectOutputStream out) throws IOException {
  572.         out.defaultWriteObject();
  573.         doWriteObject(out);
  574.     }

  575. }