42 * Container class for immutable collections. Not part of the public API.
43 * Mainly for namespace management and shared infrastructure.
44 *
45 * Serial warnings are suppressed throughout because all implementation
46 * classes use a serial proxy and thus have no need to declare serialVersionUID.
47 */
48 @SuppressWarnings("serial")
49 class ImmutableCollections {
50 /**
51 * A "salt" value used for randomizing iteration order. This is initialized once
52 * and stays constant for the lifetime of the JVM. It need not be truly random, but
53 * it needs to vary sufficiently from one run to the next so that iteration order
54 * will vary between JVM runs.
55 */
56 static final int SALT;
57 static {
58 long nt = System.nanoTime();
59 SALT = (int)((nt >>> 32) ^ nt);
60 }
61
62 /** No instances. */
63 private ImmutableCollections() { }
64
65 /**
66 * The reciprocal of load factor. Given a number of elements
67 * to store, multiply by this factor to get the table size.
68 */
69 static final int EXPAND_FACTOR = 2;
70
71 static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
72
73 // ---------- List Implementations ----------
74
75 abstract static class AbstractImmutableList<E> extends AbstractList<E>
76 implements RandomAccess, Serializable {
77 @Override public boolean add(E e) { throw uoe(); }
78 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
79 @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
80 @Override public void clear() { throw uoe(); }
81 @Override public boolean remove(Object o) { throw uoe(); }
82 @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
83 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
84 @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); }
85 @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
86 @Override public void sort(Comparator<? super E> c) { throw uoe(); }
87 }
88
89 static final class List0<E> extends AbstractImmutableList<E> {
90 private static final List0<?> INSTANCE = new List0<>();
91
92 @SuppressWarnings("unchecked")
93 static <T> List0<T> instance() {
94 return (List0<T>) INSTANCE;
95 }
96
97 private List0() { }
98
99 @Override
100 public int size() {
101 return 0;
102 }
103
104 @Override
105 public E get(int index) {
106 Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
107 return null; // but the compiler doesn't know this
108 }
109
110 @Override
111 public Iterator<E> iterator() {
112 return Collections.emptyIterator();
113 }
114
115 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
116 throw new InvalidObjectException("not serial proxy");
117 }
118
119 private Object writeReplace() {
120 return new CollSer(CollSer.IMM_LIST);
121 }
122
123 @Override
124 public boolean contains(Object o) {
125 Objects.requireNonNull(o);
126 return false;
127 }
128
129 @Override
130 public boolean containsAll(Collection<?> o) {
131 return o.isEmpty(); // implicit nullcheck of o
132 }
133
134 @Override
135 public int hashCode() {
136 return 1;
137 }
138 }
139
140 static final class List1<E> extends AbstractImmutableList<E> {
141 @Stable
142 private final E e0;
143
144 List1(E e0) {
145 this.e0 = Objects.requireNonNull(e0);
146 }
147
148 @Override
149 public int size() {
150 return 1;
151 }
152
153 @Override
154 public E get(int index) {
155 Objects.checkIndex(index, 1);
156 return e0;
157 }
158
159 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
160 throw new InvalidObjectException("not serial proxy");
161 }
162
163 private Object writeReplace() {
164 return new CollSer(CollSer.IMM_LIST, e0);
165 }
166
167 @Override
168 public boolean contains(Object o) {
169 return o.equals(e0); // implicit nullcheck of o
170 }
171
172 @Override
173 public int hashCode() {
174 return 31 + e0.hashCode();
175 }
176 }
177
178 static final class List2<E> extends AbstractImmutableList<E> {
179 @Stable
180 private final E e0;
181 @Stable
182 private final E e1;
183
184 List2(E e0, E e1) {
185 this.e0 = Objects.requireNonNull(e0);
186 this.e1 = Objects.requireNonNull(e1);
187 }
188
189 @Override
190 public int size() {
191 return 2;
192 }
193
194 @Override
195 public E get(int index) {
196 Objects.checkIndex(index, 2);
197 if (index == 0) {
198 return e0;
199 } else { // index == 1
200 return e1;
201 }
202 }
203
204 @Override
205 public boolean contains(Object o) {
206 return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
207 }
208
209 @Override
210 public int hashCode() {
211 int hash = 31 + e0.hashCode();
212 return 31 * hash + e1.hashCode();
213 }
214
215 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
216 throw new InvalidObjectException("not serial proxy");
217 }
218
219 private Object writeReplace() {
220 return new CollSer(CollSer.IMM_LIST, e0, e1);
221 }
222 }
223
224 static final class ListN<E> extends AbstractImmutableList<E> {
225 @Stable
226 private final E[] elements;
227
228 @SafeVarargs
229 ListN(E... input) {
230 // copy and check manually to avoid TOCTOU
231 @SuppressWarnings("unchecked")
232 E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
233 for (int i = 0; i < input.length; i++) {
234 tmp[i] = Objects.requireNonNull(input[i]);
235 }
236 this.elements = tmp;
237 }
238
239 @Override
240 public int size() {
241 return elements.length;
242 }
243
244 @Override
245 public E get(int index) {
246 Objects.checkIndex(index, elements.length);
247 return elements[index];
248 }
249
250 @Override
251 public boolean contains(Object o) {
252 for (E e : elements) {
253 if (o.equals(e)) { // implicit nullcheck of o
254 return true;
255 }
256 }
257 return false;
258 }
259
260 @Override
261 public int hashCode() {
262 int hash = 1;
263 for (E e : elements) {
264 hash = 31 * hash + e.hashCode();
265 }
266 return hash;
267 }
268
269 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
270 throw new InvalidObjectException("not serial proxy");
271 }
272
273 private Object writeReplace() {
274 return new CollSer(CollSer.IMM_LIST, elements);
275 }
276 }
277
278 // ---------- Set Implementations ----------
279
280 abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
281 @Override public boolean add(E e) { throw uoe(); }
282 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
283 @Override public void clear() { throw uoe(); }
284 @Override public boolean remove(Object o) { throw uoe(); }
285 @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
286 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
287 @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
288 }
289
290 static final class Set0<E> extends AbstractImmutableSet<E> {
291 private static final Set0<?> INSTANCE = new Set0<>();
292
293 @SuppressWarnings("unchecked")
294 static <T> Set0<T> instance() {
295 return (Set0<T>) INSTANCE;
296 }
297
298 private Set0() { }
299
300 @Override
301 public int size() {
302 return 0;
303 }
304
305 @Override
306 public boolean contains(Object o) {
307 Objects.requireNonNull(o);
308 return false;
309 }
310
311 @Override
312 public boolean containsAll(Collection<?> o) {
313 return o.isEmpty(); // implicit nullcheck of o
314 }
315
316 @Override
317 public Iterator<E> iterator() {
318 return Collections.emptyIterator();
319 }
320
321 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
322 throw new InvalidObjectException("not serial proxy");
323 }
324
325 private Object writeReplace() {
326 return new CollSer(CollSer.IMM_SET);
327 }
328
329 @Override
330 public int hashCode() {
331 return 0;
332 }
333 }
334
335 static final class Set1<E> extends AbstractImmutableSet<E> {
336 @Stable
337 private final E e0;
338
339 Set1(E e0) {
340 this.e0 = Objects.requireNonNull(e0);
341 }
342
343 @Override
344 public int size() {
345 return 1;
346 }
347
348 @Override
349 public boolean contains(Object o) {
350 return o.equals(e0); // implicit nullcheck of o
351 }
352
353 @Override
354 public Iterator<E> iterator() {
355 return Collections.singletonIterator(e0);
356 }
357
358 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
359 throw new InvalidObjectException("not serial proxy");
360 }
361
362 private Object writeReplace() {
363 return new CollSer(CollSer.IMM_SET, e0);
364 }
365
366 @Override
367 public int hashCode() {
368 return e0.hashCode();
369 }
370 }
371
372 static final class Set2<E> extends AbstractImmutableSet<E> {
373 @Stable
374 final E e0;
375 @Stable
376 final E e1;
377
378 Set2(E e0, E e1) {
379 if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
380 throw new IllegalArgumentException("duplicate element: " + e0);
381 }
382
383 if (SALT >= 0) {
384 this.e0 = e0;
385 this.e1 = e1;
386 } else {
387 this.e0 = e1;
388 this.e1 = e0;
389 }
390 }
391
392 @Override
393 public int size() {
394 return 2;
395 }
396
397 @Override
398 public boolean contains(Object o) {
399 return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
400 }
401
402 @Override
403 public int hashCode() {
404 return e0.hashCode() + e1.hashCode();
405 }
406
407 @Override
408 public Iterator<E> iterator() {
409 return new Iterator<E>() {
410 private int idx = 0;
411
412 @Override
413 public boolean hasNext() {
414 return idx < 2;
415 }
416
417 @Override
418 public E next() {
419 if (idx == 0) {
420 idx = 1;
421 return e0;
422 } else if (idx == 1) {
423 idx = 2;
424 return e1;
425 } else {
426 throw new NoSuchElementException();
427 }
428 }
429 };
430 }
431
432 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
433 throw new InvalidObjectException("not serial proxy");
434 }
435
436 private Object writeReplace() {
437 return new CollSer(CollSer.IMM_SET, e0, e1);
438 }
439 }
440
441 /**
442 * An array-based Set implementation. The element array must be strictly
443 * larger than the size (the number of contained elements) so that at
444 * least one null is always present.
445 * @param <E> the element type
446 */
447 static final class SetN<E> extends AbstractImmutableSet<E> {
448 @Stable
449 final E[] elements;
450 @Stable
451 final int size;
452
453 @SafeVarargs
454 @SuppressWarnings("unchecked")
455 SetN(E... input) {
456 size = input.length; // implicit nullcheck of input
457
458 elements = (E[])new Object[EXPAND_FACTOR * input.length];
459 for (int i = 0; i < input.length; i++) {
460 E e = input[i];
461 int idx = probe(e); // implicit nullcheck of e
462 if (idx >= 0) {
463 throw new IllegalArgumentException("duplicate element: " + e);
464 } else {
465 elements[-(idx + 1)] = e;
466 }
467 }
468 }
469
470 @Override
471 public int size() {
472 return size;
473 }
474
475 @Override
476 public boolean contains(Object o) {
477 return probe(o) >= 0; // implicit nullcheck of o
478 }
479
480 @Override
481 public Iterator<E> iterator() {
482 return new Iterator<E>() {
483 private int idx = 0;
484
485 @Override
486 public boolean hasNext() {
487 while (idx < elements.length) {
488 if (elements[idx] != null)
489 return true;
490 idx++;
491 }
492 return false;
493 }
494
495 @Override
496 public E next() {
497 if (! hasNext()) {
548 }
549
550 // ---------- Map Implementations ----------
551
552 abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
553 @Override public void clear() { throw uoe(); }
554 @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
555 @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
556 @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
557 @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
558 @Override public V put(K key, V value) { throw uoe(); }
559 @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
560 @Override public V putIfAbsent(K key, V value) { throw uoe(); }
561 @Override public V remove(Object key) { throw uoe(); }
562 @Override public boolean remove(Object key, Object value) { throw uoe(); }
563 @Override public V replace(K key, V value) { throw uoe(); }
564 @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
565 @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
566 }
567
568 static final class Map0<K,V> extends AbstractImmutableMap<K,V> {
569 private static final Map0<?,?> INSTANCE = new Map0<>();
570
571 @SuppressWarnings("unchecked")
572 static <K,V> Map0<K,V> instance() {
573 return (Map0<K,V>) INSTANCE;
574 }
575
576 private Map0() { }
577
578 @Override
579 public Set<Map.Entry<K,V>> entrySet() {
580 return Set.of();
581 }
582
583 @Override
584 public boolean containsKey(Object o) {
585 Objects.requireNonNull(o);
586 return false;
587 }
588
589 @Override
590 public boolean containsValue(Object o) {
591 Objects.requireNonNull(o);
592 return false;
593 }
594
595 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
596 throw new InvalidObjectException("not serial proxy");
597 }
598
599 private Object writeReplace() {
600 return new CollSer(CollSer.IMM_MAP);
601 }
602
603 @Override
604 public int hashCode() {
605 return 0;
606 }
607 }
608
609 static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
610 @Stable
611 private final K k0;
612 @Stable
613 private final V v0;
614
615 Map1(K k0, V v0) {
616 this.k0 = Objects.requireNonNull(k0);
617 this.v0 = Objects.requireNonNull(v0);
618 }
619
620 @Override
621 public Set<Map.Entry<K,V>> entrySet() {
622 return Set.of(new KeyValueHolder<>(k0, v0));
623 }
624
625 @Override
626 public boolean containsKey(Object o) {
627 return o.equals(k0); // implicit nullcheck of o
628 }
641 }
642
643 @Override
644 public int hashCode() {
645 return k0.hashCode() ^ v0.hashCode();
646 }
647 }
648
649 /**
650 * An array-based Map implementation. There is a single array "table" that
651 * contains keys and values interleaved: table[0] is kA, table[1] is vA,
652 * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
653 * also be strictly larger than the size (the number of key-value pairs contained
654 * in the map) so that at least one null key is always present.
655 * @param <K> the key type
656 * @param <V> the value type
657 */
658 static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
659 @Stable
660 final Object[] table; // pairs of key, value
661 @Stable
662 final int size; // number of pairs
663
664 MapN(Object... input) {
665 if ((input.length & 1) != 0) { // implicit nullcheck of input
666 throw new InternalError("length is odd");
667 }
668 size = input.length >> 1;
669
670 int len = EXPAND_FACTOR * input.length;
671 len = (len + 1) & ~1; // ensure table is even length
672 table = new Object[len];
673
674 for (int i = 0; i < input.length; i += 2) {
675 @SuppressWarnings("unchecked")
676 K k = Objects.requireNonNull((K)input[i]);
677 @SuppressWarnings("unchecked")
678 V v = Objects.requireNonNull((V)input[i+1]);
679 int idx = probe(k);
680 if (idx >= 0) {
681 throw new IllegalArgumentException("duplicate key: " + k);
682 } else {
683 int dest = -(idx + 1);
684 table[dest] = k;
685 table[dest+1] = v;
686 }
687 }
688 }
689
690 @Override
691 public boolean containsKey(Object o) {
692 return probe(o) >= 0; // implicit nullcheck of o
693 }
694
695 @Override
696 public boolean containsValue(Object o) {
697 for (int i = 1; i < table.length; i += 2) {
698 Object v = table[i];
699 if (v != null && o.equals(v)) { // implicit nullcheck of o
700 return true;
701 }
702 }
703 return false;
704 }
705
706 @Override
707 public int hashCode() {
708 int hash = 0;
709 for (int i = 0; i < table.length; i += 2) {
710 Object k = table[i];
711 if (k != null) {
712 hash += k.hashCode() ^ table[i + 1].hashCode();
713 }
714 }
715 return hash;
716 }
717
718 @Override
719 @SuppressWarnings("unchecked")
720 public V get(Object o) {
721 int i = probe(o);
722 if (i >= 0) {
723 return (V)table[i+1];
724 } else {
725 return null;
726 }
727 }
728
729 @Override
730 public int size() {
731 return size;
732 }
733
734 @Override
735 public Set<Map.Entry<K,V>> entrySet() {
736 return new AbstractSet<Map.Entry<K,V>>() {
737 @Override
738 public int size() {
739 return MapN.this.size;
740 }
931 * @throws InvalidObjectException if the tag value is illegal or if an exception
932 * is thrown during creation of the collection
933 * @throws ObjectStreamException if another serialization error has occurred
934 * @since 9
935 */
936 private Object readResolve() throws ObjectStreamException {
937 try {
938 if (array == null) {
939 throw new InvalidObjectException("null array");
940 }
941
942 // use low order 8 bits to indicate "kind"
943 // ignore high order 24 bits
944 switch (tag & 0xff) {
945 case IMM_LIST:
946 return List.of(array);
947 case IMM_SET:
948 return Set.of(array);
949 case IMM_MAP:
950 if (array.length == 0) {
951 return ImmutableCollections.Map0.instance();
952 } else if (array.length == 2) {
953 return new ImmutableCollections.Map1<>(array[0], array[1]);
954 } else {
955 return new ImmutableCollections.MapN<>(array);
956 }
957 default:
958 throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
959 }
960 } catch (NullPointerException|IllegalArgumentException ex) {
961 InvalidObjectException ioe = new InvalidObjectException("invalid object");
962 ioe.initCause(ex);
963 throw ioe;
964 }
965 }
966 }
|
42 * Container class for immutable collections. Not part of the public API.
43 * Mainly for namespace management and shared infrastructure.
44 *
45 * Serial warnings are suppressed throughout because all implementation
46 * classes use a serial proxy and thus have no need to declare serialVersionUID.
47 */
48 @SuppressWarnings("serial")
49 class ImmutableCollections {
50 /**
51 * A "salt" value used for randomizing iteration order. This is initialized once
52 * and stays constant for the lifetime of the JVM. It need not be truly random, but
53 * it needs to vary sufficiently from one run to the next so that iteration order
54 * will vary between JVM runs.
55 */
56 static final int SALT;
57 static {
58 long nt = System.nanoTime();
59 SALT = (int)((nt >>> 32) ^ nt);
60 }
61
62 private static final Object NULL = new Object();
63
64 /** No instances. */
65 private ImmutableCollections() { }
66
67 /**
68 * The reciprocal of load factor. Given a number of elements
69 * to store, multiply by this factor to get the table size.
70 */
71 static final int EXPAND_FACTOR = 2;
72
73 static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
74
75 // ---------- List Implementations ----------
76
77 static final List<?> EMPTY_LIST = new ListN<>();
78
79 static final Set<?> EMPTY_SET = new SetN<>();
80
81 static final Map<?,?> EMPTY_MAP = new MapN<>();
82
83 @SuppressWarnings("unchecked")
84 static <T> List<T> emptyList() {
85 return (List<T>) EMPTY_LIST;
86 }
87
88 @SuppressWarnings("unchecked")
89 static <T> Set<T> emptySet() {
90 return (Set<T>) EMPTY_SET;
91 }
92
93 @SuppressWarnings("unchecked")
94 static <K,V> Map<K,V> emptyMap() {
95 return (Map<K,V>) EMPTY_MAP;
96 }
97
98 static final class ListN<E> extends AbstractCollection<E>
99 implements List<E>, RandomAccess, Serializable {
100
101 // all mutating methods throw UnsupportedOperationException
102 @Override public boolean add(E e) { throw uoe(); }
103 @Override public void add(int index, E element) { throw uoe(); }
104 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
105 @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
106 @Override public void clear() { throw uoe(); }
107 @Override public boolean remove(Object o) { throw uoe(); }
108 @Override public E remove(int index) { throw uoe(); }
109 @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
110 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
111 @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); }
112 @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
113 @Override public E set(int index, E element) { throw uoe(); }
114 @Override public void sort(Comparator<? super E> c) { throw uoe(); }
115
116 @Override
117 public int indexOf(Object o) {
118 Objects.requireNonNull(o);
119 ListIterator<E> it = listIterator();
120 while (it.hasNext()) {
121 if (o.equals(it.next())) {
122 return it.previousIndex();
123 }
124 }
125 return -1;
126 }
127
128 @Override
129 public int lastIndexOf(Object o) {
130 Objects.requireNonNull(o);
131 ListIterator<E> it = listIterator();
132 while (it.hasNext()) {
133 if (o.equals(it.next())) {
134 return it.previousIndex();
135 }
136 }
137 return -1;
138 }
139
140 @Override
141 public boolean equals(Object o) {
142 if (o == this) {
143 return true;
144 }
145
146 if (!(o instanceof List)) {
147 return false;
148 }
149
150 if (!(o instanceof ListN)) {
151 ListN<?> other = (ListN<?>)o;
152 return this.e0.equals(other.e0) && this.e1.equals(e1);
153 }
154
155 ListIterator<E> e1 = listIterator();
156 ListIterator<?> e2 = ((List<?>) o).listIterator();
157 while (e1.hasNext() && e2.hasNext()) {
158 E o1 = e1.next();
159 Object o2 = e2.next();
160 if (!(o1==null ? o2==null : o1.equals(o2)))
161 return false;
162 }
163 return !(e1.hasNext() || e2.hasNext());
164 }
165
166 @Override
167 public List<E> subList(int fromIndex, int toIndex) {
168 int size = size();
169 Objects.checkFromToIndex(fromIndex, toIndex, size);
170 if (size == 0 || fromIndex == toIndex) {
171 return emptyList();
172 } else if (size == 1) {
173 // checks above deal with corner cases subList(0,0) and subList(1,1)
174 // that would return the empty list
175 assert(fromIndex == 0 && toIndex == 1);
176 return this;
177 } else {
178 return new SubList<E>(this, fromIndex, toIndex);
179 }
180 }
181
182 private static class SubList<E> extends AbstractList<E> implements RandomAccess {
183 private final List<E> root;
184 private final int offset;
185 int size;
186
187 // all mutating methods throw UnsupportedOperationException
188 @Override public boolean add(E e) { throw uoe(); }
189 @Override public void add(int index, E element) { throw uoe(); }
190 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
191 @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
192 @Override public void clear() { throw uoe(); }
193 @Override public boolean remove(Object o) { throw uoe(); }
194 @Override public E remove(int index) { throw uoe(); }
195 @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
196 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
197 @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); }
198 @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
199 @Override public E set(int index, E element) { throw uoe(); }
200 @Override public void sort(Comparator<? super E> c) { throw uoe(); }
201
202 /**
203 * Constructs a sublist of an arbitrary AbstractList, which is
204 * not a SubList itself.
205 */
206 public SubList(List<E> root, int fromIndex, int toIndex) {
207 this.root = root;
208 this.offset = fromIndex;
209 this.size = toIndex - fromIndex;
210 }
211
212 /**
213 * Constructs a sublist of another SubList.
214 */
215 protected SubList(SubList<E> parent, int fromIndex, int toIndex) {
216 this.root = parent.root;
217 this.offset = parent.offset + fromIndex;
218 this.size = toIndex - fromIndex;
219 }
220
221 public E get(int index) {
222 Objects.checkIndex(index, size);
223 return root.get(offset + index);
224 }
225
226 public int size() {
227 return size;
228 }
229
230 protected void removeRange(int fromIndex, int toIndex) {
231 throw uoe();
232 }
233
234 public Iterator<E> iterator() {
235 return listIterator();
236 }
237
238 public ListIterator<E> listIterator(int index) {
239 rangeCheck(index);
240
241 return new ListIterator<E>() {
242 private final ListIterator<E> i =
243 root.listIterator(offset + index);
244
245 public boolean hasNext() {
246 return nextIndex() < size;
247 }
248
249 public E next() {
250 if (hasNext())
251 return i.next();
252 else
253 throw new NoSuchElementException();
254 }
255
256 public boolean hasPrevious() {
257 return previousIndex() >= 0;
258 }
259
260 public E previous() {
261 if (hasPrevious())
262 return i.previous();
263 else
264 throw new NoSuchElementException();
265 }
266
267 public int nextIndex() {
268 return i.nextIndex() - offset;
269 }
270
271 public int previousIndex() {
272 return i.previousIndex() - offset;
273 }
274
275 public void remove() { throw uoe(); }
276 public void set(E e) { throw uoe(); }
277 public void add(E e) { throw uoe(); }
278 };
279 }
280
281 public List<E> subList(int fromIndex, int toIndex) {
282 subListRangeCheck(fromIndex, toIndex, size);
283 return new SubList<>(this, fromIndex, toIndex);
284 }
285
286 private void rangeCheck(int index) {
287 if (index < 0 || index > size)
288 throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
289 }
290
291 private String outOfBoundsMsg(int index) {
292 return "Index: "+index+", Size: "+size;
293 }
294 }
295
296 @Stable
297 private final Object e0;
298
299 @Stable
300 private final Object e1;
301
302 private final int size;
303
304 @SafeVarargs
305 ListN(E... input) {
306 if (input.length == 1) {
307 e0 = Objects.requireNonNull(input[0]);
308 e1 = NULL;
309 size = 1;
310 } else if (input.length == 2) {
311 e0 = Objects.requireNonNull(input[0]);
312 e1 = Objects.requireNonNull(input[1]);
313 size = 2;
314 } else {
315 e0 = NULL;
316 // copy and check manually to avoid TOCTOU
317 @SuppressWarnings("unchecked")
318 E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
319 for (int i = 0; i < input.length; i++) {
320 tmp[i] = Objects.requireNonNull(input[i]);
321 }
322 this.e1 = tmp;
323 size = input.length;
324 }
325 }
326
327 @Override
328 public boolean isEmpty() {
329 return size() == 0;
330 }
331
332 @Override
333 @SuppressWarnings("unchecked")
334 public int size() {
335 return size;
336 }
337
338 @Override
339 @SuppressWarnings("unchecked")
340 public E get(int index) {
341 int size = size();
342 Objects.checkIndex(index, size); // IOOBE if size == 0, or size == 1 and index == 1
343 if (size <= 2) {
344 if (index == 0) {
345 return (E)e0;
346 } else {
347 return (E)e1;
348 }
349 } else {
350 return ((E[]) e1)[index];
351 }
352 }
353
354 @Override
355 @SuppressWarnings("unchecked")
356 public boolean contains(Object o) {
357 int size = size();
358 Objects.requireNonNull(o);
359 if (size == 1) {
360 return o.equals(e0);
361 } else if (size == 2) {
362 return o.equals(e0) || o.equals(e1);
363 } else {
364 for (E e : (E[])e1) {
365 if (o.equals(e)) { // implicit nullcheck of o
366 return true;
367 }
368 }
369 return false;
370 }
371 }
372
373 @Override
374 @SuppressWarnings("unchecked")
375 public int hashCode() {
376 int size = size();
377 if (size == 1) {
378 return 31 + e0.hashCode();
379 } else if (size == 2) {
380 return (31 + e0.hashCode()) * 31 + e1.hashCode();
381 }
382
383 int hash = 1;
384 for (E e : (E[])e1) {
385 hash = 31 * hash + e.hashCode();
386 }
387 return hash;
388 }
389
390 @Override
391 public Iterator<E> iterator() {
392 return new Itr();
393 }
394
395 @Override
396 public ListIterator<E> listIterator() {
397 return listIterator(0);
398 }
399
400 @Override
401 public ListIterator<E> listIterator(final int index) {
402 Objects.checkIndex(index, size());
403 return new ListItr(index);
404 }
405
406 private class Itr implements Iterator<E> {
407 Itr() {
408 size = size();
409 }
410
411 int cursor = 0;
412
413 private final int size;
414
415 public boolean hasNext() {
416 return cursor != size;
417 }
418
419 public E next() {
420 try {
421 int i = cursor;
422 E next = get(i);
423 cursor = i + 1;
424 return next;
425 } catch (IndexOutOfBoundsException e) {
426 throw new NoSuchElementException();
427 }
428 }
429
430 public void remove() {
431 throw uoe();
432 }
433 }
434
435 private class ListItr extends Itr implements ListIterator<E> {
436 ListItr(int index) {
437 cursor = index;
438 }
439
440 public boolean hasPrevious() {
441 return cursor != 0;
442 }
443
444 public E previous() {
445 try {
446 int i = cursor - 1;
447 E previous = get(i);
448 cursor = i;
449 return previous;
450 } catch (IndexOutOfBoundsException e) {
451 throw new NoSuchElementException();
452 }
453 }
454
455 public int nextIndex() {
456 return cursor;
457 }
458
459 public int previousIndex() {
460 return cursor - 1;
461 }
462
463 public void set(E e) {
464 throw uoe();
465 }
466
467 public void add(E e) {
468 throw uoe();
469 }
470 }
471
472 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
473 throw new InvalidObjectException("not serial proxy");
474 }
475
476 @SuppressWarnings("unchecked")
477 private Object writeReplace() {
478 int size = size();
479 if (size == 1) {
480 return new CollSer(CollSer.IMM_LIST, (E)e0);
481 } else if (size == 2) {
482 return new CollSer(CollSer.IMM_LIST, (E)e0, (E)e1);
483 } else {
484 return new CollSer(CollSer.IMM_LIST, (E[])e1);
485 }
486 }
487 }
488
489 // ---------- Set Implementations ----------
490
491 abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
492 @Override public boolean add(E e) { throw uoe(); }
493 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
494 @Override public void clear() { throw uoe(); }
495 @Override public boolean remove(Object o) { throw uoe(); }
496 @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
497 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
498 @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
499 }
500
501 static final class Set1<E> extends AbstractImmutableSet<E> {
502 @Stable
503 private final E e0;
504
505 Set1(E e0) {
506 this.e0 = Objects.requireNonNull(e0);
507 }
508
509 @Override
510 public int size() {
511 return 1;
512 }
513
514 @Override
515 public boolean contains(Object o) {
516 return o.equals(e0); // implicit nullcheck of o
517 }
518
519 @Override
520 public Iterator<E> iterator() {
521 return Collections.singletonIterator(e0);
522 }
523
524 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
525 throw new InvalidObjectException("not serial proxy");
526 }
527
528 private Object writeReplace() {
529 return new CollSer(CollSer.IMM_SET, e0);
530 }
531
532 @Override
533 public int hashCode() {
534 return e0.hashCode();
535 }
536 }
537
538 /**
539 * An array-based Set implementation. The element array must be strictly
540 * larger than the size (the number of contained elements) so that at
541 * least one null is always present.
542 * @param <E> the element type
543 */
544 static final class SetN<E> extends AbstractImmutableSet<E> {
545 @Stable
546 final E[] elements;
547 @Stable
548 final int size;
549
550 @SafeVarargs
551 @SuppressWarnings("unchecked")
552 SetN(E... input) {
553 size = input.length; // implicit nullcheck of input
554
555 elements = (E[])new Object[EXPAND_FACTOR * input.length];
556 for (int i = 0; i < input.length; i++) {
557 E e = input[i];
558 int idx = probe(e); // implicit nullcheck of e
559 if (idx >= 0) {
560 throw new IllegalArgumentException("duplicate element: " + e);
561 } else {
562 elements[-(idx + 1)] = e;
563 }
564 }
565 }
566
567 @Override
568 public int size() {
569 return size;
570 }
571
572 @Override
573 public boolean contains(Object o) {
574 Objects.requireNonNull(0);
575 return size > 0 && probe(o) >= 0; // implicit nullcheck of o
576 }
577
578 @Override
579 public Iterator<E> iterator() {
580 return new Iterator<E>() {
581 private int idx = 0;
582
583 @Override
584 public boolean hasNext() {
585 while (idx < elements.length) {
586 if (elements[idx] != null)
587 return true;
588 idx++;
589 }
590 return false;
591 }
592
593 @Override
594 public E next() {
595 if (! hasNext()) {
646 }
647
648 // ---------- Map Implementations ----------
649
650 abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
651 @Override public void clear() { throw uoe(); }
652 @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
653 @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
654 @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
655 @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
656 @Override public V put(K key, V value) { throw uoe(); }
657 @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
658 @Override public V putIfAbsent(K key, V value) { throw uoe(); }
659 @Override public V remove(Object key) { throw uoe(); }
660 @Override public boolean remove(Object key, Object value) { throw uoe(); }
661 @Override public V replace(K key, V value) { throw uoe(); }
662 @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
663 @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
664 }
665
666 static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
667 @Stable
668 private final K k0;
669 @Stable
670 private final V v0;
671
672 Map1(K k0, V v0) {
673 this.k0 = Objects.requireNonNull(k0);
674 this.v0 = Objects.requireNonNull(v0);
675 }
676
677 @Override
678 public Set<Map.Entry<K,V>> entrySet() {
679 return Set.of(new KeyValueHolder<>(k0, v0));
680 }
681
682 @Override
683 public boolean containsKey(Object o) {
684 return o.equals(k0); // implicit nullcheck of o
685 }
698 }
699
700 @Override
701 public int hashCode() {
702 return k0.hashCode() ^ v0.hashCode();
703 }
704 }
705
706 /**
707 * An array-based Map implementation. There is a single array "table" that
708 * contains keys and values interleaved: table[0] is kA, table[1] is vA,
709 * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
710 * also be strictly larger than the size (the number of key-value pairs contained
711 * in the map) so that at least one null key is always present.
712 * @param <K> the key type
713 * @param <V> the value type
714 */
715 static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
716 @Stable
717 final Object[] table; // pairs of key, value
718 final int size; // number of pairs
719
720 MapN(Object... input) {
721 if ((input.length & 1) != 0) { // implicit nullcheck of input
722 throw new InternalError("length is odd");
723 }
724 size = input.length >> 1;
725
726 int len = EXPAND_FACTOR * input.length;
727 len = (len + 1) & ~1; // ensure table is even length
728 table = new Object[len];
729
730 for (int i = 0; i < input.length; i += 2) {
731 @SuppressWarnings("unchecked")
732 K k = Objects.requireNonNull((K)input[i]);
733 @SuppressWarnings("unchecked")
734 V v = Objects.requireNonNull((V)input[i+1]);
735 int idx = probe(k);
736 if (idx >= 0) {
737 throw new IllegalArgumentException("duplicate key: " + k);
738 } else {
739 int dest = -(idx + 1);
740 table[dest] = k;
741 table[dest+1] = v;
742 }
743 }
744 }
745
746 @Override
747 public boolean containsKey(Object o) {
748 Objects.requireNonNull(0);
749 return size > 0 && probe(o) >= 0;
750 }
751
752 @Override
753 public boolean containsValue(Object o) {
754 for (int i = 1; i < table.length; i += 2) {
755 Object v = table[i];
756 if (v != null && o.equals(v)) { // implicit nullcheck of o
757 return true;
758 }
759 }
760 return false;
761 }
762
763 @Override
764 public int hashCode() {
765 int hash = 0;
766 for (int i = 0; i < table.length; i += 2) {
767 Object k = table[i];
768 if (k != null) {
769 hash += k.hashCode() ^ table[i + 1].hashCode();
770 }
771 }
772 return hash;
773 }
774
775 @Override
776 @SuppressWarnings("unchecked")
777 public V get(Object o) {
778 if (size == 0) {
779 return null;
780 }
781 int i = probe(o);
782 if (i >= 0) {
783 return (V)table[i+1];
784 } else {
785 return null;
786 }
787 }
788
789 @Override
790 public int size() {
791 return size;
792 }
793
794 @Override
795 public Set<Map.Entry<K,V>> entrySet() {
796 return new AbstractSet<Map.Entry<K,V>>() {
797 @Override
798 public int size() {
799 return MapN.this.size;
800 }
991 * @throws InvalidObjectException if the tag value is illegal or if an exception
992 * is thrown during creation of the collection
993 * @throws ObjectStreamException if another serialization error has occurred
994 * @since 9
995 */
996 private Object readResolve() throws ObjectStreamException {
997 try {
998 if (array == null) {
999 throw new InvalidObjectException("null array");
1000 }
1001
1002 // use low order 8 bits to indicate "kind"
1003 // ignore high order 24 bits
1004 switch (tag & 0xff) {
1005 case IMM_LIST:
1006 return List.of(array);
1007 case IMM_SET:
1008 return Set.of(array);
1009 case IMM_MAP:
1010 if (array.length == 0) {
1011 return ImmutableCollections.emptyMap();
1012 } else if (array.length == 2) {
1013 return new ImmutableCollections.Map1<>(array[0], array[1]);
1014 } else {
1015 return new ImmutableCollections.MapN<>(array);
1016 }
1017 default:
1018 throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
1019 }
1020 } catch (NullPointerException|IllegalArgumentException ex) {
1021 InvalidObjectException ioe = new InvalidObjectException("invalid object");
1022 ioe.initCause(ex);
1023 throw ioe;
1024 }
1025 }
1026 }
|