1 package eu.simuline.util;
2
3 import java.lang.reflect.Array;
4
5 import java.util.List;
6 import java.util.Iterator;
7 import java.util.Spliterator; // for javadoc only
8 import java.util.ListIterator;
9 import java.util.Collections;
10 import java.util.Collection;
11 import java.util.AbstractCollection;
12 import java.util.ArrayList;
13 import java.util.Set;
14 import java.util.SortedSet;
15 import java.util.Comparator;
16 import java.util.WeakHashMap;
17 import java.util.EnumSet;
18 import java.util.Map;
19
20 import java.util.stream.Stream; // for javadoc only
21
22 import java.util.function.Predicate;
23 import java.util.function.Consumer;
24 import java.util.function.UnaryOperator;
25 import java.util.NavigableMap;
26
27 /**
28 * An add on of the core class {@link java.util.Collections}.
29 * This class provides various kinds of immutable collections,
30 * where immutability is configurable
31 * via a {@link CollectionsExt.Modification} object.
32 * <p>
33 * Also this class yields weak hash sets via {@link #weakHashSet()}.
34 * Moreover, there are methods to convert arrays and lists in one another
35 * also recursively.
36 * Finally, there are methods {@link #getUnique(Collection)}
37 * to retrieve the unique element and {@link #reverse(List)}
38 * reverses a list.
39 *
40 * @param <E>
41 * the class of the elements of collections under consideration.
42 *
43 * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
44 * @version 1.0
45 */
46 public abstract class CollectionsExt<E> {
47
48 /* -------------------------------------------------------------------- *
49 * inner classes. *
50 * -------------------------------------------------------------------- */
51
52 /**
53 * Enumerates the kinds of modifications on a {@link Collection}.
54 * A collection is modified either directly or via its iterator's
55 * method {@link Iterator#remove()}.
56 * The direct modifications split in adding and removing a single object,
57 * clearing the whole collection
58 * and bulk operations like adding, removing, retaining
59 * all objects which are in another {@link Collection}.
60 * Subinterfaces of {@link Collection}
61 * may offer further kinds of modifications:
62 * {@link SortedSet}s for example define views on the original set
63 *
64 */
65 public enum Modification {
66 /**
67 * Modification adding an element
68 * which may be by {@link Collection#add(Object)},
69 * {@link Collection#addAll(Collection)},
70 * by {@link List#add(int, Object)},
71 * {@link List#addAll(int, Collection)},
72 * <p>
73 . * Modification by {@link ListIterator#add(Object)}
74 * of (list)-iterator attached with underlying {@link List}
75 * via {@link List#listIterator()} or {@link List#listIterator(int)}.
76 */
77 AddObj,
78
79 /**
80 * Modification by {@link Collection#remove(Object)},
81 * {@link Collection#removeAll(Collection)},
82 * {@link Collection#retainAll(Collection)},
83 * {@link Collection#removeIf(Predicate)},
84 * {@link Collection#clear()}
85 * and by {@link List#remove(int)}.
86 * <p>
87 * Modification by {@link Iterator#remove()}
88 * of iterator attached with underlying {@link Collection}
89 * via {@link Collection#iterator()}, {@link List#listIterator()}
90 * or {@link List#listIterator(int)}.
91 */
92 RemoveObj,
93
94 /**
95 * Modification by {@link List#set(int, Object)},
96 * {@link List#replaceAll(UnaryOperator)} and
97 * {@link List#sort(Comparator)}.
98 * <p>
99 * Modification by {@link ListIterator#set(Object)}
100 * of iterator attached with underlying {@link List}
101 * via {@link List#listIterator()} or {@link List#listIterator(int)}.
102 */
103 SetObj;
104 } // enum Modification
105
106 /**
107 * A class of {@link Collection}s of elements of class <code>E</code>
108 * extending <code>C</code>
109 * initially throwing an <code>UnsupportedOperationException</code>
110 * when trying to modify the collection
111 * either directly or via its iterator(s)
112 * or via a transparent view
113 * like {@link List#subList(int, int)}.
114 * Note that neither arrays given e.g. by {@link Collection#toArray()}
115 * nor {@link Spliterator}s given by {@link Collection#spliterator()}
116 * nor {@link Stream}s given by {@link Collection#parallelStream()}
117 * give no rise to modifications of the underlying collection.
118 * **** currently, replacing (done for lists, e.g.),
119 * is not considered a modification but the objects are transformed...
120 * very esotheric...
121 * **** what must be done is overwrite the default implementation.
122 * Since it is not clear whether the wrapped collection did also overwrite,
123 * it is not clear which kind of operation is done.
124 * Thus it seems appropriate to define another kind of modification:
125 * SetAll
126
127 * New releases of the jdk may add default methods to interfaces
128 * and may thus add ways to modify a list.
129 * The problem is not so much a default implementation of the interface
130 * since this is based on elementary methods of that interface
131 * but if a class overwrites this
132 * using internal methods or direct access to fields.
133 * In particular, a each default method must be reimplemented:
134 * E.g. {@link Collection#removeIf(Predicate)}
135 * uses method {@link Collection#remove(Object)}
136 * but it is possible to implement {@link Collection#removeIf(Predicate)}
137 * without invoking {@link Collection#remove(Object)}
138 * in implementations of implementing classes of {@link Collection}.
139 *
140 * it is possible, although not likely,
141 * that
142
143
144 * <p>
145 * Instances of this class can be created via creator methods like
146 * {@link #getImmutableCollection(Collection)}.
147 * The collection with the original restrictions can be regained
148 * by {@link #unrestricted()}.
149 * A posteriory modifications can be allowed
150 * using {@link #allowModification(CollectionsExt.Modification)} or
151 * using {@link #allowModifications(Set)}.
152 * This class is <code>public</code>
153 * and {@link #getImmutableCollection(Collection)}
154 * returns instances of this class, to allow invoking methods
155 * {@link #allowModification(CollectionsExt.Modification)} and
156 * {@link #allowModifications(Set)}.
157 * <p>
158 * Methods defining non-modifying access,
159 * are just delegated to the collection
160 * returned by {@link #unrestricted()},
161 * whereas methods for modification are blocked
162 * if the modification is not allowed according to
163 * {@link #allowedModifications()}.
164 *
165 * @param <C>
166 * the class extending {@link Collection} with elements in E.
167 * @param <E>
168 * the class of the elements of this collection.
169 */
170 public abstract static
171 class AbstractImmutableCollection<C extends Collection<E>, E>
172 extends AbstractCollection<E> {
173
174 private static final long serialVersionUID = -2479143000061671589L;
175
176 /* ---------------------------------------------------------------- *
177 * fields. *
178 * ---------------------------------------------------------------- */
179
180 /**
181 * The set of allowed modifications.
182 */
183 private final Set<Modification> mods;
184
185 /* ---------------------------------------------------------------- *
186 * constructors. *
187 * ---------------------------------------------------------------- */
188
189 /**
190 * Creates an empty collection with no allowed modifications.
191 *
192 * @see #CollectionsExt.AbstractImmutableCollection(Set)
193 */
194 private AbstractImmutableCollection() {
195 this(EnumSet.noneOf(Modification.class));
196 }
197
198 /**
199 * Creates an empty collection with the allowed modifications
200 * given by <code>mods</code>.
201 * CAUTION: This is not a collection containing <code>mods</code>.
202 *
203 * @param mods
204 * The modifications currently allowed.
205 */
206 AbstractImmutableCollection(Set<Modification> mods) {
207 this.mods = mods;
208 }
209
210 /* ---------------------------------------------------------------- *
211 * methods. *
212 * ---------------------------------------------------------------- */
213
214 /**
215 * Allows in addition modification <code>mod</code>
216 * for this set, does not alter contents and returns <code>this</code>.
217 *
218 * @param mod
219 * A modification which shall be allowed in addition.
220 */
221 public final AbstractImmutableCollection<C, E>
222 allowModification(Modification mod) {
223 this.mods.add(mod);
224 return this;
225 }
226
227 /**
228 * Allows in addition modifications in <code>mods</code>
229 * for this set, does not alter contents and returns <code>this</code>.
230 *
231 * @param mods
232 * modifications which shall be allowed in addition.
233 */
234 public final void allowModifications(Set<Modification> mods) {
235 this.mods.addAll(mods);
236 }
237
238 // This method allows handling modifications more tightly
239 // so that the other methods are mere convenience methods.
240 /**
241 * Returns the set of allowed modification of this set
242 * without backup: Changing the returned set
243 * changes the allowed modifications for this set.
244 * Also applying {@link #allowModifications(Set)}
245 * modifies the returned set.
246 *
247 * @return
248 * the set of currently allowed modifications.
249 */
250 public final Set<Modification> allowedModifications() {
251 return this.mods;
252 }
253
254 /**
255 * Returns the underlying set without the restrictions
256 * imposed by this {@link CollectionsExt.ImmutableCollection}.
257 * Note that the result
258 * may still throw {@link UnsupportedOperationException}s
259 * depending on the implementation.
260 */
261 public abstract C unrestricted();
262
263 // from iterable
264 // forEach
265
266 // query operations
267
268 // iterator comes below
269
270 /**
271 * Returns the size of this collection.
272 */
273 public final int size() {
274 return unrestricted().size();
275 }
276
277 // inherited from AbstractCollection:
278 // isEmpty()
279 // boolean contains(Object o)
280 // Object[] toArray()
281 // T[] toArray(T[] a)
282
283
284 // Modification Operations
285
286 /**
287 * @throws UnsupportedOperationException
288 * if either {@link #unrestricted()} does not allow this operation
289 * or {@link CollectionsExt.Modification#AddObj AddObj}
290 * is no allowed operation
291 * according to {@link #allowedModifications()}.
292 * In the latter case it does not matter,
293 * whether effectively it is tried to add an object
294 * which is the case only <code>this</code>
295 * does not already contain <code>obj</code>.
296 */
297 // overwrites method that throws UnsupportedOperationException
298 public final boolean add(E obj) {
299 if (this.mods.contains(Modification.AddObj)) {
300 // may throw UnsupportedOperationException
301 return unrestricted().add(obj);
302 }
303
304 throw new UnsupportedOperationException();
305 }
306
307 /**
308 * @throws UnsupportedOperationException
309 * if either {@link #unrestricted()} does not allow this operation
310 * or {@link CollectionsExt.Modification#RemoveObj RemoveObj}
311 * is no allowed operation
312 * according to {@link #allowedModifications()}.
313 * In the latter case it does not matter,
314 * whether effectively it is tried to remove an object
315 * which is the case only <code>this</code>
316 * contains <code>obj</code>.
317 */
318 public final boolean remove(Object obj) {
319 if (this.mods.contains(Modification.RemoveObj)) {
320 // may throw UnsupportedOperationException
321 return unrestricted().remove(obj);
322 }
323 throw new UnsupportedOperationException();
324 }
325
326 // inherited from AbstractCollection:
327 // containsAll()
328
329 /**
330 * @throws UnsupportedOperationException
331 * if either {@link #unrestricted()} does not allow this operation
332 * or {@link CollectionsExt.Modification#RemoveObj RemoveObj}
333 * is no allowed operation
334 * according to {@link #allowedModifications()}.
335 * In the latter case it does not matter,
336 * whether effectively it is tried to clear <code>this</code>
337 * which is the case only if <code>this</code> is not empty already.
338 */
339 public final void clear() {
340 if (this.mods.contains(Modification.RemoveObj)) {
341 // may throw UnsupportedOperationException
342 unrestricted().clear();
343 }
344 throw new UnsupportedOperationException();
345 }
346
347
348 // Bulk Operations
349
350 // inherited from AbstractCollection:
351 // boolean containsAll(Collection<?> c)
352
353 /**
354 * @throws UnsupportedOperationException
355 * if either {@link #unrestricted()} does not allow this operation
356 * or {@link CollectionsExt.Modification#AddObj AddObj}
357 * is no allowed operation
358 * according to {@link #allowedModifications()}.
359 * In the latter case it does not matter,
360 * whether effectively it is tried to add objects
361 * which is the case only if <code>coll</code>
362 * is not a subcollection of <code>this</code>.
363 */
364 // **** if modifications do not distinguish between add and addAll,
365 // this method need not be implemented:
366 // Extending AbstractSet, this method is supported
367 // iff so is add(E)
368 public final boolean addAll(Collection<? extends E> coll) {
369 if (this.mods.contains(Modification.AddObj)) {
370 // may throw UnsupportedOperationException
371 return unrestricted().addAll(coll);
372 }
373 throw new UnsupportedOperationException();
374 }
375
376 /**
377 * @throws UnsupportedOperationException
378 * if either {@link #unrestricted()} does not allow this operation
379 * or {@link CollectionsExt.Modification#RemoveObj RemoveObj}
380 * is no allowed operation
381 * according to {@link #allowedModifications()}.
382 * In the latter case it does not matter,
383 * whether effectively it is tried to remove objects
384 * which is the case only if <code>this</code>
385 * is not a subcollection of <code>coll</code>.
386 */
387 // **** if modifications do not distinguish
388 // between remove and removeAll and retainAll,
389 // this method need not be implemented:
390 // Extending AbstractSet, this method is supported
391 // iff so is remove(E)
392 public final boolean retainAll(Collection<?> coll) {
393 if (this.mods.contains(Modification.RemoveObj)) {
394 // may throw UnsupportedOperationException
395 return unrestricted().retainAll(coll);
396 }
397 throw new UnsupportedOperationException();
398 }
399
400 /**
401 * @throws UnsupportedOperationException
402 * if either {@link #unrestricted()} does not allow this operation
403 * or {@link CollectionsExt.Modification#RemoveObj RemoveObj}
404 * is no allowed operation
405 * according to {@link #allowedModifications()}.
406 * In the latter case it does not matter,
407 * whether effectively it is tried to remove objects
408 * which is the case only if <code>this</code>
409 * and <code>coll</code> are not disjoint.
410 */
411 // **** see retainAll(...)
412 public final boolean removeAll(Collection<?> cmp) {
413 if (this.mods.contains(Modification.RemoveObj)) {
414 // may throw UnsupportedOperationException
415 return unrestricted().removeAll(cmp);
416 }
417 throw new UnsupportedOperationException();
418 }
419
420 /**
421 * @throws UnsupportedOperationException
422 * if either {@link #unrestricted()} does not allow this operation
423 * or {@link CollectionsExt.Modification#RemoveObj RemoveObj}
424 * is no allowed operation
425 * according to {@link #allowedModifications()}.
426 * In the latter case it does not matter,
427 * whether effectively it is tried to remove objects
428 * which is the case only if <code>filter</code>
429 * accepts an element of <code>this</code>.
430 */
431 public final boolean removeIf(Predicate<? super E> filter) {
432 if (this.mods.contains(Modification.RemoveObj)) {
433 // may throw UnsupportedOperationException
434 return unrestricted().removeIf(filter);
435 }
436 throw new UnsupportedOperationException();
437 }
438
439 /**
440 * Returns an iterator with method {@link Iterator#remove()}
441 * which throws an {@link UnsupportedOperationException}
442 * if either {@link #unrestricted()}'s iterator
443 * does not allow this operation
444 * or {@link CollectionsExt.Modification#RemoveObj RemoveObj}
445 * is no allowed operation
446 * according to {@link #allowedModifications()}.
447 */
448 public final Iterator<E> iterator() {
449 return new Iterator<E>() {
450 private Iterator<E> wrapped = AbstractImmutableCollection.this
451 .unrestricted().iterator();
452
453 public boolean hasNext() {
454 return this.wrapped.hasNext();
455 }
456
457 public E next() {
458 return this.wrapped.next();
459 }
460
461 public void forEachRemaining(Consumer<? super E> action) {
462 this.wrapped.forEachRemaining(action);
463 }
464
465 /**
466 * @throws UnsupportedOperationException
467 * if either this iterator does not allow remove
468 * or
469 *{@link CollectionsExt.Modification#RemoveObj RemoveObj}
470 * is no allowed operation
471 * according to {@link #allowedModifications()}.
472 */
473 public void remove() {
474 if (AbstractImmutableCollection.this.mods
475 .contains(Modification.RemoveObj)) {
476 // may throw UnsupportedOperationException
477 this.wrapped.remove();
478 }
479 throw new UnsupportedOperationException();
480 }
481 };
482 }
483
484 /**
485 * Returns a string representation of this set,
486 * including the allowed modifications
487 * and the wrapped set.
488 */
489 public final String toString() {
490 StringBuilder res = new StringBuilder();
491 res.append("<Immutable modifications=\"");
492 res.append(this.mods);
493 res.append("\">");
494 res.append(unrestricted().toString());
495 res.append("</Immutable>");
496 return res.toString();
497 }
498
499 // default void forEach(Consumer<? super T> action)
500 // is inherited from AbstractCollection
501
502 } // class AbstractImmutableCollection
503
504
505 /**
506 * A collection which prevents being modified
507 * by throwing an exception for the modifying methods.
508 *
509 * @param <E>
510 * the class of the elements of this collection.
511 */
512 public static final class ImmutableCollection<E>
513 extends AbstractImmutableCollection<Collection<E>, E>
514 implements Collection<E> {
515
516 /* ---------------------------------------------------------------- *
517 * fields. *
518 * ---------------------------------------------------------------- */
519
520 /**
521 * The enclosed set containing the elements of this set.
522 */
523 private final Collection<E> coll;
524
525 /* ---------------------------------------------------------------- *
526 * constructors. *
527 * ---------------------------------------------------------------- */
528
529 /**
530 * Creates a new empty <code>ImmutableCollection</code>
531 * which equals <code>coll</code> but cannot be modified
532 * neither directly nor via its iterator.
533 *
534 * @throws NullPointerException
535 * if <code>coll==null</code>.
536 */
537 ImmutableCollection(Collection<E> coll) {
538 if (coll == null) {
539 throw new NullPointerException(); // NOPMD
540 }
541 this.coll = coll;
542 }
543
544 /* ---------------------------------------------------------------- *
545 * methods. *
546 * ---------------------------------------------------------------- */
547
548 public Collection<E> unrestricted() {
549 return this.coll;
550 }
551
552 } // class ImmutableCollection<E>
553
554 /**
555 * A set which prevents being modified
556 * by throwing an exception for the modifying methods.
557 *
558 * @param <E>
559 * the class of the elements of this set.
560 */
561 public static final class ImmutableSet<E>
562 extends AbstractImmutableCollection<Set<E>, E>
563 implements Set<E> {
564
565 /* ---------------------------------------------------------------- *
566 * fields. *
567 * ---------------------------------------------------------------- */
568
569 /**
570 * The enclosed set containing the elements of this set.
571 */
572 private final Set<E> set;
573
574 /* ---------------------------------------------------------------- *
575 * constructors. *
576 * ---------------------------------------------------------------- */
577
578 ImmutableSet(Set<E> set) {
579 if (set == null) {
580 throw new NullPointerException(); // NOPMD
581 }
582 this.set = set;
583 }
584
585 ImmutableSet(Set<Modification> mods, Set<E> set) {
586 super(mods);
587 if (set == null) {
588 throw new NullPointerException(); // NOPMD
589 }
590 this.set = set;
591 }
592
593 /* ---------------------------------------------------------------- *
594 * methods. *
595 * ---------------------------------------------------------------- */
596
597 public Set<E> unrestricted() {
598 return this.set;
599 }
600
601 } // class ImmutableSet<E>
602
603 // **** modifications of views are allowed if allowed for original set.
604 // changes in allowances are reflected in views.
605 /**
606 * A sorted set which prevents being modified
607 * by throwing an exception for the modifying methods.
608 *
609 * @param <E>
610 * the class of the elements of this list.
611 */
612 public static final class ImmutableSortedSet<E>
613 extends AbstractImmutableCollection<SortedSet<E>, E>
614 implements SortedSet<E> {
615
616 /* ---------------------------------------------------------------- *
617 * fields. *
618 * ---------------------------------------------------------------- */
619
620 /**
621 * The enclosed sorted set containing the elements of this sorted set.
622 */
623 private final SortedSet<E> set;
624
625 /* ---------------------------------------------------------------- *
626 * constructors. *
627 * ---------------------------------------------------------------- */
628
629 ImmutableSortedSet(SortedSet<E> set) {
630 if (set == null) {
631 throw new NullPointerException(); // NOPMD
632 }
633 this.set = set;
634 }
635
636 ImmutableSortedSet(Set<Modification> mods, SortedSet<E> set) {
637 super(mods);
638 if (set == null) {
639 throw new NullPointerException(); // NOPMD
640 }
641 this.set = set;
642 }
643
644 /* ---------------------------------------------------------------- *
645 * methods. *
646 * ---------------------------------------------------------------- */
647
648 public SortedSet<E> unrestricted() {
649 return this.set;
650 }
651
652 public Comparator<? super E> comparator() {
653 return unrestricted().comparator();
654 }
655
656 public E first() {
657 return unrestricted().first();
658 }
659
660 public E last() {
661 return unrestricted().last();
662 }
663
664 /**
665 * Returns a view of the portion of this set
666 * whose elements are strictly less than <code>toElement</code>.
667 * For information on backing see {@link #subSet(Object, Object)}.
668 */
669 public SortedSet<E> headSet(E toElement) {
670 SortedSet<E> res0 = unrestricted().headSet(toElement);
671 return new ImmutableSortedSet<E>(allowedModifications(), res0);
672 }
673
674 /**
675 * Returns a view of the portion of this set
676 * whose elements range from <code>fromElement</code>,
677 * inclusive, to <code>toElement</code>, exclusive.
678 * (If fromElement and toElement are equal, the returned set is empty.)
679 * The returned set is backed by this set,
680 * so changes in the returned set are reflected in this set,
681 * and vice-versa.
682 * The returned set supports all optional set operations
683 * that this set supports.
684 * In particular, changes of the allowed modifications
685 * (returned by {@link #allowedModifications()})
686 * of the returned set are reflected in this set, and vice-versa.
687 */
688 public SortedSet<E> subSet(E fromElement, E toElement) {
689 SortedSet<E> res0 = unrestricted().subSet(fromElement, toElement);
690 return new ImmutableSortedSet<E>(allowedModifications(), res0);
691 }
692
693 /**
694 * Returns a view of the portion of this set
695 * whose elements are greater than or equal to <code>fromElement</code>.
696 * For information on backing see {@link #subSet(Object, Object)}.
697 */
698 public SortedSet<E> tailSet(E fromElement) {
699 SortedSet<E> res0 = unrestricted().tailSet(fromElement);
700 return new ImmutableSortedSet<E>(allowedModifications(), res0);
701 }
702 } // class ImmutableSortedSet<E>
703
704 /**
705 * A list which prevents being modified
706 * by throwing an exception for the modifying methods.
707 *
708 * @param <E>
709 * the class of the elements of this list.
710 */
711 public static final class ImmutableList<E>
712 extends AbstractImmutableCollection<List<E>, E>
713 implements List<E> {
714
715 /* ---------------------------------------------------------------- *
716 * fields. *
717 * ---------------------------------------------------------------- */
718
719 /**
720 * The enclosed list containing the elements of this list.
721 */
722 private final List<E> list;
723
724 /* ---------------------------------------------------------------- *
725 * constructors. *
726 * ---------------------------------------------------------------- */
727
728 ImmutableList(List<E> list) {
729 if (list == null) {
730 throw new NullPointerException(); // NOPMD
731 }
732 this.list = list;
733 }
734
735 ImmutableList(Set<Modification> mods, List<E> list) {
736 super(mods);
737 if (list == null) {
738 throw new NullPointerException(); // NOPMD
739 }
740 this.list = list;
741 }
742
743 /* ---------------------------------------------------------------- *
744 * methods. *
745 * ---------------------------------------------------------------- */
746
747 public List<E> unrestricted() {
748 return this.list;
749 }
750
751 /**
752 * @throws UnsupportedOperationException
753 * if either {@link #unrestricted()} does not allow this operation
754 * or {@link CollectionsExt.Modification#AddObj AddObj}
755 * is no allowed operation
756 * according to {@link #allowedModifications()}.
757 */
758 public void add(int index, E obj) {
759 if (!allowedModifications().contains(Modification.AddObj)) {
760 throw new UnsupportedOperationException();
761 }
762 // may throw UnsupportedOperationException
763 unrestricted().add(index, obj);
764 }
765
766 /**
767 * @throws UnsupportedOperationException
768 * if either {@link #unrestricted()} does not allow this operation
769 * or {@link CollectionsExt.Modification#AddObj AddObj}
770 * is no allowed operation
771 * according to {@link #allowedModifications()}.
772 * In the latter case it does not matter,
773 * whether effectively it is tried to add objects
774 * which is the case only <code>coll</code> is not empty.
775 */
776 public boolean addAll(int index, Collection<? extends E> coll) {
777 if (allowedModifications().contains(Modification.AddObj)) {
778 // may throw UnsupportedOperationException
779 return unrestricted().addAll(index, coll);
780 }
781 throw new UnsupportedOperationException();
782 }
783
784 public E get(int index) {
785 return unrestricted().get(index);
786 }
787
788 // must be implemented because contract differs from that of Collection
789 public int hashCode() {
790 return unrestricted().hashCode();
791 }
792
793 // must be implemented because hashCode() changed also
794 public boolean equals(Object obj) {
795 return unrestricted().equals(obj);
796 }
797
798 public int indexOf(Object obj) {
799 return unrestricted().indexOf(obj);
800 }
801
802 public int lastIndexOf(Object obj) {
803 return unrestricted().lastIndexOf(obj);
804 }
805
806 public ListIterator<E> listIterator() {
807 return listIterator(0);
808 }
809
810 public ListIterator<E> listIterator(int index) {
811 return new ListIterator<E>() {
812
813 private ListIterator<E> wrapped = ImmutableList.this
814 .unrestricted().listIterator();
815
816 public boolean hasNext() {
817 return this.wrapped.hasNext();
818 }
819 public E next() {
820 return this.wrapped.next();
821 }
822 public int nextIndex() {
823 return this.wrapped.nextIndex();
824 }
825 public boolean hasPrevious() {
826 return this.wrapped.hasPrevious();
827 }
828 public E previous() {
829 return this.wrapped.previous();
830 }
831 public int previousIndex() {
832 return this.wrapped.previousIndex();
833 }
834
835 public void forEachRemaining(Consumer<? super E> action) {
836 this.wrapped.forEachRemaining(action);
837 }
838
839 /**
840 * @throws UnsupportedOperationException
841 * if either this iterator does not allow remove or
842 * {@link CollectionsExt.Modification#RemoveObj RemoveObj}
843 * is no allowed operation
844 * according to {@link #allowedModifications()}.
845 */
846 public void remove() {
847 if (ImmutableList.this.allowedModifications()
848 .contains(Modification.RemoveObj)) {
849 // may throw UnsupportedOperationException
850 this.wrapped.remove();
851 }
852 throw new UnsupportedOperationException();
853 }
854
855 /**
856 * @throws UnsupportedOperationException
857 * if either this iterator does not allow remove
858 * or {@link CollectionsExt.Modification#AddObj AddObj}
859 * is no allowed operation
860 * according to {@link #allowedModifications()}.
861 */
862 public void add(E element) {
863 if (ImmutableList.this.allowedModifications()
864 .contains(Modification.AddObj)) {
865 // may throw UnsupportedOperationException
866 this.wrapped.add(element);
867 }
868 throw new UnsupportedOperationException();
869 }
870
871 /**
872 * @throws UnsupportedOperationException
873 * if either this iterator does not allow remove
874 * or {@link CollectionsExt.Modification#SetObj SetObj}
875 * is no allowed operation
876 * according to {@link #allowedModifications()}.
877 * In the latter case it does not matter,
878 * whether effectively it is tried to set an object
879 * which is the case only if <code>element</code>
880 * is not yet on the place this iterator points to.
881 */
882 public void set(E element) {
883 if (ImmutableList.this.allowedModifications()
884 .contains(Modification.SetObj)) {
885 // may throw UnsupportedOperationException
886 this.wrapped.add(element);
887 }
888 throw new UnsupportedOperationException();
889 }
890 };
891 } // listIterator
892
893 /**
894 * @throws UnsupportedOperationException
895 * if either {@link #unrestricted()} does not allow this operation
896 * or {@link CollectionsExt.Modification#RemoveObj RemoveObj}
897 * is no allowed operation
898 * according to {@link #allowedModifications()}.
899 */
900 public E remove(int index) {
901 if (allowedModifications().contains(Modification.RemoveObj)) {
902 // may throw UnsupportedOperationException
903 return unrestricted().remove(index);
904 }
905 throw new UnsupportedOperationException();
906 }
907
908 /**
909 * @throws UnsupportedOperationException
910 * if either {@link #unrestricted()} does not allow this operation
911 * or {@link CollectionsExt.Modification#SetObj SetObj}
912 * is no allowed operation
913 * according to {@link #allowedModifications()}.
914 * In the latter case it does not matter,
915 * whether effectively it is tried to set an object
916 * which is the case only if <code>element</code>
917 * is not at place <code>index</code> in <code>this</code>.
918 */
919 public E set(int index, E element) {
920 if (allowedModifications().contains(Modification.SetObj)) {
921 // may throw UnsupportedOperationException
922 return unrestricted().set(index, element);
923 }
924 throw new UnsupportedOperationException();
925 }
926
927 /**
928 * @throws UnsupportedOperationException
929 * if either {@link #unrestricted()} does not allow this operation
930 * or {@link CollectionsExt.Modification#SetObj SetObj}
931 * is no allowed operation
932 * according to {@link #allowedModifications()}.
933 * In the latter case it does not matter,
934 * whether effectively it is tried to replace an object
935 * which is the case only if <code>operator</code>
936 * really changes an object.
937 */
938 public void replaceAll(UnaryOperator<E> operator) {
939 if (!allowedModifications().contains(Modification.SetObj)) {
940 throw new UnsupportedOperationException();
941 }
942 // may throw UnsupportedOperationException
943 unrestricted().replaceAll(operator);
944 }
945
946 /**
947 * @throws UnsupportedOperationException
948 * if either {@link #unrestricted()} does not allow this operation
949 * or {@link CollectionsExt.Modification#SetObj SetObj}
950 * is no allowed operation
951 * according to {@link #allowedModifications()}.
952 * In the latter case it does not matter,
953 * whether effectively it is tried to replace an object
954 * which is the case only if <code>this</code>
955 * is not completely sorted according to <code>cmp</code>.
956 * This definition is in conjunction with the requirement,
957 * of {@link List#sort(Comparator)}
958 * that this exception is thrown iff the list iterator
959 * does not permit the {@link ListIterator#set(Object)} method.
960 */
961 public void sort(Comparator<? super E> cmp) {
962 if (!allowedModifications().contains(Modification.SetObj)) {
963 throw new UnsupportedOperationException();
964 }
965 // may throw UnsupportedOperationException
966 unrestricted().sort(cmp);
967 }
968
969 public List<E> subList(int fromIndex, int toIndex) {
970 List<E> res0 = unrestricted().subList(fromIndex, toIndex);
971 return new ImmutableList<E>(allowedModifications(), res0);
972 }
973
974 } // class ImmutableList
975
976 /**
977 * An interator which prevents modification on the underlying list,
978 * by throwing an exception for the modifying methods.
979 * This is used in conjunction
980 * with {@link CollectionsExt.ImmutableCyclicList}.
981 *
982 * @param <E>
983 * the class of the elements to iterate over.
984 */
985 public static final class NonModifyingCyclicIterator<E>
986 implements CyclicIterator<E> {
987
988 private final CyclicIterator<E> wrapped;
989
990 NonModifyingCyclicIterator(CyclicIterator<E> wrapped) {
991 this.wrapped = wrapped;
992 }
993
994 public int getFirstIndex() {
995 return this.wrapped.getFirstIndex();
996 }
997 public int getIndex() {
998 return this.wrapped.getIndex();
999 }
1000 public CyclicList<E> getCyclicList() {
1001 return this.wrapped.getCyclicList();
1002 }
1003 public boolean hasNext() {
1004 return this.wrapped.hasNext();
1005 }
1006 public E next() {
1007 return this.wrapped.next();
1008 }
1009
1010 public boolean hasPrev() {
1011 return this.wrapped.hasPrev();
1012 }
1013
1014 public E previous() {
1015 return this.wrapped.previous();
1016 }
1017
1018 public int getNextIndexOf(E obj) {
1019 return this.wrapped.getNextIndexOf(obj);
1020 }
1021
1022 public void setIndex(int index) {
1023 this.wrapped.setIndex(index);
1024 }
1025
1026 public void add(E obj) {
1027 throw new UnsupportedOperationException();
1028 }
1029
1030 public void addAll(List<? extends E> list) {
1031 throw new UnsupportedOperationException();
1032 }
1033
1034 public void set(E obj) {
1035 throw new UnsupportedOperationException();
1036 }
1037 public void remove() {
1038 throw new UnsupportedOperationException();
1039 }
1040
1041 public void refresh() {
1042 throw new UnsupportedOperationException();
1043 }
1044
1045 public boolean retEquals(CyclicIterator<?> other) {
1046 throw new NotYetImplementedException();
1047 }
1048
1049 @edu.umd.cs.findbugs.annotations.SuppressWarnings
1050 (value = "EQ_UNUSUAL",
1051 justification = "special kind of exception")
1052 public boolean equals(Object other) {
1053 throw new NotYetImplementedException();
1054 }
1055 public int hashCode() {
1056 throw new NotYetImplementedException();
1057 }
1058 public double dist(CyclicIterator<E> other) {
1059 throw new NotYetImplementedException();
1060 }
1061
1062 } // NonModifyingCyclicIterator
1063
1064 /**
1065 * Represents an immutable cyclic list
1066 * by throwing an exception
1067 * when invoking a method which modifies this list.
1068 *
1069 * @param <E>
1070 * the class of the elements of this list.
1071 */
1072 public static final class ImmutableCyclicList<E> implements CyclicList<E> {
1073
1074 private final CyclicList<E> wrapped;
1075
1076 ImmutableCyclicList(CyclicList<E> wrapped) {
1077 this.wrapped = wrapped;
1078 }
1079
1080 // ***** to be removed later.
1081 public int shiftIndex(int index) {
1082 throw new NotYetImplementedException();
1083 }
1084 public int size() {
1085 return this.wrapped.size();
1086 }
1087
1088 // based on size()
1089 public boolean isEmpty() {
1090 return this.wrapped.isEmpty();
1091 }
1092
1093 public CyclicList<E> getInverse() {
1094 throw new NotYetImplementedException();
1095 }
1096
1097 // based on getIndexOf(...)
1098 public boolean contains(Object obj) {
1099 return this.wrapped.contains(obj);
1100 }
1101
1102 // based on contains(Object)
1103 public boolean containsAll(Collection<?> coll) {
1104 throw new NotYetImplementedException();
1105 }
1106
1107 public Iterator<E> iterator() {
1108 throw new NotYetImplementedException();
1109 }
1110
1111 // public Iterator<E> iterator(int index) {
1112 // throw new NotYetImplementedException();
1113 // }
1114
1115 public CyclicIterator<E> cyclicIterator(int index) {
1116 CyclicIterator<E> tbWrapped = this.wrapped.cyclicIterator(index);
1117 return new NonModifyingCyclicIterator<E>(tbWrapped);
1118 }
1119
1120 public Object[] toArray(int index) {
1121 throw new NotYetImplementedException();
1122 }
1123 public <E> E[] toArray(int index, E[] array) {
1124 throw new NotYetImplementedException();
1125 }
1126 public Object[] toArray() {
1127 throw new NotYetImplementedException();
1128 }
1129 public <E> E[] toArray(E[] ret) {
1130 throw new NotYetImplementedException();
1131 }
1132 public List<E> asList(int index) {
1133 throw new NotYetImplementedException();
1134 }
1135 public List<E> asList() {
1136 return Collections.unmodifiableList(this.wrapped.asList());
1137 }
1138 public CyclicList<E> cycle(int num) {
1139 throw new NotYetImplementedException();
1140 }
1141
1142 public void clear() {
1143 throw new UnsupportedOperationException();
1144 }
1145
1146 public boolean equals(Object obj) {
1147 return this.wrapped.equals(obj);
1148 }
1149 public boolean equalsCyclic(Object obj) {
1150 return this.wrapped.equalsCyclic(obj);
1151 }
1152 public int hashCode() {
1153 return this.wrapped.hashCode();
1154 }
1155 public int hashCodeCyclic() {
1156 return this.wrapped.hashCodeCyclic();
1157 }
1158 public E get(int index) {
1159 return this.wrapped.get(index);
1160 }
1161 public E set(int index, E element) {
1162 throw new UnsupportedOperationException();
1163 }
1164 public void replace(int index, Iterator<E> iter) {
1165 throw new UnsupportedOperationException();
1166 }
1167 public void replace(int index, List<E> list) {
1168 throw new UnsupportedOperationException();
1169 }
1170 public boolean add(E element) {
1171 throw new UnsupportedOperationException();
1172 }
1173 public void add(int index, E element) {
1174 throw new UnsupportedOperationException();
1175 }
1176 public void addAll(int index, Iterator<E> iter) {
1177 throw new UnsupportedOperationException();
1178 }
1179 public void addAll(int index, List<? extends E> list) {
1180 throw new UnsupportedOperationException();
1181 }
1182 public boolean addAll(Collection<? extends E> coll) {
1183 throw new UnsupportedOperationException(); // for cyclic lists
1184 }
1185 public E remove(int index) throws EmptyCyclicListException {
1186 throw new UnsupportedOperationException();
1187 }
1188 public boolean remove(Object obj) {
1189 throw new UnsupportedOperationException();
1190 }
1191 public boolean removeAll(Collection<?> coll) {
1192 throw new UnsupportedOperationException();
1193 }
1194 public boolean retainAll(Collection<?> coll) {
1195 throw new UnsupportedOperationException();
1196 }
1197 public int getIndexOf(int idx, Object obj) {
1198 throw new NotYetImplementedException();
1199 }
1200 public CyclicList<E> getCopy(int len) {
1201 throw new NotYetImplementedException();
1202 }
1203
1204 } // class ImmutableCyclicList
1205
1206 /**
1207 * An immutable implementation of the multiplicity interface.
1208 */
1209 private static class ImmutableMultiplicity
1210 implements MultiSet.Multiplicity {
1211
1212 private final MultiSet.Multiplicity wrapped;
1213 private final Set<Modification> mod;
1214
1215 ImmutableMultiplicity(MultiSet.Multiplicity wrapped,
1216 Set<Modification> mod) {
1217 this.wrapped = wrapped;
1218 this.mod = mod;
1219 }
1220
1221 private Set<Modification> allowedModifications() {
1222 return this.mod;
1223 }
1224
1225 public int set(int mult) {
1226 int multOrg = this.wrapped.get();
1227
1228 // **** may cause problems with over/underflow
1229 switch ((int) Math.signum(mult - multOrg)) {
1230 case -1:
1231 assert mult < multOrg;
1232 if (allowedModifications()
1233 .contains(Modification.RemoveObj)) {
1234 // may throw UnsupportedOperationException
1235 return this.wrapped.set(mult);
1236 }
1237 break;
1238 case +1:
1239 assert mult > multOrg;
1240 if (allowedModifications()
1241 .contains(Modification.AddObj)) {
1242 // may throw UnsupportedOperationException
1243 return this.wrapped.set(mult);
1244 }
1245 break;
1246 case 0:
1247 assert mult == multOrg;
1248 // this does not modify the multiplicity
1249 // but just returns the current value.
1250 // could also return multOrg
1251 return this.wrapped.set(mult);
1252 default:
1253 throw new IllegalStateException("****");
1254 }
1255 throw new UnsupportedOperationException();
1256 }
1257
1258 public int add(int mult) {
1259 switch ((int) Math.signum(mult)) {
1260 case -1:
1261 assert mult < 0;
1262 if (allowedModifications()
1263 .contains(Modification.RemoveObj)) {
1264 // may throw UnsupportedOperationException
1265 return this.wrapped.add(mult);
1266 }
1267 break;
1268 case +1:
1269 assert mult > 0;
1270 if (allowedModifications()
1271 .contains(Modification.AddObj)) {
1272 // may throw UnsupportedOperationException
1273 return this.wrapped.add(mult);
1274 }
1275 break;
1276 case 0:
1277 assert mult == 0;
1278 // this does not modify the multiplicity
1279 // but just returns the current value.
1280 return this.wrapped.add(mult);
1281 default:
1282 throw new IllegalStateException("****");
1283 }
1284 throw new UnsupportedOperationException();
1285 }
1286
1287 public int get() {
1288 return this.wrapped.get();
1289 }
1290
1291 public int compareTo(MultiSet.Multiplicity mult) {
1292 return this.wrapped.compareTo(mult);
1293 }
1294
1295 /**
1296 * Returns <code>true</code> if and only if
1297 * <code>obj</code> is also an instance of <code>Multiplicity</code>
1298 * and if the wrapped multiplicities coincide.
1299 *
1300 * @param obj
1301 * an <code>Object</code> value
1302 * which may well be <code>null</code>.
1303 * @return
1304 * a <code>boolean</code> value which indicates
1305 * whether <code>obj</code> is also an instance
1306 * of <code>Multiplicity</code>
1307 * and whether the wrapped multiplicity coincides with this one.
1308 * @see #compareTo
1309 */
1310 public boolean equals(Object obj) {
1311 return this.wrapped.equals(obj);
1312 }
1313
1314 // api-docs provided by javadoc.
1315 public int hashCode() {
1316 return this.wrapped.hashCode();
1317 }
1318
1319
1320 } // class ImmutableMultiplicity
1321
1322 /**
1323 * A MultiSet which prevents being modified
1324 * by throwing an exception for the modifying methods.
1325 *
1326 * @param <C>
1327 * the class extending {@link MultiSet} with elements in E.
1328 * @param <E>
1329 * the class of the elements of this collection.
1330 */
1331 abstract static class AbstractImmutableMultiSet<C extends MultiSet<E>, E>
1332 implements MultiSet<E> {
1333
1334 private static final long serialVersionUID = -2479143000061671589L;
1335
1336 /* ---------------------------------------------------------------- *
1337 * fields. *
1338 * ---------------------------------------------------------------- */
1339
1340 // ***** same as for AbstractImmutableCollection
1341 /**
1342 * The set of allowed modifications.
1343 */
1344 private final Set<Modification> mods;
1345
1346 /* ---------------------------------------------------------------- *
1347 * constructors. *
1348 * ---------------------------------------------------------------- */
1349
1350 // ***** same as for AbstractCollection
1351 private AbstractImmutableMultiSet() {
1352 this(EnumSet.noneOf(Modification.class));
1353 }
1354
1355 // ***** same as for AbstractCollection
1356 AbstractImmutableMultiSet(Set<Modification> mods) {
1357 this.mods = mods;
1358 }
1359
1360 /* ---------------------------------------------------------------- *
1361 * methods. *
1362 * ---------------------------------------------------------------- */
1363
1364 public final Set<Modification> allowedModifications() {
1365 return this.mods;
1366 }
1367
1368 /**
1369 * Returns the underlying multiset without the restrictions
1370 * imposed by this {@link CollectionsExt.ImmutableCollection}.
1371 * Note that the result
1372 * may still throw {@link UnsupportedOperationException}s
1373 * depending on the implementation.
1374 */
1375 public abstract C unrestricted();
1376
1377 // query methods
1378
1379 public int size() {
1380 return unrestricted().size();
1381 }
1382
1383 public int sizeWithMult() {
1384 return unrestricted().sizeWithMult();
1385 }
1386
1387 public boolean isEmpty() {
1388 return unrestricted().isEmpty();
1389 }
1390
1391 public Object getObjWithMaxMult() {
1392 return unrestricted().getObjWithMaxMult();
1393 }
1394
1395 public int getMaxMult() {
1396 return unrestricted().getMaxMult();
1397 }
1398
1399 public int getMultiplicity(Object obj) {
1400 return unrestricted().getMultiplicity(obj);
1401 }
1402
1403 public boolean contains(Object obj) {
1404 return unrestricted().contains(obj);
1405 }
1406
1407 public Object[] toArray() {
1408 return unrestricted().toArray();
1409 }
1410
1411 public E[] toArray(E[] arr) {
1412 return unrestricted().toArray(arr);
1413 }
1414
1415 // What follows are query methods the return value of which
1416 // is required to prevent modifications.
1417
1418 public Multiplicity getMultiplicityObj(Object obj) {
1419 Multiplicity res0 = this.unrestricted().getMultiplicityObj(obj);
1420 return new ImmutableMultiplicity(res0, this.allowedModifications());
1421 }
1422
1423 public MultiSetIterator<E> iterator() {
1424 return new MultiSetIterator<E>() {
1425 private MultiSetIterator<E> wrapped =
1426 AbstractImmutableMultiSet.this.unrestricted().iterator();
1427
1428 public boolean hasNext() {
1429 return this.wrapped.hasNext();
1430 }
1431
1432 public E next() {
1433 return this.wrapped.next();
1434 }
1435
1436 public void forEachRemaining(Consumer<? super E> action) {
1437 this.wrapped.forEachRemaining(action);
1438 }
1439
1440 public void remove() {
1441 if (AbstractImmutableMultiSet.this.mods
1442 .contains(Modification.RemoveObj)) {
1443 // may throw UnsupportedOperationException
1444 this.wrapped.remove();
1445 }
1446 throw new UnsupportedOperationException();
1447 }
1448
1449 public int getMult() {
1450 return this.wrapped.getMult();
1451 }
1452
1453 public MultiSet.Multiplicity getMultObj() {
1454 return this.wrapped.getMultObj();
1455 }
1456
1457 // this is always the same as for mutable multi-sets.
1458 // I think, one has to decide:
1459 // There is a single method exposing Multiplicities:
1460 // MultiSet.getMultiplicityObj(Object).
1461 // If this is ok, then we may replace in MultiSetIterator
1462 // setMult and removeMult by getMultObj.set()
1463 // and getMultObj.remove(int)
1464 //
1465 // If we agree that Multiplicities are not public,
1466 // then we must turn
1467 // MultiSet.getMultiplicityObj(Object) protected
1468 // but we must define iterator with method
1469 // protected getMultObj and implement
1470 // setMult and removeMult in terms of getMultObj.
1471 // Moreover we need a method iteratorInternal
1472 // which exposes getMultObj to the immutable iterator
1473 // and make sure that setMult and removeMult
1474 // are implemented as in base class.
1475
1476 // Here getMultObj() returns an immutable Multiplicity
1477 public int setMult(int mult) {
1478 // **** copy from MultiSetIteratorImpl
1479 // can be avoided using default final in interface
1480 // may throw IllegalStateException
1481 Multiplicity last = getMultObj();
1482 assert last != null;
1483 if (mult == 0) {
1484 int res = last.get();
1485 // may throw UnsupportedOperationException
1486 remove();
1487 return res;
1488 }
1489 // may throw IllegalArgumentException
1490 // may throw UnsupportedOperationException
1491 return last.set(mult);
1492 //throw new NotYetImplementedException();
1493 }
1494
1495 // Here getMultObj() returns an immutable Multiplicity
1496 public int removeMult(int mult) {
1497 // **** copy from MultiSetIteratorImpl
1498 // may throw IllegalStateException
1499 Multiplicity last = getMultObj();
1500 assert last != null;
1501 // return value is old multiplicity
1502 int oldMult = last.get();
1503 if (mult == oldMult) {
1504 remove();
1505 return oldMult;
1506 }
1507
1508 // may throw an IllegalArgumentException
1509 // may throw UnsupportedOperationException
1510 last.add(-mult);
1511 return oldMult;
1512 }
1513 };
1514 }
1515
1516 public int addWithMult(E obj) {
1517 if (this.mods.contains(Modification.AddObj)) {
1518 // may throw UnsupportedOperationException
1519 return unrestricted().addWithMult(obj);
1520 }
1521 throw new UnsupportedOperationException();
1522 }
1523
1524 public int addWithMult(E obj, int addMult) {
1525 if (this.mods.contains(Modification.AddObj)) {
1526 // may throw UnsupportedOperationException
1527 return unrestricted().addWithMult(obj, addMult);
1528 }
1529 throw new UnsupportedOperationException();
1530 }
1531
1532 public boolean add(E obj) {
1533 if (this.mods.contains(Modification.AddObj)) {
1534 // may throw UnsupportedOperationException
1535 return unrestricted().add(obj);
1536 }
1537 throw new UnsupportedOperationException();
1538 }
1539
1540 public int removeWithMult(Object obj) {
1541 if (this.mods.contains(Modification.RemoveObj)) {
1542 // may throw UnsupportedOperationException
1543 return unrestricted().removeWithMult(obj);
1544 }
1545 throw new UnsupportedOperationException();
1546 }
1547
1548 public int removeWithMult(Object obj, int removeMult) {
1549 if (this.mods.contains(Modification.RemoveObj)) {
1550 // may throw UnsupportedOperationException
1551 return unrestricted().removeWithMult(obj, removeMult);
1552 }
1553 throw new UnsupportedOperationException();
1554 }
1555
1556 public boolean remove(Object obj) {
1557 if (this.mods.contains(Modification.RemoveObj)) {
1558 // may throw UnsupportedOperationException
1559 return unrestricted().remove(obj);
1560 }
1561 throw new UnsupportedOperationException();
1562 }
1563
1564 public int setMultiplicity(E obj, int newMult) {
1565 throw new NotYetImplementedException();
1566 }
1567
1568 public boolean containsAll(Collection<?> coll) {
1569 return unrestricted().containsAll(coll);
1570 }
1571
1572 public boolean addAll(MultiSet<? extends E> mvs) {
1573 if (this.mods.contains(Modification.AddObj)) {
1574 // may throw UnsupportedOperationException
1575 return unrestricted().addAll(mvs);
1576 }
1577 throw new UnsupportedOperationException();
1578 }
1579
1580 public boolean addAll(Set<? extends E> set) {
1581 if (this.mods.contains(Modification.AddObj)) {
1582 // may throw UnsupportedOperationException
1583 return unrestricted().addAll(set);
1584 }
1585 throw new UnsupportedOperationException();
1586 }
1587
1588 public boolean removeAll(Collection<?> coll) {
1589 if (this.mods.contains(Modification.RemoveObj)) {
1590 // may throw UnsupportedOperationException
1591 return unrestricted().removeAll(coll);
1592 }
1593 throw new UnsupportedOperationException();
1594 }
1595
1596 public boolean retainAll(Collection<?> coll) {
1597 if (this.mods.contains(Modification.RemoveObj)) {
1598 // may throw UnsupportedOperationException
1599 return unrestricted().retainAll(coll);
1600 }
1601 throw new UnsupportedOperationException();
1602 }
1603
1604 public void clear() {
1605 if (!this.mods.contains(Modification.RemoveObj)) {
1606 throw new UnsupportedOperationException();
1607 }
1608 // may throw UnsupportedOperationException
1609 unrestricted().clear();
1610 }
1611
1612 public Set<E> getSet() {
1613 return new ImmutableSet<E>(allowedModifications(),
1614 unrestricted().getSet());
1615 }
1616
1617 public Map<E, Multiplicity> getMap() {
1618 throw new NotYetImplementedException();
1619 }
1620
1621 public Set<Map.Entry<E, Multiplicity>> getSetWithMults() {
1622 return new ImmutableSet<Map.Entry<E, Multiplicity>>
1623 (allowedModifications(), unrestricted().getSetWithMults());
1624 }
1625
1626 // **** as in AbstractImmutableCollection
1627 public String toString() {
1628 StringBuilder res = new StringBuilder();
1629 res.append("<Immutable modifications=\">");
1630 res.append(this.mods);
1631 res.append("\">");
1632 res.append(unrestricted().toString());
1633 res.append("</Immutable>");
1634 return res.toString();
1635 }
1636
1637 public boolean equals(Object obj) {
1638 return unrestricted().equals(obj);
1639 }
1640
1641 public int hashCode() {
1642 return unrestricted().hashCode();
1643 }
1644
1645 } // class AbstractImmutableMultiSet
1646
1647 /**
1648 * A multi-set which prevents being modified
1649 * by throwing an exception for the modifying methods.
1650 *
1651 * @param <E>
1652 * the class of the elements of this list.
1653 */
1654 static class ImmutableMultiSet<E>
1655 extends AbstractImmutableMultiSet<MultiSet<E>, E>
1656 implements MultiSet<E> {
1657
1658 /* ---------------------------------------------------------------- *
1659 * fields. *
1660 * ---------------------------------------------------------------- */
1661
1662 /**
1663 * The enclosed multi-set containing the elements of this multi-set.
1664 */
1665 private final MultiSet<E> mSet;
1666
1667 /* ---------------------------------------------------------------- *
1668 * constructors. *
1669 * ---------------------------------------------------------------- */
1670
1671 /**
1672 * Creates a new empty <code>ImmutableMultiSet</code>
1673 * which equals <code>mSet</code> but cannot be modified
1674 * neither directly nor via its iterator.
1675 *y
1676 * @throws NullPointerException
1677 * if <code>coll==null</code>.
1678 */
1679 ImmutableMultiSet(MultiSet<E> mSet) {
1680 if (mSet == null) {
1681 throw new NullPointerException(); // NOPMD
1682 }
1683 this.mSet = mSet;
1684 }
1685
1686 /* ---------------------------------------------------------------- *
1687 * methods. *
1688 * ---------------------------------------------------------------- */
1689
1690 public MultiSet<E> unrestricted() {
1691 return this.mSet;
1692 }
1693 } // class ImmutableMultiSet
1694
1695 /**
1696 * A sorted multi-set which prevents being modified
1697 * by throwing an exception for the modifying methods.
1698 *
1699 * @param <E>
1700 * the class of the elements of this list.
1701 */
1702 static class ImmutableSortedMultiSet<E>
1703 extends AbstractImmutableMultiSet<SortedMultiSet<E>, E>
1704 implements SortedMultiSet<E> {
1705
1706 /* ---------------------------------------------------------------- *
1707 * fields. *
1708 * ---------------------------------------------------------------- */
1709
1710 private final SortedMultiSet<E> mSet;
1711
1712 /* ---------------------------------------------------------------- *
1713 * constructors. *
1714 * ---------------------------------------------------------------- */
1715
1716 /**
1717 * Creates a new empty <code>ImmutableSortedMultiSet</code>
1718 * which equals <code>mSet</code> but cannot be modified
1719 * neither directly nor via its iterator.
1720 *y
1721 * @throws NullPointerException
1722 * if <code>coll==null</code>.
1723 */
1724 ImmutableSortedMultiSet(SortedMultiSet<E> mSet) {
1725 if (mSet == null) {
1726 throw new NullPointerException(); // NOPMD
1727 }
1728 this.mSet = mSet;
1729 }
1730
1731 ImmutableSortedMultiSet(Set<Modification> mods,
1732 SortedMultiSet<E> mSet) {
1733 super(mods);
1734 if (mSet == null) {
1735 throw new NullPointerException(); // NOPMD
1736 }
1737 this.mSet = mSet;
1738 }
1739
1740 /* ---------------------------------------------------------------- *
1741 * methods. *
1742 * ---------------------------------------------------------------- */
1743
1744 // ****
1745 public SortedMultiSet<E> unrestricted() {
1746 return this.mSet;
1747 }
1748
1749 public SortedSet<E> getSet() {
1750 return new ImmutableSortedSet<E>(allowedModifications(),
1751 unrestricted().getSet());
1752 }
1753
1754 public NavigableMap<E, Multiplicity> getMap() {
1755 //return Collections
1756 //.unmodifiableNavigableMap(unrestricted().getMap())
1757 throw new NotYetImplementedException();
1758 // return new ImmutableNavigableMap(unrestricted().getMap());
1759 }
1760
1761 public Comparator<? super E> comparator() {
1762 return unrestricted().comparator();
1763 }
1764
1765 public E first() {
1766 return unrestricted().first();
1767 }
1768
1769 public E last() {
1770 return unrestricted().last();
1771 }
1772
1773 public SortedMultiSet<E> headSet(E toElement) {
1774 SortedMultiSet<E> res0 = unrestricted()
1775 .headSet(toElement);
1776 return new ImmutableSortedMultiSet<E>(allowedModifications(), res0);
1777 }
1778
1779 public SortedMultiSet<E> tailSet(E fromElement) {
1780 SortedMultiSet<E> res0 = unrestricted()
1781 .tailSet(fromElement);
1782 return new ImmutableSortedMultiSet<E>(allowedModifications(), res0);
1783 }
1784
1785 public SortedMultiSet<E> subSet(E fromElement, E toElement) {
1786 SortedMultiSet<E> res0 = unrestricted()
1787 .subSet(fromElement, toElement);
1788 return new ImmutableSortedMultiSet<E>(allowedModifications(), res0);
1789 }
1790
1791 } // class ImmutableSortedMultiSet
1792
1793
1794 /* -------------------------------------------------------------------- *
1795 * class fields. *
1796 * -------------------------------------------------------------------- */
1797
1798
1799
1800 /* -------------------------------------------------------------------- *
1801 * class methods. *
1802 * -------------------------------------------------------------------- */
1803
1804
1805 /**
1806 * Returns an unmodifiable view
1807 * of the specified collection <code>coll</code>.
1808 * This method allows modules to provide users
1809 * with "read-only" access to internal collections.
1810 * Query operations on the returned collection
1811 * "read through" to the specified collection,
1812 * and attempts to modify the returned collection,
1813 * whether direct or via its iterator,
1814 * result in an <code>UnsupportedOperationException</code>.
1815 *
1816 * @param coll
1817 * an instance of a <code>Collection</code>.
1818 * @return
1819 * a <code>Collection</code> which equals <code>coll</code>,
1820 * i.e. with the same elements
1821 * returned by the iterator in the same ordering
1822 * but is immutable.
1823 * Note that the return type offers methods
1824 * {@link CollectionsExt.ImmutableCollection
1825 *#allowModification(CollectionsExt.Modification)},
1826 * {@link CollectionsExt.ImmutableCollection#allowedModifications()}
1827 * and {@link CollectionsExt.ImmutableCollection#unrestricted()}.
1828 * @throws NullPointerException
1829 * if <code>coll==null</code>.
1830 */
1831 public static <E> ImmutableCollection<E>
1832 getImmutableCollection(Collection<E> coll) {
1833 return new ImmutableCollection<E>(coll);
1834 }
1835
1836 // as for {@link #getImmutableCollection(Collection)}
1837 public static <E> ImmutableSet<E> getImmutableSet(Set<E> set) {
1838 return new ImmutableSet<E>(set);
1839 }
1840
1841 // as for {@link #getImmutableCollection(Collection)}
1842 public static
1843 <E> ImmutableSortedSet<E> getImmutableSortedSet(SortedSet<E> set) {
1844 return new ImmutableSortedSet<E>(set);
1845 }
1846
1847 // as for {@link #getImmutableCollection(Collection)}
1848 public static <E> ImmutableList<E> getImmutableList(List<E> list) {
1849 return new ImmutableList<E>(list);
1850 }
1851
1852 public static <E> CyclicList<E> getImmutableCyclicList(CyclicList<E> cyc) {
1853 return new ImmutableCyclicList<E>(cyc);
1854 }
1855
1856 public static
1857 <E> MultiSet<E> getImmutableMultiSet(MultiSet<E> mSet) {
1858 return new ImmutableMultiSet<E>(mSet);
1859 }
1860
1861 public static <E>
1862 MultiSet<E> getImmutableSortedMultiSet(SortedMultiSet<E> mSet) {
1863 return new ImmutableMultiSet<E>(mSet);
1864 }
1865
1866
1867
1868 /**
1869 * Retuns a weak hash set, i.e. a hash set of weak references.
1870 *
1871 * @see java.util.HashMap
1872 * @see Collections#newSetFromMap(Map)
1873 */
1874 public static <E> Set<E> weakHashSet() {
1875 return Collections.newSetFromMap(new WeakHashMap<E, Boolean>());
1876 }
1877
1878 /**
1879 * Converts the list given recursively into an array.
1880 *
1881 * @param list
1882 * a <code>List</code>.
1883 * @return
1884 * an array <code>array</code> of objects satisfying
1885 * <code>array[i] == list.get(i)</code>
1886 * if <code>list.get(i)</code> is not a list;
1887 * <code>array[i] == recToArray(list.get(i))</code> otherwise.
1888 * Note that <code>array</code> may be a nested array
1889 * but that the dimension is always one.
1890 * @see #recToArray(Object, Class)
1891 * @see ArraysExt#recAsList(Object[])
1892 */
1893 public static Object[] recToArray(List<?> list) {
1894
1895 Object[] result = new Object[list.size()];
1896 int index = 0;
1897 for (Object cand : list) {
1898 if (cand instanceof List) {
1899 // cand is a list.
1900 result[index] = recToArray((List) cand);
1901 } else {
1902 // cand is no list.
1903 result[index] = cand;
1904 }
1905 index++;
1906 }
1907 return result;
1908 }
1909
1910 /**
1911 * Converts <code>source</code>
1912 * which is typically a {@link java.util.List},
1913 * recursively into an array with the given type.
1914 *
1915 * @param source
1916 * an arbitrary <code>Object</code>, even an array
1917 * but typically a <code>List</code>.
1918 * @param cls
1919 * Up to compatibility
1920 * (see {@link BasicTypesCompatibilityChecker#areCompatible}),
1921 * the type of the return value.
1922 * Note that typically this is an array type
1923 * such as <code>Double[][][]</code> or <code>List[][][]</code>
1924 * or even <code>int[][][]</code> but this need not be the case.
1925 * @return
1926 * <ul>
1927 * <li>
1928 * if <code>cls</code> and <code>source</code> are compatible
1929 * (see {@link BasicTypesCompatibilityChecker#areCompatible}),
1930 * e.g. if <code>source</code> is an instance of <code>cls</code>
1931 * or if <code>source == null</code>,
1932 * the object <code>source</code> is returned.
1933 * <p>
1934 * If <code>cls</code> is not an elementary type
1935 * as e.g. {@link java.lang.Boolean#TYPE},
1936 * and if <code>source != null</code>,
1937 * compatibility means that <code>source</code>
1938 * is an instance of the corresponding wrapper class.
1939 * <li>
1940 * if <code>cls</code> and <code>source</code> are not compatible,
1941 * <code>cls</code> must be an array type
1942 * and <code>source</code> must be a list;
1943 * otherwise an exception is thrown.
1944 * <p>
1945 * In the former case,
1946 * an array <code>array</code> of objects is returned
1947 * satisfying <code>array.length == ((List)source).size()</code> and
1948 * <code>array[i] == recToArray(list.get(i), cls2)</code>
1949 * for all valid indices <code>i</code> is returned.
1950 * The <code>cls2</code> argument for the recursive invocation
1951 * is the element type of <code>cls</code>.
1952 * <p>
1953 * Note that although the return value is always an array,
1954 * its type need not be a subtype of <code>Object[]</code>
1955 * or of <code>Object[][]</code>.
1956 * Consider for instance the case
1957 * where <code>source</code> is a list of <code>Integer</code>s
1958 * and <code>cls</code> is <code>int[]</code>:
1959 * This yields an
1960 * </ul>
1961 * @throws IllegalArgumentException
1962 * if neither of the following is true:
1963 * <ul>
1964 * <li>
1965 * <code>cls</code> and <code>source</code> are compatible.
1966 * <li>
1967 * <code>cls</code> is an array type and
1968 * <code>source</code> is a <code>List</code>.
1969 * </ul>
1970 * @see ArraysExt#recAsList(Object, Class)
1971 */
1972 public static Object recToArray(Object source, Class<?> cls) {
1973 return recToArray(source, cls, Caster.BASIC_TYPES);
1974 }
1975
1976 /**
1977 * Converts <code>source</code>
1978 * which is typically a {@link java.util.Collection},
1979 * recursively into an array with the given type
1980 * using the specified caster
1981 * for the elementary objects in <code>source</code>.
1982 *
1983 * @param source
1984 * an arbitrary <code>Object</code>, even an array
1985 * but typically a <code>Collection</code>.
1986 * @param cls
1987 * Up to compatibility defined by <code>caster</code>,
1988 * the type of the return value.
1989 * Note that typically this is an array type
1990 * such as <code>Double[][][]</code> or <code>List[][][]</code>
1991 * or even <code>int[][][]</code> but this need not be the case.
1992 * Note that the base type
1993 * has to be compatible with the source objects
1994 * with respect to the specified <code>caster</code>.
1995 * @param caster
1996 * performs the conversion of the top-level elements
1997 * of the <code>source</code>.
1998 * @return
1999 * <ul>
2000 * <li>
2001 * if <code>cls</code> and <code>source</code> are compatible
2002 * (see {@link Caster#areCompatible}),
2003 * the {@link Caster#cast cast of} <code>source</code> is returned.
2004 * <p>
2005 * Note that compatibility is up to wrapping of elementary types
2006 * and unwrapping of their wrappers.
2007 * <li>
2008 * if <code>cls</code> and <code>source</code> are not compatible,
2009 * <code>cls</code> must be an array type
2010 * and <code>source</code> must be a list;
2011 * otherwise an exception is thrown.
2012 * <p>
2013 * In the former case,
2014 * an array <code>array</code> of objects is returned
2015 * satisfying <code>array.length == ((Collection)source).size()</code>
2016 * and
2017 * <code>array[i] == recToArray(list.get(i), ... , caster)</code>
2018 * for all valid indices <code>i</code>.
2019 * The <code>cls2</code> argument for the recursive invocation
2020 * is the element type of <code>cls</code>.
2021 * <p>
2022 * Note that although the return value
2023 * is either the result of a casting process or an array,
2024 * in the latter case its type need not be
2025 * a subtype of <code>Object[]</code>
2026 * or of <code>Object[][]</code>.
2027 * Consider for instance the case
2028 * where <code>source</code> is a list of <code>Integer</code>s
2029 * and <code>cls</code> is <code>int[]</code>:
2030 * </ul>
2031 * @throws IllegalArgumentException
2032 * if neither of the following is true:
2033 * <ul>
2034 * <li>
2035 * <code>cls</code> and <code>source</code> are compatible
2036 * with respect to {@link Caster#areCompatible caster}.
2037 * <li>
2038 * <code>cls</code> is an array type and
2039 * <code>source</code> is a <code>List</code>.
2040 * </ul>
2041 * @see ArraysExt#recAsList(Object, Class, Caster)
2042 */
2043 public static Object recToArray(Object source,
2044 Class<?> cls,
2045 Caster caster) {
2046
2047 if (caster.areCompatible(cls, source)) {
2048 // Here, either source == null || cls.isInstance(source)
2049 // or source wraps something of type cls.
2050 return caster.cast(source);
2051 }
2052 // Here, source is not compatible with cls.
2053
2054 if (!cls.isArray()) {
2055 // Here, the result type is not an array type.
2056 throw new IllegalArgumentException
2057 ("Found incompatible types: " + source +
2058 " is not an instance of " + cls +
2059 " but of " + source.getClass() + ". ");
2060 }
2061
2062 // Here, the result type is an array type.
2063 if (!(source instanceof Collection)) {
2064 throw new IllegalArgumentException
2065 ("Found incompatible types: " + source +
2066 " is not an instance of List. ");
2067 }
2068 // Here, source instanceof Collection and cls.isArray().
2069
2070 Collection<?> coll = (Collection<?>) source;
2071 Class<?> compType = cls.getComponentType();
2072 Object result = Array.newInstance(compType, coll.size());
2073 int ind = 0;
2074 for (Object cand : coll) {
2075 // automatic unwrapping if needed.
2076 Array.set(result, ind++, recToArray(cand, compType, caster));
2077 }
2078 return result;
2079 }
2080
2081 /*
2082 * Fills the given map with key-value pairs given by <code>keyVal</code>
2083 * and returns a trace of the replaced objects.
2084 * Note that this method is misplaced in this class but ....
2085 *
2086 * @param map
2087 * a <code>Map</code> object.
2088 * @param keyVal
2089 * an array of key-value pairs.
2090 * In particular, <code>keyVal[i].length == 2</code> whenever defined.
2091 * @return
2092 * an array of key-value pairs.
2093 * An entry <code>new Object[] {key,value}</code> means,
2094 * that before invoking this method,
2095 * <code>map.get(key) == value</code> hold.
2096 * Note that <code>value == null</code> is possible.
2097 * @throws ClassCastException
2098 * if an element of an entry <code>new Object[] {key, value}</code>
2099 * of <code>keyVal</code> has not the right type.
2100 */
2101 /*
2102 public static <K, V> Object[][] fillMap(Map<K, V> map, Object[][] keyVal) {
2103 List<Object[]> replaced = new ArrayList<Object[]>();
2104 V repl;
2105 for (int i = 0; i < keyVal.length; i++) {
2106 repl = map.put((K)keyVal[i][0], (V)keyVal[i][1]);
2107 if (map.keySet().contains(keyVal[i][0])) {
2108 replaced.add(new Object[] {keyVal[i][0], repl});
2109 }
2110 }
2111 return (Object[][])replaced.toArray(new Object[][] {});
2112 }
2113 */
2114
2115 /**
2116 * Returns the unique element of the collection <code>coll</code>.
2117 *
2118 * @param coll
2119 * a collection of <code>T</code>'s.
2120 * @return
2121 * the unique element of the collection <code>coll</code>.
2122 * @throws IllegalStateException
2123 * if <code>coll</code> does not contain a unique element.
2124 */
2125 public static <T> T getUnique(Collection<? extends T> coll) {
2126 if (coll.size() != 1) {
2127 throw new IllegalStateException
2128 ("Expected a single element; found collection " + coll + ". ");
2129 }
2130 assert !coll.isEmpty();
2131
2132 return coll.iterator().next();
2133 // for (T res : coll) {
2134 // return res;
2135 // }
2136 // This place is never reached, because coll is not empty
2137 //throw new IllegalStateException();
2138 }
2139
2140 /**
2141 * Returns the reverse of the given list.
2142 * In fact the list returned is an {@link java.util.ArrayList}.
2143 */
2144 public static <T> List<T> reverse(List<T> list) {
2145 List<T> res = new ArrayList<T>(list.size());
2146 // NOPMD
2147 for (int i = 0; i < list.size(); i++) {// NOPMD
2148 res.add(list.get(list.size() - 1 - i));
2149 }
2150 return res;
2151 }
2152
2153 public static void main(String[] args) {
2154 }
2155
2156 }
2157
2158