@@ -112,11 +112,11 @@ public boolean setAll(E... elements) {
112112
113113 @ Override
114114 public boolean setAll (Collection <? extends E > col ) {
115- Objects . requireNonNull (col );
116- onProposedChange (Collections . unmodifiableList ( new ArrayList <>( col )) , 0 , size ());
115+ List < E > elements = unmodifiableList (col );
116+ onProposedChange (elements , 0 , size ());
117117 try {
118118 modCount ++;
119- return list .setAll (col );
119+ return list .setAll (elements );
120120 } catch (Exception e ) {
121121 modCount --;
122122 throw e ;
@@ -191,7 +191,7 @@ public boolean contains(Object o) {
191191
192192 @ Override
193193 public Iterator <E > iterator () {
194- return new VetoableIteratorDecorator (new ModCountAccessorImpl (),list .iterator (), 0 );
194+ return new VetoableIteratorDecorator (this , new ModCountAccessorImpl (), list .iterator (), 0 );
195195 }
196196
197197 @ Override
@@ -234,11 +234,11 @@ public boolean containsAll(Collection<?> c) {
234234
235235 @ Override
236236 public boolean addAll (Collection <? extends E > c ) {
237- Objects . requireNonNull (c );
238- onProposedChange (Collections . unmodifiableList ( new ArrayList <>( c )) , size (), size ());
237+ List < E > elements = unmodifiableList (c );
238+ onProposedChange (elements , size (), size ());
239239 try {
240240 modCount ++;
241- boolean ret = list .addAll (c );
241+ boolean ret = list .addAll (elements );
242242 if (!ret )
243243 modCount --;
244244 return ret ;
@@ -250,12 +250,12 @@ public boolean addAll(Collection<? extends E> c) {
250250
251251 @ Override
252252 public boolean addAll (int index , Collection <? extends E > c ) {
253- Objects .requireNonNull (c );
254253 Objects .checkIndex (index , size () + 1 );
255- onProposedChange (Collections .unmodifiableList (new ArrayList <>(c )), index , index );
254+ List <E > elements = unmodifiableList (c );
255+ onProposedChange (elements , index , index );
256256 try {
257257 modCount ++;
258- boolean ret = list .addAll (index , c );
258+ boolean ret = list .addAll (index , elements );
259259 if (!ret )
260260 modCount --;
261261 return ret ;
@@ -267,11 +267,11 @@ public boolean addAll(int index, Collection<? extends E> c) {
267267
268268 @ Override
269269 public boolean removeAll (Collection <?> c ) {
270- Objects . requireNonNull (c );
271- removeFromList (this , 0 , c , false );
270+ Collection <?> elements = safeCollection (c );
271+ removeFromList (this , 0 , elements , false );
272272 try {
273273 modCount ++;
274- boolean ret = list .removeAll (c );
274+ boolean ret = list .removeAll (elements );
275275 if (!ret )
276276 modCount --;
277277 return ret ;
@@ -283,11 +283,11 @@ public boolean removeAll(Collection<?> c) {
283283
284284 @ Override
285285 public boolean retainAll (Collection <?> c ) {
286- Objects . requireNonNull (c );
287- removeFromList (this , 0 , c , true );
286+ Collection <?> elements = safeCollection (c );
287+ removeFromList (this , 0 , elements , true );
288288 try {
289289 modCount ++;
290- boolean ret = list .retainAll (c );
290+ boolean ret = list .retainAll (elements );
291291 if (!ret )
292292 modCount --;
293293 return ret ;
@@ -359,17 +359,17 @@ public int lastIndexOf(Object o) {
359359
360360 @ Override
361361 public ListIterator <E > listIterator () {
362- return new VetoableListIteratorDecorator (new ModCountAccessorImpl (), list .listIterator (), 0 );
362+ return new VetoableListIteratorDecorator (this , new ModCountAccessorImpl (), list .listIterator (), 0 );
363363 }
364364
365365 @ Override
366366 public ListIterator <E > listIterator (int index ) {
367- return new VetoableListIteratorDecorator (new ModCountAccessorImpl (), list .listIterator (index ), index );
367+ return new VetoableListIteratorDecorator (this , new ModCountAccessorImpl (), list .listIterator (index ), index );
368368 }
369369
370370 @ Override
371371 public List <E > subList (int fromIndex , int toIndex ) {
372- return new VetoableSubListDecorator (new ModCountAccessorImpl (), list .subList (fromIndex , toIndex ), fromIndex );
372+ return new VetoableSubListDecorator (this , new ModCountAccessorImpl (), list .subList (fromIndex , toIndex ), fromIndex );
373373 }
374374
375375 @ Override
@@ -387,14 +387,37 @@ public int hashCode() {
387387 return list .hashCode ();
388388 }
389389
390- private class VetoableSubListDecorator implements List <E > {
390+ /**
391+ * Returns the specified collection as an unmodifiable list that can safely be used in all bulk
392+ * operations without triggering {@link ConcurrentModificationException}.
393+ */
394+ private <T > List <T > unmodifiableList (Collection <? extends T > c ) {
395+ Objects .requireNonNull (c );
396+ return !(c instanceof List <?>) || (c instanceof VetoableSubListDecorator <?> d && d .parent == this )
397+ ? Collections .unmodifiableList (new ArrayList <>(c ))
398+ : Collections .unmodifiableList ((List <T >)c );
399+ }
400+
401+ /**
402+ * Returns a collection that can safely be used in the {@link #removeAll(Collection)} and
403+ * {@link #retainAll(Collection)} operations without triggering {@link ConcurrentModificationException}.
404+ */
405+ private <T > Collection <T > safeCollection (Collection <T > c ) {
406+ Objects .requireNonNull (c );
407+ return c instanceof VetoableSubListDecorator <?> d && d .parent == this
408+ ? (List <T >)Arrays .asList (c .toArray ())
409+ : c ;
410+ }
391411
412+ private static class VetoableSubListDecorator <E > implements List <E > {
413+ private final VetoableListDecorator parent ;
392414 private final List <E > subList ;
393415 private final int offset ;
394416 private final ModCountAccessor modCountAccessor ;
395417 private int modCount ;
396418
397- public VetoableSubListDecorator (ModCountAccessor modCountAccessor , List <E > subList , int offset ) {
419+ public VetoableSubListDecorator (VetoableListDecorator <E > parent , ModCountAccessor modCountAccessor , List <E > subList , int offset ) {
420+ this .parent = parent ;
398421 this .modCountAccessor = modCountAccessor ;
399422 this .modCount = modCountAccessor .get ();
400423 this .subList = subList ;
@@ -423,7 +446,7 @@ public boolean contains(Object o) {
423446 @ Override
424447 public Iterator <E > iterator () {
425448 checkForComodification ();
426- return new VetoableIteratorDecorator (new ModCountAccessorImplSub (), subList .iterator (), offset );
449+ return new VetoableIteratorDecorator (parent , new ModCountAccessorImplSub (), subList .iterator (), offset );
427450 }
428451
429452 @ Override
@@ -441,7 +464,7 @@ public <T> T[] toArray(T[] a) {
441464 @ Override
442465 public boolean add (E e ) {
443466 checkForComodification ();
444- onProposedChange (Collections .<E >singletonList (e ), offset + size (), offset + size ());
467+ parent . onProposedChange (Collections .<E >singletonList (e ), offset + size (), offset + size ());
445468 try {
446469 incrementModCount ();
447470 subList .add (e );
@@ -471,12 +494,12 @@ public boolean containsAll(Collection<?> c) {
471494
472495 @ Override
473496 public boolean addAll (Collection <? extends E > c ) {
474- Objects .requireNonNull (c );
475497 checkForComodification ();
476- onProposedChange (Collections .unmodifiableList (new ArrayList <>(c )), offset + size (), offset + size ());
498+ List <E > elements = parent .unmodifiableList (c );
499+ parent .onProposedChange (elements , offset + size (), offset + size ());
477500 try {
478501 incrementModCount ();
479- boolean res = subList .addAll (c );
502+ boolean res = subList .addAll (elements );
480503 if (!res )
481504 decrementModCount ();
482505 return res ;
@@ -488,13 +511,13 @@ public boolean addAll(Collection<? extends E> c) {
488511
489512 @ Override
490513 public boolean addAll (int index , Collection <? extends E > c ) {
491- Objects .requireNonNull (c );
492514 Objects .checkIndex (index , size () + 1 );
493515 checkForComodification ();
494- onProposedChange (Collections .unmodifiableList (new ArrayList <>(c )), offset + index , offset + index );
516+ List <E > elements = parent .unmodifiableList (c );
517+ parent .onProposedChange (elements , offset + index , offset + index );
495518 try {
496519 incrementModCount ();
497- boolean res = subList .addAll (index , c );
520+ boolean res = subList .addAll (index , elements );
498521 if (!res )
499522 decrementModCount ();
500523 return res ;
@@ -506,12 +529,12 @@ public boolean addAll(int index, Collection<? extends E> c) {
506529
507530 @ Override
508531 public boolean removeAll (Collection <?> c ) {
509- Objects .requireNonNull (c );
510532 checkForComodification ();
511- removeFromList (this , offset , c , false );
533+ Collection <?> elements = parent .safeCollection (c );
534+ parent .removeFromList (this , offset , elements , false );
512535 try {
513536 incrementModCount ();
514- boolean res = subList .removeAll (c );
537+ boolean res = subList .removeAll (elements );
515538 if (!res )
516539 decrementModCount ();
517540 return res ;
@@ -523,12 +546,12 @@ public boolean removeAll(Collection<?> c) {
523546
524547 @ Override
525548 public boolean retainAll (Collection <?> c ) {
526- Objects .requireNonNull (c );
527549 checkForComodification ();
528- removeFromList (this , offset , c , true );
550+ Collection <?> elements = parent .safeCollection (c );
551+ parent .removeFromList (this , offset , elements , true );
529552 try {
530553 incrementModCount ();
531- boolean res = subList .retainAll (c );
554+ boolean res = subList .retainAll (elements );
532555 if (!res )
533556 decrementModCount ();
534557 return res ;
@@ -541,7 +564,7 @@ public boolean retainAll(Collection<?> c) {
541564 @ Override
542565 public void clear () {
543566 checkForComodification ();
544- onProposedChange (Collections .<E >emptyList (), offset , offset + size ());
567+ parent . onProposedChange (Collections .<E >emptyList (), offset , offset + size ());
545568 try {
546569 incrementModCount ();
547570 subList .clear ();
@@ -560,15 +583,15 @@ public E get(int index) {
560583 @ Override
561584 public E set (int index , E element ) {
562585 checkForComodification ();
563- onProposedChange (Collections .singletonList (element ), offset + index , offset + index + 1 );
586+ parent . onProposedChange (Collections .singletonList (element ), offset + index , offset + index + 1 );
564587 return subList .set (index , element );
565588 }
566589
567590 @ Override
568591 public void add (int index , E element ) {
569592 Objects .checkIndex (index , size () + 1 );
570593 checkForComodification ();
571- onProposedChange (Collections .singletonList (element ), offset + index , offset + index );
594+ parent . onProposedChange (Collections .singletonList (element ), offset + index , offset + index );
572595 try {
573596 incrementModCount ();
574597 subList .add (index , element );
@@ -582,7 +605,7 @@ public void add(int index, E element) {
582605 public E remove (int index ) {
583606 Objects .checkIndex (index , size ());
584607 checkForComodification ();
585- onProposedChange (Collections .<E >emptyList (), offset + index , offset + index + 1 );
608+ parent . onProposedChange (Collections .<E >emptyList (), offset + index , offset + index + 1 );
586609 try {
587610 incrementModCount ();
588611 E res = subList .remove (index );
@@ -609,21 +632,21 @@ public int lastIndexOf(Object o) {
609632 @ Override
610633 public ListIterator <E > listIterator () {
611634 checkForComodification ();
612- return new VetoableListIteratorDecorator (new ModCountAccessorImplSub (),
635+ return new VetoableListIteratorDecorator (parent , new ModCountAccessorImplSub (),
613636 subList .listIterator (), offset );
614637 }
615638
616639 @ Override
617640 public ListIterator <E > listIterator (int index ) {
618641 checkForComodification ();
619- return new VetoableListIteratorDecorator (new ModCountAccessorImplSub (),
642+ return new VetoableListIteratorDecorator (parent , new ModCountAccessorImplSub (),
620643 subList .listIterator (index ), offset + index );
621644 }
622645
623646 @ Override
624647 public List <E > subList (int fromIndex , int toIndex ) {
625648 checkForComodification ();
626- return new VetoableSubListDecorator (new ModCountAccessorImplSub (),
649+ return new VetoableSubListDecorator (parent , new ModCountAccessorImplSub (),
627650 subList .subList (fromIndex , toIndex ), offset + fromIndex );
628651 }
629652
@@ -678,16 +701,17 @@ public int decrementAndGet() {
678701 }
679702 }
680703
681- private class VetoableIteratorDecorator implements Iterator <E > {
682-
704+ private static class VetoableIteratorDecorator < E > implements Iterator <E > {
705+ final VetoableListDecorator < E > parent ;
683706 private final Iterator <E > it ;
684707 private final ModCountAccessor modCountAccessor ;
685708 private int modCount ;
686709 protected final int offset ;
687710 protected int cursor ;
688711 protected int lastReturned ;
689712
690- public VetoableIteratorDecorator (ModCountAccessor modCountAccessor , Iterator <E > it , int offset ) {
713+ public VetoableIteratorDecorator (VetoableListDecorator <E > parent , ModCountAccessor modCountAccessor , Iterator <E > it , int offset ) {
714+ this .parent = parent ;
691715 this .modCountAccessor = modCountAccessor ;
692716 this .modCount = modCountAccessor .get ();
693717 this .it = it ;
@@ -714,7 +738,7 @@ public void remove() {
714738 if (lastReturned == -1 ) {
715739 throw new IllegalStateException ();
716740 }
717- onProposedChange (Collections .<E >emptyList (), offset + lastReturned , offset + lastReturned + 1 );
741+ parent . onProposedChange (Collections .<E >emptyList (), offset + lastReturned , offset + lastReturned + 1 );
718742 try {
719743 incrementModCount ();
720744 it .remove ();
@@ -741,12 +765,12 @@ protected void decrementModCount() {
741765 }
742766 }
743767
744- private class VetoableListIteratorDecorator extends VetoableIteratorDecorator implements ListIterator <E > {
768+ private static class VetoableListIteratorDecorator < E > extends VetoableIteratorDecorator < E > implements ListIterator <E > {
745769
746770 private final ListIterator <E > lit ;
747771
748- public VetoableListIteratorDecorator (ModCountAccessor modCountAccessor , ListIterator <E > it , int offset ) {
749- super (modCountAccessor , it , offset );
772+ public VetoableListIteratorDecorator (VetoableListDecorator < E > parent , ModCountAccessor modCountAccessor , ListIterator <E > it , int offset ) {
773+ super (parent , modCountAccessor , it , offset );
750774 this .lit = it ;
751775 }
752776
@@ -782,14 +806,14 @@ public void set(E e) {
782806 if (lastReturned == -1 ) {
783807 throw new IllegalStateException ();
784808 }
785- onProposedChange (Collections .singletonList (e ), offset + lastReturned , offset + lastReturned + 1 );
809+ parent . onProposedChange (Collections .singletonList (e ), offset + lastReturned , offset + lastReturned + 1 );
786810 lit .set (e );
787811 }
788812
789813 @ Override
790814 public void add (E e ) {
791815 checkForComodification ();
792- onProposedChange (Collections .singletonList (e ), offset + cursor , offset + cursor );
816+ parent . onProposedChange (Collections .singletonList (e ), offset + cursor , offset + cursor );
793817 try {
794818 incrementModCount ();
795819 lit .add (e );
0 commit comments