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