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()) {
532 }
533
534 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
535 throw new InvalidObjectException("not serial proxy");
536 }
537
538 private Object writeReplace() {
539 Object[] array = new Object[size];
540 int dest = 0;
541 for (Object o : elements) {
542 if (o != null) {
543 array[dest++] = o;
544 }
545 }
546 return new CollSer(CollSer.IMM_SET, array);
547 }
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 }
|
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 static final List<?> EMPTY_LIST = new ListN<>();
76
77 @SuppressWarnings("unchecked")
78 static <E> List<E> emptyList() {
79 return (List<E>) EMPTY_LIST;
80 }
81
82 static abstract class AbstractImmutableList<E> extends AbstractCollection<E>
83 implements List<E>, RandomAccess {
84
85 // all mutating methods throw UnsupportedOperationException
86 @Override public boolean add(E e) { throw uoe(); }
87 @Override public void add(int index, E element) { throw uoe(); }
88 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
89 @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
90 @Override public void clear() { throw uoe(); }
91 @Override public boolean remove(Object o) { throw uoe(); }
92 @Override public E remove(int index) { throw uoe(); }
93 @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
94 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
95 @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); }
96 @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
97 @Override public E set(int index, E element) { throw uoe(); }
98 @Override public void sort(Comparator<? super E> c) { throw uoe(); }
99
100 @Override
101 public int indexOf(Object o) {
102 // Input should be checked for null, but this needs a CSR. See JDK-8191418
103 if (o == null) {
104 return -1;
105 }
106 // Objects.requireNonNull(o);
107 ListIterator<E> it = listIterator();
108 while (it.hasNext()) {
109 if (o.equals(it.next())) {
110 return it.previousIndex();
111 }
112 }
113 return -1;
114 }
115
116 @Override
117 public int lastIndexOf(Object o) {
118 // Input should be checked for null, but this needs a CSR. See JDK-8191418
119 if (o == null) {
120 return -1;
121 }
122 // Objects.requireNonNull(o);
123
124 ListIterator<E> it = listIterator();
125 while (it.hasNext()) {
126 if (o.equals(it.next())) {
127 return it.previousIndex();
128 }
129 }
130 return -1;
131 }
132
133 @Override
134 public boolean isEmpty() {
135 return size() == 0;
136 }
137
138 @Override
139 public List<E> subList(int fromIndex, int toIndex) {
140 int size = size();
141 subListRangeCheck(fromIndex, toIndex, size);
142 return new SubList<E>(this, fromIndex, toIndex);
143 }
144
145 private static final class SubList<E> extends AbstractImmutableList<E> implements RandomAccess {
146 private final List<E> root;
147 final int offset;
148 int size;
149
150 /**
151 * Constructs a sublist of an arbitrary AbstractList, which is
152 * not a SubList itself.
153 */
154 SubList(List<E> root, int fromIndex, int toIndex) {
155 this.root = root;
156 this.offset = fromIndex;
157 this.size = toIndex - fromIndex;
158 }
159
160 /**
161 * Constructs a sublist of another SubList.
162 */
163 SubList(SubList<E> parent, int fromIndex, int toIndex) {
164 this.root = parent.root;
165 this.offset = parent.offset + fromIndex;
166 this.size = toIndex - fromIndex;
167 }
168
169 public E get(int index) {
170 Objects.checkIndex(index, size);
171 return root.get(offset + index);
172 }
173
174 public int size() {
175 return size;
176 }
177
178 public Iterator<E> iterator() {
179 return listIterator();
180 }
181
182 public ListIterator<E> listIterator(int index) {
183 rangeCheck(index);
184
185 ListIterator<E> i = root.listIterator(offset + index);
186
187 return new ListIterator<>() {
188
189 public boolean hasNext() {
190 return nextIndex() < size;
191 }
192
193 public E next() {
194 if (hasNext()) {
195 return i.next();
196 } else {
197 throw new NoSuchElementException();
198 }
199 }
200
201 public boolean hasPrevious() {
202 return previousIndex() >= 0;
203 }
204
205 public E previous() {
206 if (hasPrevious()) {
207 return i.previous();
208 } else {
209 throw new NoSuchElementException();
210 }
211 }
212
213 public int nextIndex() {
214 return i.nextIndex() - offset;
215 }
216
217 public int previousIndex() {
218 return i.previousIndex() - offset;
219 }
220
221 public void remove() { throw uoe(); }
222 public void set(E e) { throw uoe(); }
223 public void add(E e) { throw uoe(); }
224 };
225 }
226
227 public List<E> subList(int fromIndex, int toIndex) {
228 subListRangeCheck(fromIndex, toIndex, size);
229 return new SubList<>(this, fromIndex, toIndex);
230 }
231
232 private void rangeCheck(int index) {
233 if (index < 0 || index > size) {
234 throw outOfBounds(index);
235 }
236 }
237 }
238
239 static void subListRangeCheck(int fromIndex, int toIndex, int size) {
240 if (fromIndex < 0)
241 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
242 if (toIndex > size)
243 throw new IndexOutOfBoundsException("toIndex = " + toIndex);
244 if (fromIndex > toIndex)
245 throw new IllegalArgumentException("fromIndex(" + fromIndex +
246 ") > toIndex(" + toIndex + ")");
247 }
248
249 @Override
250 public Iterator<E> iterator() {
251 return new Itr(size());
252 }
253
254 @Override
255 public ListIterator<E> listIterator() {
256 return listIterator(0);
257 }
258
259 @Override
260 public ListIterator<E> listIterator(final int index) {
261 int size = size();
262 if (index < 0 || index > size) {
263 throw outOfBounds(index);
264 }
265 return new ListItr(index, size);
266 }
267
268 private class Itr implements Iterator<E> {
269
270 int cursor;
271
272 private final int size;
273
274 Itr(int size) {
275 this.size = size;
276 }
277
278 public boolean hasNext() {
279 return cursor != size;
280 }
281
282 public E next() {
283 try {
284 int i = cursor;
285 E next = get(i);
286 cursor = i + 1;
287 return next;
288 } catch (IndexOutOfBoundsException e) {
289 throw new NoSuchElementException();
290 }
291 }
292
293 public void remove() {
294 throw uoe();
295 }
296 }
297
298 private class ListItr extends Itr implements ListIterator<E> {
299
300 ListItr(int index, int size) {
301 super(size);
302 cursor = index;
303 }
304
305 public boolean hasPrevious() {
306 return cursor != 0;
307 }
308
309 public E previous() {
310 try {
311 int i = cursor - 1;
312 E previous = get(i);
313 cursor = i;
314 return previous;
315 } catch (IndexOutOfBoundsException e) {
316 throw new NoSuchElementException();
317 }
318 }
319
320 public int nextIndex() {
321 return cursor;
322 }
323
324 public int previousIndex() {
325 return cursor - 1;
326 }
327
328 public void set(E e) {
329 throw uoe();
330 }
331
332 public void add(E e) {
333 throw uoe();
334 }
335 }
336
337
338 @Override
339 public boolean equals(Object o) {
340 if (o == this) {
341 return true;
342 }
343
344 if (!(o instanceof List)) {
345 return false;
346 }
347
348 Iterator<?> e1 = iterator();
349 Iterator<?> e2 = ((List<?>) o).iterator();
350 while (e1.hasNext() && e2.hasNext()) {
351 Object o1 = e1.next(); // can't be null
352 Object o2 = e2.next();
353 if (o1.equals(o2)) {
354 return false;
355 }
356 }
357 return !(e1.hasNext() || e2.hasNext());
358 }
359
360 IndexOutOfBoundsException outOfBounds(int index) {
361 return new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
362 }
363 }
364
365 static final class List12<E> extends AbstractImmutableList<E> implements Serializable {
366
367 @Stable
368 private final E e0;
369
370 @Stable
371 private final E e1;
372
373 List12(E e0) {
374 this.e0 = Objects.requireNonNull(e0);
375 this.e1 = null;
376 }
377
378 List12(E e0, E e1) {
379 this.e0 = Objects.requireNonNull(e0);
380 this.e1 = Objects.requireNonNull(e1);
381 }
382
383 @Override
384 public int size() {
385 return e1 != null ? 2 : 1;
386 }
387
388 @Override
389 public E get(int index) {
390 if (index == 0) {
391 return e0;
392 } else if (index == 1 && e1 != null) {
393 return e1;
394 }
395 throw outOfBounds(index);
396 }
397
398 @Override
399 public boolean contains(Object o) {
400 return o.equals(e0) || o.equals(e1); // implicit null check of o
401 }
402
403 @Override
404 public int hashCode() {
405 int hash = 31 + e0.hashCode();
406 if (e1 != null) {
407 hash = 31 * hash + e1.hashCode();
408 }
409 return hash;
410 }
411
412 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
413 throw new InvalidObjectException("not serial proxy");
414 }
415
416 private Object writeReplace() {
417 if (e1 == null) {
418 return new CollSer(CollSer.IMM_LIST, e0);
419 } else {
420 return new CollSer(CollSer.IMM_LIST, e0, e1);
421 }
422 }
423 }
424
425 static final class ListN<E> extends AbstractImmutableList<E> implements Serializable {
426
427 @Stable
428 private final E[] elements;
429
430 @SuppressWarnings("unchecked")
431 ListN(E e0) {
432 elements = (E[])new Object[] { e0 };
433 }
434
435 @SuppressWarnings("unchecked")
436 ListN(E e0, E e1) {
437 elements = (E[])new Object[] { e0, e1 };
438 }
439
440 @SafeVarargs
441 ListN(E... input) {
442 // copy and check manually to avoid TOCTOU
443 @SuppressWarnings("unchecked")
444 E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
445 for (int i = 0; i < input.length; i++) {
446 tmp[i] = Objects.requireNonNull(input[i]);
447 }
448 elements = tmp;
449 }
450
451 @Override
452 public boolean isEmpty() {
453 return size() == 0;
454 }
455
456 @Override
457 public int size() {
458 return elements.length;
459 }
460
461 @Override
462 public E get(int index) {
463 return elements[index];
464 }
465
466 @Override
467 public boolean contains(Object o) {
468 Objects.requireNonNull(o);
469 for (E e : elements) {
470 if (o.equals(e)) {
471 return true;
472 }
473 }
474 return false;
475 }
476
477 @Override
478 public int hashCode() {
479 int hash = 1;
480 for (E e : elements) {
481 hash = 31 * hash + e.hashCode();
482 }
483 return hash;
484 }
485
486 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
487 throw new InvalidObjectException("not serial proxy");
488 }
489
490 private Object writeReplace() {
491 return new CollSer(CollSer.IMM_LIST, elements);
492 }
493 }
494
495 // ---------- Set Implementations ----------
496
497 static final Set<?> EMPTY_SET = new SetN<>();
498
499 @SuppressWarnings("unchecked")
500 static <E> Set<E> emptySet() {
501 return (Set<E>) EMPTY_SET;
502 }
503
504 abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
505 @Override public boolean add(E e) { throw uoe(); }
506 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
507 @Override public void clear() { throw uoe(); }
508 @Override public boolean remove(Object o) { throw uoe(); }
509 @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
510 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
511 @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
512 }
513
514 static final class Set12<E> extends AbstractImmutableSet<E> {
515 @Stable
516 final E e0;
517 @Stable
518 final E e1;
519
520 Set12(E e0) {
521 this.e0 = Objects.requireNonNull(e0);
522 this.e1 = null;
523 }
524
525 Set12(E e0, E e1) {
526 if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
527 throw new IllegalArgumentException("duplicate element: " + e0);
528 }
529
530 if (SALT >= 0) {
531 this.e0 = e0;
532 this.e1 = e1;
533 } else {
534 this.e0 = e1;
535 this.e1 = e0;
536 }
537 }
538
539 @Override
540 public int size() {
541 return (e1 == null) ? 1 : 2;
542 }
543
544 @Override
545 public boolean contains(Object o) {
546 return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
547 }
548
549 @Override
550 public int hashCode() {
551 return e0.hashCode() + (e1 == null ? 0 : e1.hashCode());
552 }
553
554 @Override
555 public Iterator<E> iterator() {
556 return new Iterator<E>() {
557 private int idx = size();
558
559 @Override
560 public boolean hasNext() {
561 return idx > 0;
562 }
563
564 @Override
565 public E next() {
566 if (idx == 1) {
567 idx = 0;
568 return e0;
569 } else if (idx == 2) {
570 idx = 1;
571 return e1;
572 } else {
573 throw new NoSuchElementException();
574 }
575 }
576 };
577 }
578
579 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
580 throw new InvalidObjectException("not serial proxy");
581 }
582
583 private Object writeReplace() {
584 if (e1 == null) {
585 return new CollSer(CollSer.IMM_SET, e0);
586 } else {
587 return new CollSer(CollSer.IMM_SET, e0, e1);
588 }
589 }
590 }
591
592 /**
593 * An array-based Set implementation. The element array must be strictly
594 * larger than the size (the number of contained elements) so that at
595 * least one null is always present.
596 * @param <E> the element type
597 */
598 static final class SetN<E> extends AbstractImmutableSet<E> {
599 @Stable
600 final E[] elements;
601 @Stable
602 final int size;
603
604 @SafeVarargs
605 @SuppressWarnings("unchecked")
606 SetN(E... input) {
607 size = input.length; // implicit nullcheck of input
608
609 elements = (E[])new Object[EXPAND_FACTOR * input.length];
610 for (int i = 0; i < input.length; i++) {
611 E e = input[i];
612 int idx = probe(e); // implicit nullcheck of e
613 if (idx >= 0) {
614 throw new IllegalArgumentException("duplicate element: " + e);
615 } else {
616 elements[-(idx + 1)] = e;
617 }
618 }
619 }
620
621 @Override
622 public int size() {
623 return size;
624 }
625
626 @Override
627 public boolean contains(Object o) {
628 Objects.requireNonNull(o);
629 return size > 0 && probe(o) >= 0; // implicit nullcheck of o
630 }
631
632 @Override
633 public Iterator<E> iterator() {
634 return new Iterator<E>() {
635 private int idx = 0;
636
637 @Override
638 public boolean hasNext() {
639 while (idx < elements.length) {
640 if (elements[idx] != null)
641 return true;
642 idx++;
643 }
644 return false;
645 }
646
647 @Override
648 public E next() {
649 if (! hasNext()) {
684 }
685
686 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
687 throw new InvalidObjectException("not serial proxy");
688 }
689
690 private Object writeReplace() {
691 Object[] array = new Object[size];
692 int dest = 0;
693 for (Object o : elements) {
694 if (o != null) {
695 array[dest++] = o;
696 }
697 }
698 return new CollSer(CollSer.IMM_SET, array);
699 }
700 }
701
702 // ---------- Map Implementations ----------
703
704 static final Map<?,?> EMPTY_MAP = new MapN<>();
705
706 @SuppressWarnings("unchecked")
707 static <K,V> Map<K,V> emptyMap() {
708 return (Map<K,V>) EMPTY_MAP;
709 }
710
711 abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
712 @Override public void clear() { throw uoe(); }
713 @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
714 @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
715 @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
716 @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
717 @Override public V put(K key, V value) { throw uoe(); }
718 @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
719 @Override public V putIfAbsent(K key, V value) { throw uoe(); }
720 @Override public V remove(Object key) { throw uoe(); }
721 @Override public boolean remove(Object key, Object value) { throw uoe(); }
722 @Override public V replace(K key, V value) { throw uoe(); }
723 @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
724 @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
725 }
726
727 static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
728 @Stable
729 private final K k0;
730 @Stable
731 private final V v0;
732
733 Map1(K k0, V v0) {
734 this.k0 = Objects.requireNonNull(k0);
735 this.v0 = Objects.requireNonNull(v0);
736 }
737
738 @Override
739 public Set<Map.Entry<K,V>> entrySet() {
740 return Set.of(new KeyValueHolder<>(k0, v0));
741 }
742
743 @Override
744 public boolean containsKey(Object o) {
745 return o.equals(k0); // implicit nullcheck of o
746 }
759 }
760
761 @Override
762 public int hashCode() {
763 return k0.hashCode() ^ v0.hashCode();
764 }
765 }
766
767 /**
768 * An array-based Map implementation. There is a single array "table" that
769 * contains keys and values interleaved: table[0] is kA, table[1] is vA,
770 * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
771 * also be strictly larger than the size (the number of key-value pairs contained
772 * in the map) so that at least one null key is always present.
773 * @param <K> the key type
774 * @param <V> the value type
775 */
776 static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
777 @Stable
778 final Object[] table; // pairs of key, value
779
780 @Stable
781 final int size; // number of pairs
782
783 MapN(Object... input) {
784 if ((input.length & 1) != 0) { // implicit nullcheck of input
785 throw new InternalError("length is odd");
786 }
787 size = input.length >> 1;
788
789 int len = EXPAND_FACTOR * input.length;
790 len = (len + 1) & ~1; // ensure table is even length
791 table = new Object[len];
792
793 for (int i = 0; i < input.length; i += 2) {
794 @SuppressWarnings("unchecked")
795 K k = Objects.requireNonNull((K)input[i]);
796 @SuppressWarnings("unchecked")
797 V v = Objects.requireNonNull((V)input[i+1]);
798 int idx = probe(k);
799 if (idx >= 0) {
800 throw new IllegalArgumentException("duplicate key: " + k);
801 } else {
802 int dest = -(idx + 1);
803 table[dest] = k;
804 table[dest+1] = v;
805 }
806 }
807 }
808
809 @Override
810 public boolean containsKey(Object o) {
811 Objects.requireNonNull(o);
812 return size > 0 && probe(o) >= 0;
813 }
814
815 @Override
816 public boolean containsValue(Object o) {
817 for (int i = 1; i < table.length; i += 2) {
818 Object v = table[i];
819 if (v != null && o.equals(v)) { // implicit nullcheck of o
820 return true;
821 }
822 }
823 return false;
824 }
825
826 @Override
827 public int hashCode() {
828 int hash = 0;
829 for (int i = 0; i < table.length; i += 2) {
830 Object k = table[i];
831 if (k != null) {
832 hash += k.hashCode() ^ table[i + 1].hashCode();
833 }
834 }
835 return hash;
836 }
837
838 @Override
839 @SuppressWarnings("unchecked")
840 public V get(Object o) {
841 if (size == 0) {
842 return null;
843 }
844 int i = probe(o);
845 if (i >= 0) {
846 return (V)table[i+1];
847 } else {
848 return null;
849 }
850 }
851
852 @Override
853 public int size() {
854 return size;
855 }
856
857 @Override
858 public Set<Map.Entry<K,V>> entrySet() {
859 return new AbstractSet<Map.Entry<K,V>>() {
860 @Override
861 public int size() {
862 return MapN.this.size;
863 }
1054 * @throws InvalidObjectException if the tag value is illegal or if an exception
1055 * is thrown during creation of the collection
1056 * @throws ObjectStreamException if another serialization error has occurred
1057 * @since 9
1058 */
1059 private Object readResolve() throws ObjectStreamException {
1060 try {
1061 if (array == null) {
1062 throw new InvalidObjectException("null array");
1063 }
1064
1065 // use low order 8 bits to indicate "kind"
1066 // ignore high order 24 bits
1067 switch (tag & 0xff) {
1068 case IMM_LIST:
1069 return List.of(array);
1070 case IMM_SET:
1071 return Set.of(array);
1072 case IMM_MAP:
1073 if (array.length == 0) {
1074 return ImmutableCollections.emptyMap();
1075 } else if (array.length == 2) {
1076 return new ImmutableCollections.Map1<>(array[0], array[1]);
1077 } else {
1078 return new ImmutableCollections.MapN<>(array);
1079 }
1080 default:
1081 throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
1082 }
1083 } catch (NullPointerException|IllegalArgumentException ex) {
1084 InvalidObjectException ioe = new InvalidObjectException("invalid object");
1085 ioe.initCause(ex);
1086 throw ioe;
1087 }
1088 }
1089 }
|