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