001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.collections4.list;
018
019import java.io.IOException;
020import java.io.ObjectInputStream;
021import java.io.ObjectOutputStream;
022import java.io.Serializable;
023import java.lang.ref.WeakReference;
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.ConcurrentModificationException;
027import java.util.Iterator;
028import java.util.List;
029import java.util.ListIterator;
030
031/**
032 * A {@code List} implementation with a {@code ListIterator} that
033 * allows concurrent modifications to the underlying list.
034 * <p>
035 * This implementation supports all of the optional {@link List} operations.
036 * It extends {@code AbstractLinkedList} and thus provides the
037 * stack/queue/dequeue operations available in {@link java.util.LinkedList}.
038 * </p>
039 * <p>
040 * The main feature of this class is the ability to modify the list and the
041 * iterator at the same time. Both the {@link #listIterator()} and {@link #cursor()}
042 * methods provides access to a {@code Cursor} instance which extends
043 * {@code ListIterator}. The cursor allows changes to the list concurrent
044 * with changes to the iterator. Note that the {@link #iterator()} method and
045 * sublists do <strong>not</strong> provide this cursor behavior.
046 * </p>
047 * <p>
048 * The {@code Cursor} class is provided partly for backwards compatibility
049 * and partly because it allows the cursor to be directly closed. Closing the
050 * cursor is optional because references are held via a {@code WeakReference}.
051 * For most purposes, simply modify the iterator and list at will, and then let
052 * the garbage collector to the rest.
053 * </p>
054 * <p>
055 * <strong>Note that this implementation is not synchronized.</strong>
056 * </p>
057 *
058 * @param <E> the type of the elements in the list.
059 * @see java.util.LinkedList
060 * @since 1.0
061 * @deprecated parent {@link AbstractLinkedList} is source incompatible with List methods added in Java 21
062 */
063@Deprecated
064public class CursorableLinkedList<E> extends AbstractLinkedList<E> implements Serializable {
065
066    /**
067     * An extended {@code ListIterator} that allows concurrent changes to
068     * the underlying list.
069     *
070     * @param <E> the type of elements in this cursor.
071     */
072    public static class Cursor<E> extends AbstractLinkedList.LinkedListIterator<E> {
073        /** Is the cursor valid (not closed) */
074        boolean valid = true;
075        /** Is the next index valid */
076        boolean nextIndexValid = true;
077        /** Flag to indicate if the current element was removed by another object. */
078        boolean currentRemovedByAnother;
079
080        /**
081         * Constructs a new cursor.
082         *
083         * @param parent  the parent list
084         * @param index  the index to start from
085         */
086        protected Cursor(final CursorableLinkedList<E> parent, final int index) {
087            super(parent, index);
088            valid = true;
089        }
090
091        /**
092         * Adds an object to the list.
093         * The object added here will be the new 'previous' in the iterator.
094         *
095         * @param obj  the object to add
096         */
097        @Override
098        public void add(final E obj) {
099            // overridden, as the nodeInserted() method updates the iterator state
100            super.add(obj);
101            // matches the (next.previous == node) clause in nodeInserted()
102            // thus next gets changed - reset it again here
103            next = next.next;
104        }
105
106        /**
107         * Override superclass modCount check, and replace it with our valid flag.
108         */
109        @Override
110        protected void checkModCount() {
111            if (!valid) {
112                throw new ConcurrentModificationException("Cursor closed");
113            }
114        }
115
116        // set is not overridden, as it works ok
117        // note that we want it to throw an exception if the element being
118        // set has been removed from the real list (compare this with the
119        // remove method where we silently ignore this case)
120
121        /**
122         * Mark this cursor as no longer being needed. Any resources
123         * associated with this cursor are immediately released.
124         * In previous versions of this class, it was mandatory to close
125         * all cursor objects to avoid memory leaks. It is <em>no longer</em>
126         * necessary to call this close method; an instance of this class
127         * can now be treated exactly like a normal iterator.
128         */
129        public void close() {
130            if (valid) {
131                ((CursorableLinkedList<E>) parent).unregisterCursor(this);
132                valid = false;
133            }
134        }
135
136        /**
137         * Gets the index of the next element to be returned.
138         *
139         * @return the next index
140         */
141        @Override
142        public int nextIndex() {
143            if (!nextIndexValid) {
144                if (next == parent.header) {
145                    nextIndex = parent.size();
146                } else {
147                    int pos = 0;
148                    Node<E> temp = parent.header.next;
149                    while (temp != next) {
150                        pos++;
151                        temp = temp.next;
152                    }
153                    nextIndex = pos;
154                }
155                nextIndexValid = true;
156            }
157            return nextIndex;
158        }
159
160        /**
161         * Handle event from the list when a node has changed.
162         *
163         * @param node  the node that changed
164         */
165        protected void nodeChanged(final Node<E> node) {
166            // do nothing
167        }
168
169        /**
170         * Handle event from the list when a node has been added.
171         *
172         * @param node  the node that was added
173         */
174        protected void nodeInserted(final Node<E> node) {
175            if (node.previous == current || next.previous == node) {
176                next = node;
177            } else {
178                nextIndexValid = false;
179            }
180        }
181
182        /**
183         * Handle event from the list when a node has been removed.
184         *
185         * @param node  the node that was removed
186         */
187        protected void nodeRemoved(final Node<E> node) {
188            if (node == next && node == current) {
189                // state where next() followed by previous()
190                next = node.next;
191                current = null;
192                currentRemovedByAnother = true;
193            } else if (node == next) {
194                // state where next() not followed by previous()
195                // and we are matching next node
196                next = node.next;
197                currentRemovedByAnother = false;
198            } else if (node == current) {
199                // state where next() not followed by previous()
200                // and we are matching current (last returned) node
201                current = null;
202                currentRemovedByAnother = true;
203                nextIndex--;
204            } else {
205                nextIndexValid = false;
206                currentRemovedByAnother = false;
207            }
208        }
209
210        /**
211         * Removes the item last returned by this iterator.
212         * <p>
213         * There may have been subsequent alterations to the list
214         * since you obtained this item, however you can still remove it.
215         * You can even remove it if the item is no longer in the main list.
216         * However, you can't call this method on the same iterator more
217         * than once without calling next() or previous().
218         *
219         * @throws IllegalStateException if there is no item to remove
220         */
221        @Override
222        public void remove() {
223            // overridden, as the nodeRemoved() method updates the iterator
224            // state in the parent.removeNode() call below
225            if (current == null && currentRemovedByAnother) { // NOPMD
226                // quietly ignore, as the last returned node was removed
227                // by the list or some other iterator
228                // by ignoring it, we keep this iterator independent of
229                // other changes as much as possible
230            } else {
231                checkModCount();
232                parent.removeNode(getLastNodeReturned());
233            }
234            currentRemovedByAnother = false;
235        }
236    }
237
238    /**
239     * A cursor for the sublist based on LinkedSubListIterator.
240     *
241     * @param <E> the type of elements in this cursor.
242     * @since 3.2
243     */
244    protected static class SubCursor<E> extends Cursor<E> {
245
246        /** The parent list */
247        protected final LinkedSubList<E> sub;
248
249        /**
250         * Constructs a new cursor.
251         *
252         * @param sub  the sub list
253         * @param index  the index to start from
254         */
255        protected SubCursor(final LinkedSubList<E> sub, final int index) {
256            super((CursorableLinkedList<E>) sub.parent, index + sub.offset);
257            this.sub = sub;
258        }
259
260        @Override
261        public void add(final E obj) {
262            super.add(obj);
263            sub.expectedModCount = parent.modCount;
264            sub.size++;
265        }
266
267        @Override
268        public boolean hasNext() {
269            return nextIndex() < sub.size;
270        }
271
272        @Override
273        public boolean hasPrevious() {
274            return previousIndex() >= 0;
275        }
276
277        @Override
278        public int nextIndex() {
279            return super.nextIndex() - sub.offset;
280        }
281
282        @Override
283        public void remove() {
284            super.remove();
285            sub.expectedModCount = parent.modCount;
286            sub.size--;
287        }
288    }
289
290    /** Ensure serialization compatibility */
291    private static final long serialVersionUID = 8836393098519411393L;
292
293    /** A list of the cursor currently open on this list */
294    private transient List<WeakReference<Cursor<E>>> cursors;
295
296    /**
297     * Constructor that creates.
298     */
299    public CursorableLinkedList() {
300        init(); // must call init() as use super();
301    }
302
303    /**
304     * Constructor that copies the specified collection
305     *
306     * @param coll  the collection to copy
307     */
308    public CursorableLinkedList(final Collection<? extends E> coll) {
309        super(coll);
310    }
311
312    /**
313     * Inserts a new node into the list.
314     *
315     * @param nodeToInsert  new node to insert
316     * @param insertBeforeNode  node to insert before
317     * @throws NullPointerException if either node is null
318     */
319    @Override
320    protected void addNode(final Node<E> nodeToInsert, final Node<E> insertBeforeNode) {
321        super.addNode(nodeToInsert, insertBeforeNode);
322        broadcastNodeInserted(nodeToInsert);
323    }
324
325    /**
326     * Informs all of my registered cursors that the specified
327     * element was changed.
328     *
329     * @param node  the node that was changed
330     */
331    protected void broadcastNodeChanged(final Node<E> node) {
332        final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator();
333        while (it.hasNext()) {
334            final WeakReference<Cursor<E>> ref = it.next();
335            final Cursor<E> cursor = ref.get();
336            if (cursor == null) {
337                it.remove(); // clean up list
338            } else {
339                cursor.nodeChanged(node);
340            }
341        }
342    }
343
344    /**
345     * Informs all of my registered cursors that the specified
346     * element was just added to my list.
347     *
348     * @param node  the node that was changed
349     */
350    protected void broadcastNodeInserted(final Node<E> node) {
351        final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator();
352        while (it.hasNext()) {
353            final WeakReference<Cursor<E>> ref = it.next();
354            final Cursor<E> cursor = ref.get();
355            if (cursor == null) {
356                it.remove(); // clean up list
357            } else {
358                cursor.nodeInserted(node);
359            }
360        }
361    }
362
363    /**
364     * Informs all of my registered cursors that the specified
365     * element was just removed from my list.
366     *
367     * @param node  the node that was changed
368     */
369    protected void broadcastNodeRemoved(final Node<E> node) {
370        final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator();
371        while (it.hasNext()) {
372            final WeakReference<Cursor<E>> ref = it.next();
373            final Cursor<E> cursor = ref.get();
374            if (cursor == null) {
375                it.remove(); // clean up list
376            } else {
377                cursor.nodeRemoved(node);
378            }
379        }
380    }
381
382    /**
383     * Creates a list iterator for the sublist.
384     *
385     * @param subList  the sublist to get an iterator for
386     * @param fromIndex  the index to start from, relative to the sublist
387     * @return the list iterator for the sublist
388     */
389    @Override
390    protected ListIterator<E> createSubListListIterator(final LinkedSubList<E> subList, final int fromIndex) {
391        final SubCursor<E> cursor = new SubCursor<>(subList, fromIndex);
392        registerCursor(cursor);
393        return cursor;
394    }
395
396    /**
397     * Returns a {@link Cursor} for iterating through the elements of this list.
398     * <p>
399     * A {@code Cursor} is a {@code ListIterator} with an additional
400     * {@code close()} method. Calling this method immediately discards the
401     * references to the cursor. If it is not called, then the garbage collector
402     * will still remove the reference as it is held via a {@code WeakReference}.
403     * <p>
404     * The cursor enables iteration and list changes to occur in any order without
405     * invalidating the iterator (from one thread). When elements are added to the
406     * list, an event is fired to all active cursors enabling them to adjust to the
407     * change in the list.
408     * <p>
409     * When the "current" (i.e., last returned by {@link ListIterator#next}
410     * or {@link ListIterator#previous}) element of the list is removed,
411     * the cursor automatically adjusts to the change (invalidating the
412     * last returned value such that it cannot be removed).
413     * <p>
414     * The {@link #listIterator()} method returns the same as this method, and can
415     * be cast to a {@code Cursor} if the {@code close} method is required.
416     *
417     * @return a new cursor iterator
418     */
419    public CursorableLinkedList.Cursor<E> cursor() {
420        return cursor(0);
421    }
422
423    /**
424     * Returns a {@link Cursor} for iterating through the elements of this list
425     * starting from a specified index.
426     * <p>
427     * A {@code Cursor} is a {@code ListIterator} with an additional
428     * {@code close()} method. Calling this method immediately discards the
429     * references to the cursor. If it is not called, then the garbage collector
430     * will still remove the reference as it is held via a {@code WeakReference}.
431     * <p>
432     * The cursor enables iteration and list changes to occur in any order without
433     * invalidating the iterator (from one thread). When elements are added to the
434     * list, an event is fired to all active cursors enabling them to adjust to the
435     * change in the list.
436     * <p>
437     * When the "current" (i.e., last returned by {@link ListIterator#next}
438     * or {@link ListIterator#previous}) element of the list is removed,
439     * the cursor automatically adjusts to the change (invalidating the
440     * last returned value such that it cannot be removed).
441     * <p>
442     * The {@link #listIterator(int)} method returns the same as this method, and can
443     * be cast to a {@code Cursor} if the {@code close} method is required.
444     *
445     * @param fromIndex  the index to start from
446     * @return a new cursor iterator
447     * @throws IndexOutOfBoundsException if the index is out of range
448     *      (index &lt; 0 || index &gt; size()).
449     */
450    public CursorableLinkedList.Cursor<E> cursor(final int fromIndex) {
451        final Cursor<E> cursor = new Cursor<>(this, fromIndex);
452        registerCursor(cursor);
453        return cursor;
454    }
455
456    /**
457     * The equivalent of a default constructor called
458     * by any constructor and by {@code readObject}.
459     */
460    @Override
461    protected void init() {
462        super.init();
463        cursors = new ArrayList<>();
464    }
465
466    /**
467     * Returns an iterator that does <strong>not</strong> support concurrent modification.
468     * <p>
469     * If the underlying list is modified while iterating using this iterator
470     * a ConcurrentModificationException will occur.
471     * The cursor behavior is available via {@link #listIterator()}.
472     *
473     * @return a new iterator that does <strong>not</strong> support concurrent modification
474     */
475    @Override
476    public Iterator<E> iterator() {
477        return super.listIterator(0);
478    }
479
480    /**
481     * Returns a cursor iterator that allows changes to the underlying list in parallel.
482     * <p>
483     * The cursor enables iteration and list changes to occur in any order without
484     * invalidating the iterator (from one thread). When elements are added to the
485     * list, an event is fired to all active cursors enabling them to adjust to the
486     * change in the list.
487     * <p>
488     * When the "current" (i.e., last returned by {@link ListIterator#next}
489     * or {@link ListIterator#previous}) element of the list is removed,
490     * the cursor automatically adjusts to the change (invalidating the
491     * last returned value such that it cannot be removed).
492     *
493     * @return a new cursor iterator
494     */
495    @Override
496    public ListIterator<E> listIterator() {
497        return cursor(0);
498    }
499
500    /**
501     * Returns a cursor iterator that allows changes to the underlying list in parallel.
502     * <p>
503     * The cursor enables iteration and list changes to occur in any order without
504     * invalidating the iterator (from one thread). When elements are added to the
505     * list, an event is fired to all active cursors enabling them to adjust to the
506     * change in the list.
507     * <p>
508     * When the "current" (i.e., last returned by {@link ListIterator#next}
509     * or {@link ListIterator#previous}) element of the list is removed,
510     * the cursor automatically adjusts to the change (invalidating the
511     * last returned value such that it cannot be removed).
512     *
513     * @param fromIndex  the index to start from
514     * @return a new cursor iterator
515     */
516    @Override
517    public ListIterator<E> listIterator(final int fromIndex) {
518        return cursor(fromIndex);
519    }
520
521    /**
522     * Deserializes the data held in this object to the stream specified.
523     *
524     * @param in  the input stream
525     * @throws IOException if an error occurs while reading from the stream
526     * @throws ClassNotFoundException if an object read from the stream cannot be loaded
527     */
528    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
529        in.defaultReadObject();
530        doReadObject(in);
531    }
532
533    /**
534     * Registers a cursor to be notified of changes to this list.
535     *
536     * @param cursor  the cursor to register
537     */
538    protected void registerCursor(final Cursor<E> cursor) {
539        // We take this opportunity to clean the cursors list
540        // of WeakReference objects to garbage-collected cursors.
541        cursors.removeIf(ref -> ref.get() == null);
542        cursors.add(new WeakReference<>(cursor));
543    }
544
545    /**
546     * Removes all nodes by iteration.
547     */
548    @Override
549    protected void removeAllNodes() {
550        if (!isEmpty()) {
551            // superclass implementation would break all the iterators
552            final Iterator<E> it = iterator();
553            while (it.hasNext()) {
554                it.next();
555                it.remove();
556            }
557        }
558    }
559
560    /**
561     * Removes the specified node from the list.
562     *
563     * @param node  the node to remove
564     * @throws NullPointerException if {@code node} is null
565     */
566    @Override
567    protected void removeNode(final Node<E> node) {
568        super.removeNode(node);
569        broadcastNodeRemoved(node);
570    }
571
572    /**
573     * Deregisters a cursor from the list to be notified of changes.
574     *
575     * @param cursor  the cursor to deregister
576     */
577    protected void unregisterCursor(final Cursor<E> cursor) {
578        for (final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator(); it.hasNext();) {
579            final WeakReference<Cursor<E>> ref = it.next();
580            final Cursor<E> cur = ref.get();
581            if (cur == null) {
582                // some other unrelated cursor object has been
583                // garbage-collected; let's take the opportunity to
584                // clean up the cursors list anyway.
585                it.remove();
586            } else if (cur == cursor) {
587                ref.clear();
588                it.remove();
589                break;
590            }
591        }
592    }
593
594    /**
595     * Updates the node with a new value.
596     * This implementation sets the value on the node.
597     * Subclasses can override this to record the change.
598     *
599     * @param node  node to update
600     * @param value  new value of the node
601     */
602    @Override
603    protected void updateNode(final Node<E> node, final E value) {
604        super.updateNode(node, value);
605        broadcastNodeChanged(node);
606    }
607
608    /**
609     * Serializes this object to an ObjectOutputStream.
610     *
611     * @param out the target ObjectOutputStream.
612     * @throws IOException thrown when an I/O errors occur writing to the target stream.
613     */
614    private void writeObject(final ObjectOutputStream out) throws IOException {
615        out.defaultWriteObject();
616        doWriteObject(out);
617    }
618
619}