• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.util;
27 
28 import java.io.IOException;
29 import java.io.InvalidObjectException;
30 import java.io.ObjectInputStream;
31 import java.io.ObjectOutputStream;
32 import java.io.ObjectStreamException;
33 import java.io.Serializable;
34 import java.lang.reflect.Array;
35 import java.util.function.BiFunction;
36 import java.util.function.Function;
37 import java.util.function.Predicate;
38 import java.util.function.UnaryOperator;
39 import jdk.internal.access.JavaUtilCollectionAccess;
40 import jdk.internal.access.SharedSecrets;
41 import jdk.internal.vm.annotation.Stable;
42 
43 /**
44  * Container class for immutable collections. Not part of the public API.
45  * Mainly for namespace management and shared infrastructure.
46  *
47  * Serial warnings are suppressed throughout because all implementation
48  * classes use a serial proxy and thus have no need to declare serialVersionUID.
49  */
50 @SuppressWarnings("serial")
51 class ImmutableCollections {
52     /**
53      * A "salt" value used for randomizing iteration order. This is initialized once
54      * and stays constant for the lifetime of the JVM. It need not be truly random, but
55      * it needs to vary sufficiently from one run to the next so that iteration order
56      * will vary between JVM runs.
57      */
58     private static final long SALT32L;
59 
60     /**
61      * For set and map iteration, we will iterate in "reverse" stochastically,
62      * decided at bootstrap time.
63      */
64     private static final boolean REVERSE;
65     static {
66         // to generate a reasonably random and well-mixed SALT, use an arbitrary
67         // value (a slice of pi), multiply with a random seed, then pick
68         // the mid 32-bits from the product. By picking a SALT value in the
69         // [0 ... 0xFFFF_FFFFL == 2^32-1] range, we ensure that for any positive
70         // int N, (SALT32L * N) >> 32 is a number in the [0 ... N-1] range. This
71         // property will be used to avoid more expensive modulo-based
72         // calculations.
73         long color = 0x243F_6A88_85A3_08D3L; // slice of pi
74 
75         // BEGIN Android-changed: set seed directly, as CDS is not available.
76         // When running with -Xshare:dump, the VM will supply a "random" seed that's
77         // derived from the JVM build/version, so can we generate the exact same
78         // CDS archive for the same JDK build. This makes it possible to verify the
79         // consistency of the JDK build.
80         // long seed = CDS.getRandomSeedForDumping();
81         // if (seed == 0) {
82         //   seed = System.nanoTime();
83         // }
84         long seed = System.nanoTime();
85         // END Android-changed: set seed directly, as CDS is not available.
86         SALT32L = (int)((color * seed) >> 16) & 0xFFFF_FFFFL;
87         // use the lowest bit to determine if we should reverse iteration
88         REVERSE = (SALT32L & 1) == 0;
89     }
90 
91     // BEGIN Android-changed: always initialize empty collections.
92     /*
93      * Constants following this might be initialized from the CDS archive via
94      * this array.
95      *
96     // private static Object[] archivedObjects;
97      */
98 
99     private static final Object EMPTY = new Object();
100     static final ListN<?> EMPTY_LIST = new ListN<>(new Object[0], false);
101     static final ListN<?> EMPTY_LIST_NULLS = new ListN<>(new Object[0], true);
102     static final SetN<?> EMPTY_SET = new SetN<>();
103     static final MapN<?,?> EMPTY_MAP = new MapN<>();
104 
105     /*
106     static {
107         CDS.initializeFromArchive(ImmutableCollections.class);
108         if (archivedObjects == null) {
109             EMPTY = new Object();
110             EMPTY_LIST = new ListN<>(new Object[0], false);
111             EMPTY_LIST_NULLS = new ListN<>(new Object[0], true);
112             EMPTY_SET = new SetN<>();
113             EMPTY_MAP = new MapN<>();
114             archivedObjects =
115                 new Object[] { EMPTY, EMPTY_LIST, EMPTY_LIST_NULLS, EMPTY_SET, EMPTY_MAP };
116         } else {
117             EMPTY = archivedObjects[0];
118             EMPTY_LIST = (ListN)archivedObjects[1];
119             EMPTY_LIST_NULLS = (ListN)archivedObjects[2];
120             EMPTY_SET = (SetN)archivedObjects[3];
121             EMPTY_MAP = (MapN)archivedObjects[4];
122         }
123     }
124     */
125     // END Android-changed: always initialize empty collections.
126 
127     static class Access {
128         static {
SharedSecrets.setJavaUtilCollectionAccess(new JavaUtilCollectionAccess() { public <E> List<E> listFromTrustedArray(Object[] array) { return ImmutableCollections.listFromTrustedArray(array); } public <E> List<E> listFromTrustedArrayNullsAllowed(Object[] array) { return ImmutableCollections.listFromTrustedArrayNullsAllowed(array); } })129             SharedSecrets.setJavaUtilCollectionAccess(new JavaUtilCollectionAccess() {
130                 public <E> List<E> listFromTrustedArray(Object[] array) {
131                     return ImmutableCollections.listFromTrustedArray(array);
132                 }
133                 public <E> List<E> listFromTrustedArrayNullsAllowed(Object[] array) {
134                     return ImmutableCollections.listFromTrustedArrayNullsAllowed(array);
135                 }
136             });
137         }
138     }
139 
140     /** No instances. */
ImmutableCollections()141     private ImmutableCollections() { }
142 
143     /**
144      * The reciprocal of load factor. Given a number of elements
145      * to store, multiply by this factor to get the table size.
146      */
147     static final int EXPAND_FACTOR = 2;
148 
uoe()149     static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
150 
151     @jdk.internal.ValueBased
152     abstract static class AbstractImmutableCollection<E> extends AbstractCollection<E> {
153         // all mutating methods throw UnsupportedOperationException
add(E e)154         @Override public boolean add(E e) { throw uoe(); }
addAll(Collection<? extends E> c)155         @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
clear()156         @Override public void    clear() { throw uoe(); }
remove(Object o)157         @Override public boolean remove(Object o) { throw uoe(); }
removeAll(Collection<?> c)158         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
removeIf(Predicate<? super E> filter)159         @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
retainAll(Collection<?> c)160         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
161     }
162 
163     // ---------- List Static Factory Methods ----------
164 
165     /**
166      * Copies a collection into a new List, unless the arg is already a safe,
167      * null-prohibiting unmodifiable list, in which case the arg itself is returned.
168      * Null argument or null elements in the argument will result in NPE.
169      *
170      * @param <E> the List's element type
171      * @param input the input array
172      * @return the new list
173      */
174     @SuppressWarnings("unchecked")
listCopy(Collection<? extends E> coll)175     static <E> List<E> listCopy(Collection<? extends E> coll) {
176         if (coll instanceof List12 || (coll instanceof ListN<?> c && !c.allowNulls)) {
177             return (List<E>)coll;
178         } else if (coll.isEmpty()) { // implicit nullcheck of coll
179             return List.of();
180         } else {
181             return (List<E>)List.of(coll.toArray());
182         }
183     }
184 
185     /**
186      * Creates a new List from an untrusted array, creating a new array for internal
187      * storage, and checking for and rejecting null elements.
188      *
189      * @param <E> the List's element type
190      * @param input the input array
191      * @return the new list
192      */
193     @SafeVarargs
listFromArray(E... input)194     static <E> List<E> listFromArray(E... input) {
195         // copy and check manually to avoid TOCTOU
196         @SuppressWarnings("unchecked")
197         E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
198         for (int i = 0; i < input.length; i++) {
199             tmp[i] = Objects.requireNonNull(input[i]);
200         }
201         return new ListN<>(tmp, false);
202     }
203 
204     /**
205      * Creates a new List from a trusted array, checking for and rejecting null
206      * elements.
207      *
208      * <p>A trusted array has no references retained by the caller. It can therefore be
209      * safely reused as the List's internal storage, avoiding a defensive copy. The array's
210      * class must be Object[].class. This method is declared with a parameter type of
211      * Object... instead of E... so that a varargs call doesn't accidentally create an array
212      * of some class other than Object[].class.
213      *
214      * @param <E> the List's element type
215      * @param input the input array
216      * @return the new list
217      */
218     @SuppressWarnings("unchecked")
listFromTrustedArray(Object... input)219     static <E> List<E> listFromTrustedArray(Object... input) {
220         assert input.getClass() == Object[].class;
221         for (Object o : input) { // implicit null check of 'input' array
222             Objects.requireNonNull(o);
223         }
224 
225         return switch (input.length) {
226             case 0  -> (List<E>) ImmutableCollections.EMPTY_LIST;
227             case 1  -> (List<E>) new List12<>(input[0]);
228             case 2  -> (List<E>) new List12<>(input[0], input[1]);
229             default -> (List<E>) new ListN<>(input, false);
230         };
231     }
232 
233     /**
234      * Creates a new List from a trusted array, allowing null elements.
235      *
236      * <p>A trusted array has no references retained by the caller. It can therefore be
237      * safely reused as the List's internal storage, avoiding a defensive copy. The array's
238      * class must be Object[].class. This method is declared with a parameter type of
239      * Object... instead of E... so that a varargs call doesn't accidentally create an array
240      * of some class other than Object[].class.
241      *
242      * <p>Avoids creating a List12 instance, as it cannot accommodate null elements.
243      *
244      * @param <E> the List's element type
245      * @param input the input array
246      * @return the new list
247      */
248     @SuppressWarnings("unchecked")
listFromTrustedArrayNullsAllowed(Object... input)249     static <E> List<E> listFromTrustedArrayNullsAllowed(Object... input) {
250         assert input.getClass() == Object[].class;
251         if (input.length == 0) {
252             return (List<E>) EMPTY_LIST_NULLS;
253         } else {
254             return new ListN<>((E[])input, true);
255         }
256     }
257 
258     // ---------- List Implementations ----------
259 
260     @jdk.internal.ValueBased
261     abstract static class AbstractImmutableList<E> extends AbstractImmutableCollection<E>
262             implements List<E>, RandomAccess {
263 
264         // all mutating methods throw UnsupportedOperationException
add(int index, E element)265         @Override public void    add(int index, E element) { throw uoe(); }
addAll(int index, Collection<? extends E> c)266         @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
remove(int index)267         @Override public E       remove(int index) { throw uoe(); }
replaceAll(UnaryOperator<E> operator)268         @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
set(int index, E element)269         @Override public E       set(int index, E element) { throw uoe(); }
sort(Comparator<? super E> c)270         @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
271 
272         @Override
subList(int fromIndex, int toIndex)273         public List<E> subList(int fromIndex, int toIndex) {
274             int size = size();
275             subListRangeCheck(fromIndex, toIndex, size);
276             return SubList.fromList(this, fromIndex, toIndex);
277         }
278 
subListRangeCheck(int fromIndex, int toIndex, int size)279         static void subListRangeCheck(int fromIndex, int toIndex, int size) {
280             if (fromIndex < 0)
281                 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
282             if (toIndex > size)
283                 throw new IndexOutOfBoundsException("toIndex = " + toIndex);
284             if (fromIndex > toIndex)
285                 throw new IllegalArgumentException("fromIndex(" + fromIndex +
286                         ") > toIndex(" + toIndex + ")");
287         }
288 
289         @Override
iterator()290         public Iterator<E> iterator() {
291             return new ListItr<E>(this, size());
292         }
293 
294         @Override
listIterator()295         public ListIterator<E> listIterator() {
296             return listIterator(0);
297         }
298 
299         @Override
listIterator(final int index)300         public ListIterator<E> listIterator(final int index) {
301             int size = size();
302             if (index < 0 || index > size) {
303                 throw outOfBounds(index);
304             }
305             return new ListItr<E>(this, size, index);
306         }
307 
308         @Override
equals(Object o)309         public boolean equals(Object o) {
310             if (o == this) {
311                 return true;
312             }
313 
314             if (!(o instanceof List)) {
315                 return false;
316             }
317 
318             Iterator<?> oit = ((List<?>) o).iterator();
319             for (int i = 0, s = size(); i < s; i++) {
320                 if (!oit.hasNext() || !Objects.equals(get(i), oit.next())) {
321                     return false;
322                 }
323             }
324             return !oit.hasNext();
325         }
326 
327         @Override
hashCode()328         public int hashCode() {
329             int hash = 1;
330             for (int i = 0, s = size(); i < s; i++) {
331                 hash = 31 * hash + Objects.hashCode(get(i));
332             }
333             return hash;
334         }
335 
336         @Override
contains(Object o)337         public boolean contains(Object o) {
338             return indexOf(o) >= 0;
339         }
340 
341         @Override
reversed()342         public List<E> reversed() {
343             return ReverseOrderListView.of(this, false);
344         }
345 
outOfBounds(int index)346         IndexOutOfBoundsException outOfBounds(int index) {
347             return new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
348         }
349     }
350 
351     static final class ListItr<E> implements ListIterator<E> {
352 
353         @Stable
354         private final List<E> list;
355 
356         @Stable
357         private final int size;
358 
359         @Stable
360         private final boolean isListIterator;
361 
362         private int cursor;
363 
ListItr(List<E> list, int size)364         ListItr(List<E> list, int size) {
365             this.list = list;
366             this.size = size;
367             this.cursor = 0;
368             isListIterator = false;
369         }
370 
ListItr(List<E> list, int size, int index)371         ListItr(List<E> list, int size, int index) {
372             this.list = list;
373             this.size = size;
374             this.cursor = index;
375             isListIterator = true;
376         }
377 
hasNext()378         public boolean hasNext() {
379             return cursor != size;
380         }
381 
next()382         public E next() {
383             try {
384                 int i = cursor;
385                 E next = list.get(i);
386                 cursor = i + 1;
387                 return next;
388             } catch (IndexOutOfBoundsException e) {
389                 throw new NoSuchElementException();
390             }
391         }
392 
remove()393         public void remove() {
394             throw uoe();
395         }
396 
hasPrevious()397         public boolean hasPrevious() {
398             if (!isListIterator) {
399                 throw uoe();
400             }
401             return cursor != 0;
402         }
403 
previous()404         public E previous() {
405             if (!isListIterator) {
406                 throw uoe();
407             }
408             try {
409                 int i = cursor - 1;
410                 E previous = list.get(i);
411                 cursor = i;
412                 return previous;
413             } catch (IndexOutOfBoundsException e) {
414                 throw new NoSuchElementException();
415             }
416         }
417 
nextIndex()418         public int nextIndex() {
419             if (!isListIterator) {
420                 throw uoe();
421             }
422             return cursor;
423         }
424 
previousIndex()425         public int previousIndex() {
426             if (!isListIterator) {
427                 throw uoe();
428             }
429             return cursor - 1;
430         }
431 
set(E e)432         public void set(E e) {
433             throw uoe();
434         }
435 
add(E e)436         public void add(E e) {
437             throw uoe();
438         }
439     }
440 
441     static final class SubList<E> extends AbstractImmutableList<E>
442             implements RandomAccess {
443 
444         @Stable
445         private final AbstractImmutableList<E> root;
446 
447         @Stable
448         private final int offset;
449 
450         @Stable
451         private final int size;
452 
SubList(AbstractImmutableList<E> root, int offset, int size)453         private SubList(AbstractImmutableList<E> root, int offset, int size) {
454             assert root instanceof List12 || root instanceof ListN;
455             this.root = root;
456             this.offset = offset;
457             this.size = size;
458         }
459 
460         /**
461          * Constructs a sublist of another SubList.
462          */
fromSubList(SubList<E> parent, int fromIndex, int toIndex)463         static <E> SubList<E> fromSubList(SubList<E> parent, int fromIndex, int toIndex) {
464             return new SubList<>(parent.root, parent.offset + fromIndex, toIndex - fromIndex);
465         }
466 
467         /**
468          * Constructs a sublist of an arbitrary AbstractImmutableList, which is
469          * not a SubList itself.
470          */
fromList(AbstractImmutableList<E> list, int fromIndex, int toIndex)471         static <E> SubList<E> fromList(AbstractImmutableList<E> list, int fromIndex, int toIndex) {
472             return new SubList<>(list, fromIndex, toIndex - fromIndex);
473         }
474 
get(int index)475         public E get(int index) {
476             Objects.checkIndex(index, size);
477             return root.get(offset + index);
478         }
479 
size()480         public int size() {
481             return size;
482         }
483 
iterator()484         public Iterator<E> iterator() {
485             return new ListItr<>(this, size());
486         }
487 
listIterator(int index)488         public ListIterator<E> listIterator(int index) {
489             rangeCheck(index);
490             return new ListItr<>(this, size(), index);
491         }
492 
subList(int fromIndex, int toIndex)493         public List<E> subList(int fromIndex, int toIndex) {
494             subListRangeCheck(fromIndex, toIndex, size);
495             return SubList.fromSubList(this, fromIndex, toIndex);
496         }
497 
rangeCheck(int index)498         private void rangeCheck(int index) {
499             if (index < 0 || index > size) {
500                 throw outOfBounds(index);
501             }
502         }
503 
allowNulls()504         private boolean allowNulls() {
505             return root instanceof ListN && ((ListN<?>)root).allowNulls;
506         }
507 
508         @Override
indexOf(Object o)509         public int indexOf(Object o) {
510             if (!allowNulls() && o == null) {
511                 throw new NullPointerException();
512             }
513             for (int i = 0, s = size(); i < s; i++) {
514                 if (Objects.equals(o, get(i))) {
515                     return i;
516                 }
517             }
518             return -1;
519         }
520 
521         @Override
lastIndexOf(Object o)522         public int lastIndexOf(Object o) {
523             if (!allowNulls() && o == null) {
524                 throw new NullPointerException();
525             }
526             for (int i = size() - 1; i >= 0; i--) {
527                 if (Objects.equals(o, get(i))) {
528                     return i;
529                 }
530             }
531             return -1;
532         }
533 
534         @Override
toArray()535         public Object[] toArray() {
536             Object[] array = new Object[size];
537             for (int i = 0; i < size; i++) {
538                 array[i] = get(i);
539             }
540             return array;
541         }
542 
543         @Override
544         @SuppressWarnings("unchecked")
toArray(T[] a)545         public <T> T[] toArray(T[] a) {
546             T[] array = a.length >= size ? a :
547                     (T[])java.lang.reflect.Array
548                             .newInstance(a.getClass().getComponentType(), size);
549             for (int i = 0; i < size; i++) {
550                 array[i] = (T)get(i);
551             }
552             if (array.length > size) {
553                 array[size] = null; // null-terminate
554             }
555             return array;
556         }
557     }
558 
559     @jdk.internal.ValueBased
560     static final class List12<E> extends AbstractImmutableList<E>
561             implements Serializable {
562 
563         @Stable
564         private final E e0;
565 
566         @Stable
567         private final Object e1;
568 
List12(E e0)569         List12(E e0) {
570             this.e0 = Objects.requireNonNull(e0);
571             // Use EMPTY as a sentinel for an unused element: not using null
572             // enables constant folding optimizations over single-element lists
573             this.e1 = EMPTY;
574         }
575 
List12(E e0, E e1)576         List12(E e0, E e1) {
577             this.e0 = Objects.requireNonNull(e0);
578             this.e1 = Objects.requireNonNull(e1);
579         }
580 
581         @Override
size()582         public int size() {
583             return e1 != EMPTY ? 2 : 1;
584         }
585 
586         @Override
isEmpty()587         public boolean isEmpty() {
588             return false;
589         }
590 
591         @Override
592         @SuppressWarnings("unchecked")
get(int index)593         public E get(int index) {
594             if (index == 0) {
595                 return e0;
596             } else if (index == 1 && e1 != EMPTY) {
597                 return (E)e1;
598             }
599             throw outOfBounds(index);
600         }
601 
602         @Override
indexOf(Object o)603         public int indexOf(Object o) {
604             Objects.requireNonNull(o);
605             if (o.equals(e0)) {
606                 return 0;
607             } else if (e1 != EMPTY && o.equals(e1)) {
608                 return 1;
609             } else {
610                 return -1;
611             }
612         }
613 
614         @Override
lastIndexOf(Object o)615         public int lastIndexOf(Object o) {
616             Objects.requireNonNull(o);
617             if (e1 != EMPTY && o.equals(e1)) {
618                 return 1;
619             } else if (o.equals(e0)) {
620                 return 0;
621             } else {
622                 return -1;
623             }
624         }
625 
626         @java.io.Serial
readObject(ObjectInputStream in)627         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
628             throw new InvalidObjectException("not serial proxy");
629         }
630 
631         @java.io.Serial
writeReplace()632         private Object writeReplace() {
633             if (e1 == EMPTY) {
634                 return new CollSer(CollSer.IMM_LIST, e0);
635             } else {
636                 return new CollSer(CollSer.IMM_LIST, e0, e1);
637             }
638         }
639 
640         @Override
toArray()641         public Object[] toArray() {
642             if (e1 == EMPTY) {
643                 return new Object[] { e0 };
644             } else {
645                 return new Object[] { e0, e1 };
646             }
647         }
648 
649         @Override
650         @SuppressWarnings("unchecked")
toArray(T[] a)651         public <T> T[] toArray(T[] a) {
652             int size = size();
653             T[] array = a.length >= size ? a :
654                     (T[])Array.newInstance(a.getClass().getComponentType(), size);
655             array[0] = (T)e0;
656             if (size == 2) {
657                 array[1] = (T)e1;
658             }
659             if (array.length > size) {
660                 array[size] = null; // null-terminate
661             }
662             return array;
663         }
664     }
665 
666     @jdk.internal.ValueBased
667     static final class ListN<E> extends AbstractImmutableList<E>
668             implements Serializable {
669 
670         @Stable
671         private final E[] elements;
672 
673         @Stable
674         private final boolean allowNulls;
675 
676         // caller must ensure that elements has no nulls if allowNulls is false
ListN(E[] elements, boolean allowNulls)677         private ListN(E[] elements, boolean allowNulls) {
678             this.elements = elements;
679             this.allowNulls = allowNulls;
680         }
681 
682         @Override
isEmpty()683         public boolean isEmpty() {
684             return elements.length == 0;
685         }
686 
687         @Override
size()688         public int size() {
689             return elements.length;
690         }
691 
692         @Override
get(int index)693         public E get(int index) {
694             return elements[index];
695         }
696 
697         @java.io.Serial
readObject(ObjectInputStream in)698         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
699             throw new InvalidObjectException("not serial proxy");
700         }
701 
702         @java.io.Serial
writeReplace()703         private Object writeReplace() {
704             return new CollSer(allowNulls ? CollSer.IMM_LIST_NULLS : CollSer.IMM_LIST, elements);
705         }
706 
707         @Override
toArray()708         public Object[] toArray() {
709             return Arrays.copyOf(elements, elements.length);
710         }
711 
712         @Override
713         @SuppressWarnings("unchecked")
toArray(T[] a)714         public <T> T[] toArray(T[] a) {
715             int size = elements.length;
716             if (a.length < size) {
717                 // Make a new array of a's runtime type, but my contents:
718                 return (T[]) Arrays.copyOf(elements, size, a.getClass());
719             }
720             System.arraycopy(elements, 0, a, 0, size);
721             if (a.length > size) {
722                 a[size] = null; // null-terminate
723             }
724             return a;
725         }
726 
727         @Override
indexOf(Object o)728         public int indexOf(Object o) {
729             if (!allowNulls && o == null) {
730                 throw new NullPointerException();
731             }
732             Object[] es = elements;
733             for (int i = 0; i < es.length; i++) {
734                 if (Objects.equals(o, es[i])) {
735                     return i;
736                 }
737             }
738             return -1;
739         }
740 
741         @Override
lastIndexOf(Object o)742         public int lastIndexOf(Object o) {
743             if (!allowNulls && o == null) {
744                 throw new NullPointerException();
745             }
746             Object[] es = elements;
747             for (int i = es.length - 1; i >= 0; i--) {
748                 if (Objects.equals(o, es[i])) {
749                     return i;
750                 }
751             }
752             return -1;
753         }
754     }
755 
756     // ---------- Set Implementations ----------
757 
758     @jdk.internal.ValueBased
759     abstract static class AbstractImmutableSet<E> extends AbstractImmutableCollection<E>
760             implements Set<E> {
761 
762         @Override
equals(Object o)763         public boolean equals(Object o) {
764             if (o == this) {
765                 return true;
766             } else if (!(o instanceof Set)) {
767                 return false;
768             }
769 
770             Collection<?> c = (Collection<?>) o;
771             if (c.size() != size()) {
772                 return false;
773             }
774             for (Object e : c) {
775                 if (e == null || !contains(e)) {
776                     return false;
777                 }
778             }
779             return true;
780         }
781 
782         @Override
hashCode()783         public abstract int hashCode();
784     }
785 
786     @jdk.internal.ValueBased
787     static final class Set12<E> extends AbstractImmutableSet<E>
788             implements Serializable {
789 
790         @Stable
791         private final E e0;
792 
793         @Stable
794         private final Object e1;
795 
Set12(E e0)796         Set12(E e0) {
797             this.e0 = Objects.requireNonNull(e0);
798             // Use EMPTY as a sentinel for an unused element: not using null
799             // enable constant folding optimizations over single-element sets
800             this.e1 = EMPTY;
801         }
802 
Set12(E e0, E e1)803         Set12(E e0, E e1) {
804             if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
805                 throw new IllegalArgumentException("duplicate element: " + e0);
806             }
807 
808             this.e0 = e0;
809             this.e1 = e1;
810         }
811 
812         @Override
size()813         public int size() {
814             return (e1 == EMPTY) ? 1 : 2;
815         }
816 
817         @Override
isEmpty()818         public boolean isEmpty() {
819             return false;
820         }
821 
822         @Override
contains(Object o)823         public boolean contains(Object o) {
824             return o.equals(e0) || e1.equals(o); // implicit nullcheck of o
825         }
826 
827         @Override
hashCode()828         public int hashCode() {
829             return e0.hashCode() + (e1 == EMPTY ? 0 : e1.hashCode());
830         }
831 
832         @Override
iterator()833         public Iterator<E> iterator() {
834             return new Iterator<>() {
835                 private int idx = (e1 == EMPTY) ? 1 : 2;
836 
837                 @Override
838                 public boolean hasNext() {
839                     return idx > 0;
840                 }
841 
842                 @Override
843                 @SuppressWarnings("unchecked")
844                 public E next() {
845                     if (idx == 1) {
846                         idx = 0;
847                         return (REVERSE || e1 == EMPTY) ? e0 : (E)e1;
848                     } else if (idx == 2) {
849                         idx = 1;
850                         return REVERSE ? (E)e1 : e0;
851                     } else {
852                         throw new NoSuchElementException();
853                     }
854                 }
855             };
856         }
857 
858         @java.io.Serial
readObject(ObjectInputStream in)859         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
860             throw new InvalidObjectException("not serial proxy");
861         }
862 
863         @java.io.Serial
writeReplace()864         private Object writeReplace() {
865             if (e1 == EMPTY) {
866                 return new CollSer(CollSer.IMM_SET, e0);
867             } else {
868                 return new CollSer(CollSer.IMM_SET, e0, e1);
869             }
870         }
871 
872         @Override
toArray()873         public Object[] toArray() {
874             if (e1 == EMPTY) {
875                 return new Object[] { e0 };
876             } else if (REVERSE) {
877                 return new Object[] { e1, e0 };
878             } else {
879                 return new Object[] { e0, e1 };
880             }
881         }
882 
883         @Override
884         @SuppressWarnings("unchecked")
toArray(T[] a)885         public <T> T[] toArray(T[] a) {
886             int size = size();
887             T[] array = a.length >= size ? a :
888                     (T[])Array.newInstance(a.getClass().getComponentType(), size);
889             if (size == 1) {
890                 array[0] = (T)e0;
891             } else if (REVERSE) {
892                 array[0] = (T)e1;
893                 array[1] = (T)e0;
894             } else {
895                 array[0] = (T)e0;
896                 array[1] = (T)e1;
897             }
898             if (array.length > size) {
899                 array[size] = null; // null-terminate
900             }
901             return array;
902         }
903     }
904 
905 
906     /**
907      * An array-based Set implementation. The element array must be strictly
908      * larger than the size (the number of contained elements) so that at
909      * least one null is always present.
910      * @param <E> the element type
911      */
912     @jdk.internal.ValueBased
913     static final class SetN<E> extends AbstractImmutableSet<E>
914             implements Serializable {
915 
916         @Stable
917         final E[] elements;
918 
919         @Stable
920         final int size;
921 
922         @SafeVarargs
923         @SuppressWarnings("unchecked")
924         SetN(E... input) {
925             size = input.length; // implicit nullcheck of input
926 
927             elements = (E[])new Object[EXPAND_FACTOR * input.length];
928             for (int i = 0; i < input.length; i++) {
929                 E e = input[i];
930                 int idx = probe(e); // implicit nullcheck of e
931                 if (idx >= 0) {
932                     throw new IllegalArgumentException("duplicate element: " + e);
933                 } else {
934                     elements[-(idx + 1)] = e;
935                 }
936             }
937         }
938 
939         @Override
940         public int size() {
941             return size;
942         }
943 
944         @Override
945         public boolean isEmpty() {
946             return size == 0;
947         }
948 
949         @Override
950         public boolean contains(Object o) {
951             Objects.requireNonNull(o);
952             return size > 0 && probe(o) >= 0;
953         }
954 
955         private final class SetNIterator implements Iterator<E> {
956 
957             private int remaining;
958 
959             private int idx;
960 
961             SetNIterator() {
962                 remaining = size;
963                 // pick a starting index in the [0 .. element.length-1] range
964                 // randomly based on SALT32L
965                 idx = (int) ((SALT32L * elements.length) >>> 32);
966             }
967 
968             @Override
969             public boolean hasNext() {
970                 return remaining > 0;
971             }
972 
973             @Override
974             public E next() {
975                 if (remaining > 0) {
976                     E element;
977                     int idx = this.idx;
978                     int len = elements.length;
979                     // step to the next element; skip null elements
980                     do {
981                         if (REVERSE) {
982                             if (++idx >= len) {
983                                 idx = 0;
984                             }
985                         } else {
986                             if (--idx < 0) {
987                                 idx = len - 1;
988                             }
989                         }
990                     } while ((element = elements[idx]) == null);
991                     this.idx = idx;
992                     remaining--;
993                     return element;
994                 } else {
995                     throw new NoSuchElementException();
996                 }
997             }
998         }
999 
1000         @Override
1001         public Iterator<E> iterator() {
1002             return new SetNIterator();
1003         }
1004 
1005         @Override
1006         public int hashCode() {
1007             int h = 0;
1008             for (E e : elements) {
1009                 if (e != null) {
1010                     h += e.hashCode();
1011                 }
1012             }
1013             return h;
1014         }
1015 
1016         // returns index at which element is present; or if absent,
1017         // (-i - 1) where i is location where element should be inserted.
1018         // Callers are relying on this method to perform an implicit nullcheck
1019         // of pe
1020         private int probe(Object pe) {
1021             int idx = Math.floorMod(pe.hashCode(), elements.length);
1022             while (true) {
1023                 E ee = elements[idx];
1024                 if (ee == null) {
1025                     return -idx - 1;
1026                 } else if (pe.equals(ee)) {
1027                     return idx;
1028                 } else if (++idx == elements.length) {
1029                     idx = 0;
1030                 }
1031             }
1032         }
1033 
1034         @java.io.Serial
1035         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1036             throw new InvalidObjectException("not serial proxy");
1037         }
1038 
1039         @java.io.Serial
1040         private Object writeReplace() {
1041             Object[] array = new Object[size];
1042             int dest = 0;
1043             for (Object o : elements) {
1044                 if (o != null) {
1045                     array[dest++] = o;
1046                 }
1047             }
1048             return new CollSer(CollSer.IMM_SET, array);
1049         }
1050 
1051         @Override
1052         public Object[] toArray() {
1053             Object[] array = new Object[size];
1054             Iterator<E> it = iterator();
1055             for (int i = 0; i < size; i++) {
1056                 array[i] = it.next();
1057             }
1058             return array;
1059         }
1060 
1061         @Override
1062         @SuppressWarnings("unchecked")
1063         public <T> T[] toArray(T[] a) {
1064             T[] array = a.length >= size ? a :
1065                     (T[])Array.newInstance(a.getClass().getComponentType(), size);
1066             Iterator<E> it = iterator();
1067             for (int i = 0; i < size; i++) {
1068                 array[i] = (T)it.next();
1069             }
1070             if (array.length > size) {
1071                 array[size] = null; // null-terminate
1072             }
1073             return array;
1074         }
1075     }
1076 
1077     // ---------- Map Implementations ----------
1078 
1079     // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap
1080     abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
1081         @Override public void clear() { throw uoe(); }
1082         @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
1083         @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
1084         @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
1085         @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
1086         @Override public V put(K key, V value) { throw uoe(); }
1087         @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
1088         @Override public V putIfAbsent(K key, V value) { throw uoe(); }
1089         @Override public V remove(Object key) { throw uoe(); }
1090         @Override public boolean remove(Object key, Object value) { throw uoe(); }
1091         @Override public V replace(K key, V value) { throw uoe(); }
1092         @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
1093         @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
1094 
1095         /**
1096          * @implNote {@code null} values are disallowed in these immutable maps,
1097          * so we can improve upon the default implementation since a
1098          * {@code null} return from {@code get(key)} always means the default
1099          * value should be returned.
1100          */
1101         @Override
1102         public V getOrDefault(Object key, V defaultValue) {
1103             V v;
1104             return ((v = get(key)) != null)
1105                     ? v
1106                     : defaultValue;
1107         }
1108     }
1109 
1110     // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap
1111     static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
1112         @Stable
1113         private final K k0;
1114         @Stable
1115         private final V v0;
1116 
1117         Map1(K k0, V v0) {
1118             this.k0 = Objects.requireNonNull(k0);
1119             this.v0 = Objects.requireNonNull(v0);
1120         }
1121 
1122         @Override
1123         public Set<Map.Entry<K,V>> entrySet() {
1124             return Set.of(new KeyValueHolder<>(k0, v0));
1125         }
1126 
1127         @Override
1128         public V get(Object o) {
1129             return o.equals(k0) ? v0 : null; // implicit nullcheck of o
1130         }
1131 
1132         @Override
1133         public boolean containsKey(Object o) {
1134             return o.equals(k0); // implicit nullcheck of o
1135         }
1136 
1137         @Override
1138         public boolean containsValue(Object o) {
1139             return o.equals(v0); // implicit nullcheck of o
1140         }
1141 
1142         @Override
1143         public int size() {
1144             return 1;
1145         }
1146 
1147         @Override
1148         public boolean isEmpty() {
1149             return false;
1150         }
1151 
1152         @java.io.Serial
1153         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1154             throw new InvalidObjectException("not serial proxy");
1155         }
1156 
1157         @java.io.Serial
1158         private Object writeReplace() {
1159             return new CollSer(CollSer.IMM_MAP, k0, v0);
1160         }
1161 
1162         @Override
1163         public int hashCode() {
1164             return k0.hashCode() ^ v0.hashCode();
1165         }
1166     }
1167 
1168     /**
1169      * An array-based Map implementation. There is a single array "table" that
1170      * contains keys and values interleaved: table[0] is kA, table[1] is vA,
1171      * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
1172      * also be strictly larger than the size (the number of key-value pairs contained
1173      * in the map) so that at least one null key is always present.
1174      * @param <K> the key type
1175      * @param <V> the value type
1176      */
1177     // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap
1178     static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
1179 
1180         @Stable
1181         final Object[] table; // pairs of key, value
1182 
1183         @Stable
1184         final int size; // number of pairs
1185 
1186         MapN(Object... input) {
1187             if ((input.length & 1) != 0) { // implicit nullcheck of input
1188                 throw new InternalError("length is odd");
1189             }
1190             size = input.length >> 1;
1191 
1192             int len = EXPAND_FACTOR * input.length;
1193             len = (len + 1) & ~1; // ensure table is even length
1194             table = new Object[len];
1195 
1196             for (int i = 0; i < input.length; i += 2) {
1197                 @SuppressWarnings("unchecked")
1198                     K k = Objects.requireNonNull((K)input[i]);
1199                 @SuppressWarnings("unchecked")
1200                     V v = Objects.requireNonNull((V)input[i+1]);
1201                 int idx = probe(k);
1202                 if (idx >= 0) {
1203                     throw new IllegalArgumentException("duplicate key: " + k);
1204                 } else {
1205                     int dest = -(idx + 1);
1206                     table[dest] = k;
1207                     table[dest+1] = v;
1208                 }
1209             }
1210         }
1211 
1212         @Override
1213         public boolean containsKey(Object o) {
1214             Objects.requireNonNull(o);
1215             return size > 0 && probe(o) >= 0;
1216         }
1217 
1218         @Override
1219         public boolean containsValue(Object o) {
1220             Objects.requireNonNull(o);
1221             for (int i = 1; i < table.length; i += 2) {
1222                 Object v = table[i];
1223                 if (v != null && o.equals(v)) {
1224                     return true;
1225                 }
1226             }
1227             return false;
1228         }
1229 
1230         @Override
1231         public int hashCode() {
1232             int hash = 0;
1233             for (int i = 0; i < table.length; i += 2) {
1234                 Object k = table[i];
1235                 if (k != null) {
1236                     hash += k.hashCode() ^ table[i + 1].hashCode();
1237                 }
1238             }
1239             return hash;
1240         }
1241 
1242         @Override
1243         @SuppressWarnings("unchecked")
1244         public V get(Object o) {
1245             if (size == 0) {
1246                 Objects.requireNonNull(o);
1247                 return null;
1248             }
1249             int i = probe(o);
1250             if (i >= 0) {
1251                 return (V)table[i+1];
1252             } else {
1253                 return null;
1254             }
1255         }
1256 
1257         @Override
1258         public int size() {
1259             return size;
1260         }
1261 
1262         @Override
1263         public boolean isEmpty() {
1264             return size == 0;
1265         }
1266 
1267         class MapNIterator implements Iterator<Map.Entry<K,V>> {
1268 
1269             private int remaining;
1270 
1271             private int idx;
1272 
1273             MapNIterator() {
1274                 remaining = size;
1275                 // pick an even starting index in the [0 .. table.length-1]
1276                 // range randomly based on SALT32L
1277                 idx = (int) ((SALT32L * (table.length >> 1)) >>> 32) << 1;
1278             }
1279 
1280             @Override
1281             public boolean hasNext() {
1282                 return remaining > 0;
1283             }
1284 
1285             private int nextIndex() {
1286                 int idx = this.idx;
1287                 if (REVERSE) {
1288                     if ((idx += 2) >= table.length) {
1289                         idx = 0;
1290                     }
1291                 } else {
1292                     if ((idx -= 2) < 0) {
1293                         idx = table.length - 2;
1294                     }
1295                 }
1296                 return this.idx = idx;
1297             }
1298 
1299             @Override
1300             public Map.Entry<K,V> next() {
1301                 if (remaining > 0) {
1302                     int idx;
1303                     while (table[idx = nextIndex()] == null) {}
1304                     @SuppressWarnings("unchecked")
1305                     Map.Entry<K,V> e =
1306                             new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
1307                     remaining--;
1308                     return e;
1309                 } else {
1310                     throw new NoSuchElementException();
1311                 }
1312             }
1313         }
1314 
1315         @Override
1316         public Set<Map.Entry<K,V>> entrySet() {
1317             return new AbstractSet<>() {
1318                 @Override
1319                 public int size() {
1320                     return MapN.this.size;
1321                 }
1322 
1323                 @Override
1324                 public Iterator<Map.Entry<K,V>> iterator() {
1325                     return new MapNIterator();
1326                 }
1327 
1328                 // Android-added: AbstractCollection#clear implementation is no-op when
1329                 // collection is empty. Overriding this method to make Map.of().clear()
1330                 // and Map.of().entrySet().clear() behaviour equal.
1331                 @Override
1332                 public void clear() {
1333                     throw uoe();
1334                 }
1335             };
1336         }
1337 
1338         // returns index at which the probe key is present; or if absent,
1339         // (-i - 1) where i is location where element should be inserted.
1340         // Callers are relying on this method to perform an implicit nullcheck
1341         // of pk.
1342         private int probe(Object pk) {
1343             int idx = Math.floorMod(pk.hashCode(), table.length >> 1) << 1;
1344             while (true) {
1345                 @SuppressWarnings("unchecked")
1346                 K ek = (K)table[idx];
1347                 if (ek == null) {
1348                     return -idx - 1;
1349                 } else if (pk.equals(ek)) {
1350                     return idx;
1351                 } else if ((idx += 2) == table.length) {
1352                     idx = 0;
1353                 }
1354             }
1355         }
1356 
1357         @java.io.Serial
1358         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1359             throw new InvalidObjectException("not serial proxy");
1360         }
1361 
1362         @java.io.Serial
1363         private Object writeReplace() {
1364             Object[] array = new Object[2 * size];
1365             int len = table.length;
1366             int dest = 0;
1367             for (int i = 0; i < len; i += 2) {
1368                 if (table[i] != null) {
1369                     array[dest++] = table[i];
1370                     array[dest++] = table[i+1];
1371                 }
1372             }
1373             return new CollSer(CollSer.IMM_MAP, array);
1374         }
1375     }
1376 }
1377 
1378 // ---------- Serialization Proxy ----------
1379 
1380 /**
1381  * A unified serialization proxy class for the immutable collections.
1382  *
1383  * @serial
1384  * @since 9
1385  */
1386 final class CollSer implements Serializable {
1387     @java.io.Serial
1388     private static final long serialVersionUID = 6309168927139932177L;
1389 
1390     static final int IMM_LIST       = 1;
1391     static final int IMM_SET        = 2;
1392     static final int IMM_MAP        = 3;
1393     static final int IMM_LIST_NULLS = 4;
1394 
1395     /**
1396      * Indicates the type of collection that is serialized.
1397      * The low order 8 bits have the value 1 for an immutable
1398      * {@code List}, 2 for an immutable {@code Set}, 3 for
1399      * an immutable {@code Map}, and 4 for an immutable
1400      * {@code List} that allows null elements.
1401      *
1402      * Any other value causes an
1403      * {@link InvalidObjectException} to be thrown. The high
1404      * order 24 bits are zero when an instance is serialized,
1405      * and they are ignored when an instance is deserialized.
1406      * They can thus be used by future implementations without
1407      * causing compatibility issues.
1408      *
1409      * <p>The tag value also determines the interpretation of the
1410      * transient {@code Object[] array} field.
1411      * For {@code List} and {@code Set}, the array's length is the size
1412      * of the collection, and the array contains the elements of the collection.
1413      * Null elements are not allowed. For {@code Set}, duplicate elements
1414      * are not allowed.
1415      *
1416      * <p>For {@code Map}, the array's length is twice the number of mappings
1417      * present in the map. The array length is necessarily even.
1418      * The array contains a succession of key and value pairs:
1419      * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed,
1420      * and duplicate keys are not allowed.
1421      *
1422      * @serial
1423      * @since 9
1424      */
1425     private final int tag;
1426 
1427     /**
1428      * @serial
1429      * @since 9
1430      */
1431     private transient Object[] array;
1432 
1433     CollSer(int t, Object... a) {
1434         tag = t;
1435         array = a;
1436     }
1437 
1438     /**
1439      * Reads objects from the stream and stores them
1440      * in the transient {@code Object[] array} field.
1441      *
1442      * @serialData
1443      * A nonnegative int, indicating the count of objects,
1444      * followed by that many objects.
1445      *
1446      * @param ois the ObjectInputStream from which data is read
1447      * @throws IOException if an I/O error occurs
1448      * @throws ClassNotFoundException if a serialized class cannot be loaded
1449      * @throws InvalidObjectException if the count is negative
1450      * @since 9
1451      */
1452     @java.io.Serial
1453     private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1454         ois.defaultReadObject();
1455         int len = ois.readInt();
1456 
1457         if (len < 0) {
1458             throw new InvalidObjectException("negative length " + len);
1459         }
1460 
1461         SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, len);
1462         Object[] a = new Object[len];
1463         for (int i = 0; i < len; i++) {
1464             a[i] = ois.readObject();
1465         }
1466 
1467         array = a;
1468     }
1469 
1470     /**
1471      * Writes objects to the stream from
1472      * the transient {@code Object[] array} field.
1473      *
1474      * @serialData
1475      * A nonnegative int, indicating the count of objects,
1476      * followed by that many objects.
1477      *
1478      * @param oos the ObjectOutputStream to which data is written
1479      * @throws IOException if an I/O error occurs
1480      * @since 9
1481      */
1482     @java.io.Serial
1483     private void writeObject(ObjectOutputStream oos) throws IOException {
1484         oos.defaultWriteObject();
1485         oos.writeInt(array.length);
1486         for (int i = 0; i < array.length; i++) {
1487             oos.writeObject(array[i]);
1488         }
1489     }
1490 
1491     /**
1492      * Creates and returns an immutable collection from this proxy class.
1493      * The instance returned is created as if by calling one of the
1494      * static factory methods for
1495      * <a href="List.html#unmodifiable">List</a>,
1496      * <a href="Map.html#unmodifiable">Map</a>, or
1497      * <a href="Set.html#unmodifiable">Set</a>.
1498      * This proxy class is the serial form for all immutable collection instances,
1499      * regardless of implementation type. This is necessary to ensure that the
1500      * existence of any particular implementation type is kept out of the
1501      * serialized form.
1502      *
1503      * @return a collection created from this proxy object
1504      * @throws InvalidObjectException if the tag value is illegal or if an exception
1505      *         is thrown during creation of the collection
1506      * @throws ObjectStreamException if another serialization error has occurred
1507      * @since 9
1508      */
1509     @java.io.Serial
1510     private Object readResolve() throws ObjectStreamException {
1511         try {
1512             if (array == null) {
1513                 throw new InvalidObjectException("null array");
1514             }
1515 
1516             // use low order 8 bits to indicate "kind"
1517             // ignore high order 24 bits
1518             switch (tag & 0xff) {
1519                 case IMM_LIST:
1520                     return List.of(array);
1521                 case IMM_LIST_NULLS:
1522                     return ImmutableCollections.listFromTrustedArrayNullsAllowed(
1523                             Arrays.copyOf(array, array.length, Object[].class));
1524                 case IMM_SET:
1525                     return Set.of(array);
1526                 case IMM_MAP:
1527                     if (array.length == 0) {
1528                         return ImmutableCollections.EMPTY_MAP;
1529                     } else if (array.length == 2) {
1530                         return new ImmutableCollections.Map1<>(array[0], array[1]);
1531                     } else {
1532                         return new ImmutableCollections.MapN<>(array);
1533                     }
1534                 default:
1535                     throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
1536             }
1537         } catch (NullPointerException|IllegalArgumentException ex) {
1538             InvalidObjectException ioe = new InvalidObjectException("invalid object");
1539             ioe.initCause(ex);
1540             throw ioe;
1541         }
1542     }
1543 }
1544