1 /*
   2  * Copyright (c) 2016, 2019, 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.SharedSecrets;
  40 import jdk.internal.misc.VM;
  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     static final int SALT;
  59     static {
  60         long nt = System.nanoTime();
  61         SALT = (int)((nt >>> 32) ^ nt);
  62     }
  63 
  64     /** No instances. */
  65     private ImmutableCollections() { }
  66 
  67     /**
  68      * The reciprocal of load factor. Given a number of elements
  69      * to store, multiply by this factor to get the table size.
  70      */
  71     static final int EXPAND_FACTOR = 2;
  72 
  73     static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
  74 
  75     static abstract class AbstractImmutableCollection<E> extends AbstractCollection<E> {
  76         // all mutating methods throw UnsupportedOperationException
  77         @Override public boolean add(E e) { throw uoe(); }
  78         @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
  79         @Override public void    clear() { throw uoe(); }
  80         @Override public boolean remove(Object o) { throw uoe(); }
  81         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
  82         @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
  83         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
  84     }
  85 
  86     // ---------- List Implementations ----------
  87 
  88     // make a copy, short-circuiting based on implementation class
  89     @SuppressWarnings("unchecked")
  90     static <E> List<E> listCopy(Collection<? extends E> coll) {
  91         if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
  92             return (List<E>)coll;
  93         } else {
  94             return (List<E>)List.of(coll.toArray());
  95         }
  96     }
  97 
  98     static abstract class AbstractImmutableList<E> extends AbstractImmutableCollection<E>
  99             implements List<E>, RandomAccess {
 100 
 101         // all mutating methods throw UnsupportedOperationException
 102         @Override public void    add(int index, E element) { throw uoe(); }
 103         @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
 104         @Override public E       remove(int index) { throw uoe(); }
 105         @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
 106         @Override public E       set(int index, E element) { throw uoe(); }
 107         @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
 108 
 109         @Override
 110         public List<E> subList(int fromIndex, int toIndex) {
 111             int size = size();
 112             subListRangeCheck(fromIndex, toIndex, size);
 113             return SubList.fromList(this, fromIndex, toIndex);
 114         }
 115 
 116         static void subListRangeCheck(int fromIndex, int toIndex, int size) {
 117             if (fromIndex < 0)
 118                 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
 119             if (toIndex > size)
 120                 throw new IndexOutOfBoundsException("toIndex = " + toIndex);
 121             if (fromIndex > toIndex)
 122                 throw new IllegalArgumentException("fromIndex(" + fromIndex +
 123                         ") > toIndex(" + toIndex + ")");
 124         }
 125 
 126         @Override
 127         public Iterator<E> iterator() {
 128             return new ListItr<E>(this, size());
 129         }
 130 
 131         @Override
 132         public ListIterator<E> listIterator() {
 133             return listIterator(0);
 134         }
 135 
 136         @Override
 137         public ListIterator<E> listIterator(final int index) {
 138             int size = size();
 139             if (index < 0 || index > size) {
 140                 throw outOfBounds(index);
 141             }
 142             return new ListItr<E>(this, size, index);
 143         }
 144 
 145         @Override
 146         public boolean equals(Object o) {
 147             if (o == this) {
 148                 return true;
 149             }
 150 
 151             if (!(o instanceof List)) {
 152                 return false;
 153             }
 154 
 155             Iterator<?> oit = ((List<?>) o).iterator();
 156             for (int i = 0, s = size(); i < s; i++) {
 157                 if (!oit.hasNext() || !get(i).equals(oit.next())) {
 158                     return false;
 159                 }
 160             }
 161             return !oit.hasNext();
 162         }
 163 
 164         @Override
 165         public int indexOf(Object o) {
 166             Objects.requireNonNull(o);
 167             for (int i = 0, s = size(); i < s; i++) {
 168                 if (o.equals(get(i))) {
 169                     return i;
 170                 }
 171             }
 172             return -1;
 173         }
 174 
 175         @Override
 176         public int lastIndexOf(Object o) {
 177             Objects.requireNonNull(o);
 178             for (int i = size() - 1; i >= 0; i--) {
 179                 if (o.equals(get(i))) {
 180                     return i;
 181                 }
 182             }
 183             return -1;
 184         }
 185 
 186         @Override
 187         public int hashCode() {
 188             int hash = 1;
 189             for (int i = 0, s = size(); i < s; i++) {
 190                 hash = 31 * hash + get(i).hashCode();
 191             }
 192             return hash;
 193         }
 194 
 195         @Override
 196         public boolean contains(Object o) {
 197             return indexOf(o) >= 0;
 198         }
 199 
 200         IndexOutOfBoundsException outOfBounds(int index) {
 201             return new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 202         }
 203     }
 204 
 205     static final class ListItr<E> implements ListIterator<E> {
 206 
 207         @Stable
 208         private final List<E> list;
 209 
 210         @Stable
 211         private final int size;
 212 
 213         @Stable
 214         private final boolean isListIterator;
 215 
 216         private int cursor;
 217 
 218         ListItr(List<E> list, int size) {
 219             this.list = list;
 220             this.size = size;
 221             this.cursor = 0;
 222             isListIterator = false;
 223         }
 224 
 225         ListItr(List<E> list, int size, int index) {
 226             this.list = list;
 227             this.size = size;
 228             this.cursor = index;
 229             isListIterator = true;
 230         }
 231 
 232         public boolean hasNext() {
 233             return cursor != size;
 234         }
 235 
 236         public E next() {
 237             try {
 238                 int i = cursor;
 239                 E next = list.get(i);
 240                 cursor = i + 1;
 241                 return next;
 242             } catch (IndexOutOfBoundsException e) {
 243                 throw new NoSuchElementException();
 244             }
 245         }
 246 
 247         public void remove() {
 248             throw uoe();
 249         }
 250 
 251         public boolean hasPrevious() {
 252             if (!isListIterator) {
 253                 throw uoe();
 254             }
 255             return cursor != 0;
 256         }
 257 
 258         public E previous() {
 259             if (!isListIterator) {
 260                 throw uoe();
 261             }
 262             try {
 263                 int i = cursor - 1;
 264                 E previous = list.get(i);
 265                 cursor = i;
 266                 return previous;
 267             } catch (IndexOutOfBoundsException e) {
 268                 throw new NoSuchElementException();
 269             }
 270         }
 271 
 272         public int nextIndex() {
 273             if (!isListIterator) {
 274                 throw uoe();
 275             }
 276             return cursor;
 277         }
 278 
 279         public int previousIndex() {
 280             if (!isListIterator) {
 281                 throw uoe();
 282             }
 283             return cursor - 1;
 284         }
 285 
 286         public void set(E e) {
 287             throw uoe();
 288         }
 289 
 290         public void add(E e) {
 291             throw uoe();
 292         }
 293     }
 294 
 295     static final class SubList<E> extends AbstractImmutableList<E>
 296             implements RandomAccess {
 297 
 298         @Stable
 299         private final List<E> root;
 300 
 301         @Stable
 302         private final int offset;
 303 
 304         @Stable
 305         private final int size;
 306 
 307         private SubList(List<E> root, int offset, int size) {
 308             this.root = root;
 309             this.offset = offset;
 310             this.size = size;
 311         }
 312 
 313         /**
 314          * Constructs a sublist of another SubList.
 315          */
 316         static <E> SubList<E> fromSubList(SubList<E> parent, int fromIndex, int toIndex) {
 317             return new SubList<>(parent.root, parent.offset + fromIndex, toIndex - fromIndex);
 318         }
 319 
 320         /**
 321          * Constructs a sublist of an arbitrary AbstractImmutableList, which is
 322          * not a SubList itself.
 323          */
 324         static <E> SubList<E> fromList(List<E> list, int fromIndex, int toIndex) {
 325             return new SubList<>(list, fromIndex, toIndex - fromIndex);
 326         }
 327 
 328         public E get(int index) {
 329             Objects.checkIndex(index, size);
 330             return root.get(offset + index);
 331         }
 332 
 333         public int size() {
 334             return size;
 335         }
 336 
 337         public Iterator<E> iterator() {
 338             return new ListItr<>(this, size());
 339         }
 340 
 341         public ListIterator<E> listIterator(int index) {
 342             rangeCheck(index);
 343             return new ListItr<>(this, size(), index);
 344         }
 345 
 346         public List<E> subList(int fromIndex, int toIndex) {
 347             subListRangeCheck(fromIndex, toIndex, size);
 348             return SubList.fromSubList(this, fromIndex, toIndex);
 349         }
 350 
 351         private void rangeCheck(int index) {
 352             if (index < 0 || index > size) {
 353                 throw outOfBounds(index);
 354             }
 355         }
 356 
 357         @Override
 358         public Object[] toArray() {
 359             Object[] array = new Object[size];
 360             for (int i = 0; i < size; i++) {
 361                 array[i] = get(i);
 362             }
 363             return array;
 364         }
 365 
 366         @Override
 367         @SuppressWarnings("unchecked")
 368         public <T> T[] toArray(T[] a) {
 369             T[] array = a.length >= size ? a :
 370                     (T[])java.lang.reflect.Array
 371                             .newInstance(a.getClass().getComponentType(), size);
 372             for (int i = 0; i < size; i++) {
 373                 array[i] = (T)get(i);
 374             }
 375             if (array.length > size) {
 376                 array[size] = null; // null-terminate
 377             }
 378             return array;
 379         }
 380     }
 381 
 382     static final class List12<E> extends AbstractImmutableList<E>
 383             implements Serializable {
 384 
 385         @Stable
 386         private final E e0;
 387 
 388         @Stable
 389         private final E e1;
 390 
 391         List12(E e0) {
 392             this.e0 = Objects.requireNonNull(e0);
 393             this.e1 = null;
 394         }
 395 
 396         List12(E e0, E e1) {
 397             this.e0 = Objects.requireNonNull(e0);
 398             this.e1 = Objects.requireNonNull(e1);
 399         }
 400 
 401         @Override
 402         public int size() {
 403             return e1 != null ? 2 : 1;
 404         }
 405 
 406         @Override
 407         public boolean isEmpty() {
 408             return false;
 409         }
 410 
 411         @Override
 412         public E get(int index) {
 413             if (index == 0) {
 414                 return e0;
 415             } else if (index == 1 && e1 != null) {
 416                 return e1;
 417             }
 418             throw outOfBounds(index);
 419         }
 420 
 421         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 422             throw new InvalidObjectException("not serial proxy");
 423         }
 424 
 425         private Object writeReplace() {
 426             if (e1 == null) {
 427                 return new CollSer(CollSer.IMM_LIST, e0);
 428             } else {
 429                 return new CollSer(CollSer.IMM_LIST, e0, e1);
 430             }
 431         }
 432 
 433         @Override
 434         public Object[] toArray() {
 435             if (e1 == null) {
 436                 return new Object[] { e0 };
 437             } else {
 438                 return new Object[] { e0, e1 };
 439             }
 440         }
 441 
 442         @Override
 443         @SuppressWarnings("unchecked")
 444         public <T> T[] toArray(T[] a) {
 445             int size = e1 == null ? 1 : 2;
 446             T[] array = a.length >= size ? a :
 447                     (T[])Array.newInstance(a.getClass().getComponentType(), size);
 448             array[0] = (T)e0;
 449             if (size == 2) {
 450                 array[1] = (T)e1;
 451             }
 452             if (array.length > size) {
 453                 array[size] = null; // null-terminate
 454             }
 455             return array;
 456         }
 457     }
 458 
 459     static final class ListN<E> extends AbstractImmutableList<E>
 460             implements Serializable {
 461 
 462         // EMPTY_LIST may be initialized from the CDS archive.
 463         static @Stable List<?> EMPTY_LIST;
 464 
 465         static {
 466             VM.initializeFromArchive(ListN.class);
 467             if (EMPTY_LIST == null) {
 468                 EMPTY_LIST = new ListN<>();
 469             }
 470         }
 471 
 472         @Stable
 473         private final E[] elements;
 474 
 475         @SafeVarargs
 476         ListN(E... input) {
 477             // copy and check manually to avoid TOCTOU
 478             @SuppressWarnings("unchecked")
 479             E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
 480             for (int i = 0; i < input.length; i++) {
 481                 tmp[i] = Objects.requireNonNull(input[i]);
 482             }
 483             elements = tmp;
 484         }
 485 
 486         @Override
 487         public boolean isEmpty() {
 488             return elements.length == 0;
 489         }
 490 
 491         @Override
 492         public int size() {
 493             return elements.length;
 494         }
 495 
 496         @Override
 497         public E get(int index) {
 498             return elements[index];
 499         }
 500 
 501         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 502             throw new InvalidObjectException("not serial proxy");
 503         }
 504 
 505         private Object writeReplace() {
 506             return new CollSer(CollSer.IMM_LIST, elements);
 507         }
 508 
 509         @Override
 510         public Object[] toArray() {
 511             return Arrays.copyOf(elements, elements.length);
 512         }
 513 
 514         @Override
 515         @SuppressWarnings("unchecked")
 516         public <T> T[] toArray(T[] a) {
 517             int size = elements.length;
 518             if (a.length < size) {
 519                 // Make a new array of a's runtime type, but my contents:
 520                 return (T[]) Arrays.copyOf(elements, size, a.getClass());
 521             }
 522             System.arraycopy(elements, 0, a, 0, size);
 523             if (a.length > size) {
 524                 a[size] = null; // null-terminate
 525             }
 526             return a;
 527         }
 528     }
 529 
 530     // ---------- Set Implementations ----------
 531 
 532     static abstract class AbstractImmutableSet<E> extends AbstractImmutableCollection<E>
 533             implements Set<E> {
 534 
 535         @Override
 536         public boolean equals(Object o) {
 537             if (o == this) {
 538                 return true;
 539             } else if (!(o instanceof Set)) {
 540                 return false;
 541             }
 542 
 543             Collection<?> c = (Collection<?>) o;
 544             if (c.size() != size()) {
 545                 return false;
 546             }
 547             for (Object e : c) {
 548                 if (e == null || !contains(e)) {
 549                     return false;
 550                 }
 551             }
 552             return true;
 553         }
 554 
 555         @Override
 556         public abstract int hashCode();
 557     }
 558 
 559     static final class Set12<E> extends AbstractImmutableSet<E>
 560             implements Serializable {
 561 
 562         @Stable
 563         final E e0;
 564         @Stable
 565         final E e1;
 566 
 567         Set12(E e0) {
 568             this.e0 = Objects.requireNonNull(e0);
 569             this.e1 = null;
 570         }
 571 
 572         Set12(E e0, E e1) {
 573             if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
 574                 throw new IllegalArgumentException("duplicate element: " + e0);
 575             }
 576 
 577             this.e0 = e0;
 578             this.e1 = e1;
 579         }
 580 
 581         @Override
 582         public int size() {
 583             return (e1 == null) ? 1 : 2;
 584         }
 585 
 586         @Override
 587         public boolean isEmpty() {
 588             return false;
 589         }
 590 
 591         @Override
 592         public boolean contains(Object o) {
 593             return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
 594         }
 595 
 596         @Override
 597         public int hashCode() {
 598             return e0.hashCode() + (e1 == null ? 0 : e1.hashCode());
 599         }
 600 
 601         @Override
 602         public Iterator<E> iterator() {
 603             return new Iterator<>() {
 604                 private int idx = size();
 605 
 606                 @Override
 607                 public boolean hasNext() {
 608                     return idx > 0;
 609                 }
 610 
 611                 @Override
 612                 public E next() {
 613                     if (idx == 1) {
 614                         idx = 0;
 615                         return SALT >= 0 || e1 == null ? e0 : e1;
 616                     } else if (idx == 2) {
 617                         idx = 1;
 618                         return SALT >= 0 ? e1 : e0;
 619                     } else {
 620                         throw new NoSuchElementException();
 621                     }
 622                 }
 623             };
 624         }
 625 
 626         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 627             throw new InvalidObjectException("not serial proxy");
 628         }
 629 
 630         private Object writeReplace() {
 631             if (e1 == null) {
 632                 return new CollSer(CollSer.IMM_SET, e0);
 633             } else {
 634                 return new CollSer(CollSer.IMM_SET, e0, e1);
 635             }
 636         }
 637 
 638         @Override
 639         public Object[] toArray() {
 640             if (e1 == null) {
 641                 return new Object[] { e0 };
 642             } else if (SALT >= 0) {
 643                 return new Object[] { e1, e0 };
 644             } else {
 645                 return new Object[] { e0, e1 };
 646             }
 647         }
 648 
 649         @Override
 650         @SuppressWarnings("unchecked")
 651         public <T> T[] toArray(T[] a) {
 652             int size = e1 == null ? 1 : 2;
 653             T[] array = a.length >= size ? a :
 654                     (T[])Array.newInstance(a.getClass().getComponentType(), size);
 655             if (size == 1) {
 656                 array[0] = (T)e0;
 657             } else if (SALT >= 0) {
 658                 array[0] = (T)e1;
 659                 array[1] = (T)e0;
 660             } else {
 661                 array[0] = (T)e0;
 662                 array[1] = (T)e1;
 663             }
 664             if (array.length > size) {
 665                 array[size] = null; // null-terminate
 666             }
 667             return array;
 668         }
 669     }
 670 
 671 
 672     /**
 673      * An array-based Set implementation. The element array must be strictly
 674      * larger than the size (the number of contained elements) so that at
 675      * least one null is always present.
 676      * @param <E> the element type
 677      */
 678     static final class SetN<E> extends AbstractImmutableSet<E>
 679             implements Serializable {
 680 
 681         // EMPTY_SET may be initialized from the CDS archive.
 682         static @Stable Set<?> EMPTY_SET;
 683 
 684         static {
 685             VM.initializeFromArchive(SetN.class);
 686             if (EMPTY_SET == null) {
 687                 EMPTY_SET = new SetN<>();
 688             }
 689         }
 690 
 691         @Stable
 692         final E[] elements;
 693         @Stable
 694         final int size;
 695 
 696         @SafeVarargs
 697         @SuppressWarnings("unchecked")
 698         SetN(E... input) {
 699             size = input.length; // implicit nullcheck of input
 700 
 701             elements = (E[])new Object[EXPAND_FACTOR * input.length];
 702             for (int i = 0; i < input.length; i++) {
 703                 E e = input[i];
 704                 int idx = probe(e); // implicit nullcheck of e
 705                 if (idx >= 0) {
 706                     throw new IllegalArgumentException("duplicate element: " + e);
 707                 } else {
 708                     elements[-(idx + 1)] = e;
 709                 }
 710             }
 711         }
 712 
 713         @Override
 714         public int size() {
 715             return size;
 716         }
 717 
 718         @Override
 719         public boolean isEmpty() {
 720             return size == 0;
 721         }
 722 
 723         @Override
 724         public boolean contains(Object o) {
 725             Objects.requireNonNull(o);
 726             return size > 0 && probe(o) >= 0;
 727         }
 728 
 729         private final class SetNIterator implements Iterator<E> {
 730 
 731             private int remaining;
 732 
 733             private int idx;
 734 
 735             SetNIterator() {
 736                 remaining = size();
 737                 if (remaining > 0) {
 738                     idx = Math.floorMod(SALT, elements.length);
 739                 }
 740             }
 741 
 742             @Override
 743             public boolean hasNext() {
 744                 return remaining > 0;
 745             }
 746 
 747             private int nextIndex() {
 748                 int idx = this.idx;
 749                 if (SALT >= 0) {
 750                     if (++idx >= elements.length) {
 751                         idx = 0;
 752                     }
 753                 } else {
 754                     if (--idx < 0) {
 755                         idx = elements.length - 1;
 756                     }
 757                 }
 758                 return this.idx = idx;
 759             }
 760 
 761             @Override
 762             public E next() {
 763                 if (remaining > 0) {
 764                     E element;
 765                     // skip null elements
 766                     while ((element = elements[nextIndex()]) == null) {}
 767                     remaining--;
 768                     return element;
 769                 } else {
 770                     throw new NoSuchElementException();
 771                 }
 772             }
 773         }
 774 
 775         @Override
 776         public Iterator<E> iterator() {
 777             return new SetNIterator();
 778         }
 779 
 780         @Override
 781         public int hashCode() {
 782             int h = 0;
 783             for (E e : elements) {
 784                 if (e != null) {
 785                     h += e.hashCode();
 786                 }
 787             }
 788             return h;
 789         }
 790 
 791         // returns index at which element is present; or if absent,
 792         // (-i - 1) where i is location where element should be inserted.
 793         // Callers are relying on this method to perform an implicit nullcheck
 794         // of pe
 795         private int probe(Object pe) {
 796             int idx = Math.floorMod(pe.hashCode(), elements.length);
 797             while (true) {
 798                 E ee = elements[idx];
 799                 if (ee == null) {
 800                     return -idx - 1;
 801                 } else if (pe.equals(ee)) {
 802                     return idx;
 803                 } else if (++idx == elements.length) {
 804                     idx = 0;
 805                 }
 806             }
 807         }
 808 
 809         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 810             throw new InvalidObjectException("not serial proxy");
 811         }
 812 
 813         private Object writeReplace() {
 814             Object[] array = new Object[size];
 815             int dest = 0;
 816             for (Object o : elements) {
 817                 if (o != null) {
 818                     array[dest++] = o;
 819                 }
 820             }
 821             return new CollSer(CollSer.IMM_SET, array);
 822         }
 823 
 824         @Override
 825         public Object[] toArray() {
 826             Object[] array = new Object[size];
 827             Iterator<E> it = iterator();
 828             for (int i = 0; i < size; i++) {
 829                 array[i] = it.next();
 830             }
 831             return array;
 832         }
 833 
 834         @Override
 835         @SuppressWarnings("unchecked")
 836         public <T> T[] toArray(T[] a) {
 837             T[] array = a.length >= size ? a :
 838                     (T[])Array.newInstance(a.getClass().getComponentType(), size);
 839             Iterator<E> it = iterator();
 840             for (int i = 0; i < size; i++) {
 841                 array[i] = (T)it.next();
 842             }
 843             if (array.length > size) {
 844                 array[size] = null; // null-terminate
 845             }
 846             return array;
 847         }
 848     }
 849 
 850     // ---------- Map Implementations ----------
 851 
 852     abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
 853         @Override public void clear() { throw uoe(); }
 854         @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 855         @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
 856         @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 857         @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
 858         @Override public V put(K key, V value) { throw uoe(); }
 859         @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
 860         @Override public V putIfAbsent(K key, V value) { throw uoe(); }
 861         @Override public V remove(Object key) { throw uoe(); }
 862         @Override public boolean remove(Object key, Object value) { throw uoe(); }
 863         @Override public V replace(K key, V value) { throw uoe(); }
 864         @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
 865         @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
 866     }
 867 
 868     static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
 869         @Stable
 870         private final K k0;
 871         @Stable
 872         private final V v0;
 873 
 874         Map1(K k0, V v0) {
 875             this.k0 = Objects.requireNonNull(k0);
 876             this.v0 = Objects.requireNonNull(v0);
 877         }
 878 
 879         @Override
 880         public Set<Map.Entry<K,V>> entrySet() {
 881             return Set.of(new KeyValueHolder<>(k0, v0));
 882         }
 883 
 884         @Override
 885         public V get(Object o) {
 886             return o.equals(k0) ? v0 : null; // implicit nullcheck of o
 887         }
 888 
 889         @Override
 890         public boolean containsKey(Object o) {
 891             return o.equals(k0); // implicit nullcheck of o
 892         }
 893 
 894         @Override
 895         public boolean containsValue(Object o) {
 896             return o.equals(v0); // implicit nullcheck of o
 897         }
 898 
 899         @Override
 900         public int size() {
 901             return 1;
 902         }
 903 
 904         @Override
 905         public boolean isEmpty() {
 906             return false;
 907         }
 908 
 909         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 910             throw new InvalidObjectException("not serial proxy");
 911         }
 912 
 913         private Object writeReplace() {
 914             return new CollSer(CollSer.IMM_MAP, k0, v0);
 915         }
 916 
 917         @Override
 918         public int hashCode() {
 919             return k0.hashCode() ^ v0.hashCode();
 920         }
 921     }
 922 
 923     /**
 924      * An array-based Map implementation. There is a single array "table" that
 925      * contains keys and values interleaved: table[0] is kA, table[1] is vA,
 926      * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
 927      * also be strictly larger than the size (the number of key-value pairs contained
 928      * in the map) so that at least one null key is always present.
 929      * @param <K> the key type
 930      * @param <V> the value type
 931      */
 932     static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
 933 
 934         // EMPTY_MAP may be initialized from the CDS archive.
 935         static @Stable Map<?,?> EMPTY_MAP;
 936 
 937         static {
 938             VM.initializeFromArchive(MapN.class);
 939             if (EMPTY_MAP == null) {
 940                 EMPTY_MAP = new MapN<>();
 941             }
 942         }
 943 
 944         @Stable
 945         final Object[] table; // pairs of key, value
 946 
 947         @Stable
 948         final int size; // number of pairs
 949 
 950         MapN(Object... input) {
 951             if ((input.length & 1) != 0) { // implicit nullcheck of input
 952                 throw new InternalError("length is odd");
 953             }
 954             size = input.length >> 1;
 955 
 956             int len = EXPAND_FACTOR * input.length;
 957             len = (len + 1) & ~1; // ensure table is even length
 958             table = new Object[len];
 959 
 960             for (int i = 0; i < input.length; i += 2) {
 961                 @SuppressWarnings("unchecked")
 962                     K k = Objects.requireNonNull((K)input[i]);
 963                 @SuppressWarnings("unchecked")
 964                     V v = Objects.requireNonNull((V)input[i+1]);
 965                 int idx = probe(k);
 966                 if (idx >= 0) {
 967                     throw new IllegalArgumentException("duplicate key: " + k);
 968                 } else {
 969                     int dest = -(idx + 1);
 970                     table[dest] = k;
 971                     table[dest+1] = v;
 972                 }
 973             }
 974         }
 975 
 976         @Override
 977         public boolean containsKey(Object o) {
 978             Objects.requireNonNull(o);
 979             return size > 0 && probe(o) >= 0;
 980         }
 981 
 982         @Override
 983         public boolean containsValue(Object o) {
 984             Objects.requireNonNull(o);
 985             for (int i = 1; i < table.length; i += 2) {
 986                 Object v = table[i];
 987                 if (v != null && o.equals(v)) {
 988                     return true;
 989                 }
 990             }
 991             return false;
 992         }
 993 
 994         @Override
 995         public int hashCode() {
 996             int hash = 0;
 997             for (int i = 0; i < table.length; i += 2) {
 998                 Object k = table[i];
 999                 if (k != null) {
1000                     hash += k.hashCode() ^ table[i + 1].hashCode();
1001                 }
1002             }
1003             return hash;
1004         }
1005 
1006         @Override
1007         @SuppressWarnings("unchecked")
1008         public V get(Object o) {
1009             if (size == 0) {
1010                 Objects.requireNonNull(o);
1011                 return null;
1012             }
1013             int i = probe(o);
1014             if (i >= 0) {
1015                 return (V)table[i+1];
1016             } else {
1017                 return null;
1018             }
1019         }
1020 
1021         @Override
1022         public int size() {
1023             return size;
1024         }
1025 
1026         @Override
1027         public boolean isEmpty() {
1028             return size == 0;
1029         }
1030 
1031         class MapNIterator implements Iterator<Map.Entry<K,V>> {
1032 
1033             private int remaining;
1034 
1035             private int idx;
1036 
1037             MapNIterator() {
1038                 remaining = size();
1039                 if (remaining > 0) {
1040                     idx = Math.floorMod(SALT, table.length >> 1) << 1;
1041                 }
1042             }
1043 
1044             @Override
1045             public boolean hasNext() {
1046                 return remaining > 0;
1047             }
1048 
1049             private int nextIndex() {
1050                 int idx = this.idx;
1051                 if (SALT >= 0) {
1052                     if ((idx += 2) >= table.length) {
1053                         idx = 0;
1054                     }
1055                 } else {
1056                     if ((idx -= 2) < 0) {
1057                         idx = table.length - 2;
1058                     }
1059                 }
1060                 return this.idx = idx;
1061             }
1062 
1063             @Override
1064             public Map.Entry<K,V> next() {
1065                 if (remaining > 0) {
1066                     int idx;
1067                     while (table[idx = nextIndex()] == null) {}
1068                     @SuppressWarnings("unchecked")
1069                     Map.Entry<K,V> e =
1070                             new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
1071                     remaining--;
1072                     return e;
1073                 } else {
1074                     throw new NoSuchElementException();
1075                 }
1076             }
1077         }
1078 
1079         @Override
1080         public Set<Map.Entry<K,V>> entrySet() {
1081             return new AbstractSet<>() {
1082                 @Override
1083                 public int size() {
1084                     return MapN.this.size;
1085                 }
1086 
1087                 @Override
1088                 public Iterator<Map.Entry<K,V>> iterator() {
1089                     return new MapNIterator();
1090                 }
1091             };
1092         }
1093 
1094         // returns index at which the probe key is present; or if absent,
1095         // (-i - 1) where i is location where element should be inserted.
1096         // Callers are relying on this method to perform an implicit nullcheck
1097         // of pk.
1098         private int probe(Object pk) {
1099             int idx = Math.floorMod(pk.hashCode(), table.length >> 1) << 1;
1100             while (true) {
1101                 @SuppressWarnings("unchecked")
1102                 K ek = (K)table[idx];
1103                 if (ek == null) {
1104                     return -idx - 1;
1105                 } else if (pk.equals(ek)) {
1106                     return idx;
1107                 } else if ((idx += 2) == table.length) {
1108                     idx = 0;
1109                 }
1110             }
1111         }
1112 
1113         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1114             throw new InvalidObjectException("not serial proxy");
1115         }
1116 
1117         private Object writeReplace() {
1118             Object[] array = new Object[2 * size];
1119             int len = table.length;
1120             int dest = 0;
1121             for (int i = 0; i < len; i += 2) {
1122                 if (table[i] != null) {
1123                     array[dest++] = table[i];
1124                     array[dest++] = table[i+1];
1125                 }
1126             }
1127             return new CollSer(CollSer.IMM_MAP, array);
1128         }
1129     }
1130 }
1131 
1132 // ---------- Serialization Proxy ----------
1133 
1134 /**
1135  * A unified serialization proxy class for the immutable collections.
1136  *
1137  * @serial
1138  * @since 9
1139  */
1140 final class CollSer implements Serializable {
1141     private static final long serialVersionUID = 6309168927139932177L;
1142 
1143     static final int IMM_LIST = 1;
1144     static final int IMM_SET = 2;
1145     static final int IMM_MAP = 3;
1146 
1147     /**
1148      * Indicates the type of collection that is serialized.
1149      * The low order 8 bits have the value 1 for an immutable
1150      * {@code List}, 2 for an immutable {@code Set}, and 3 for
1151      * an immutable {@code Map}. Any other value causes an
1152      * {@link InvalidObjectException} to be thrown. The high
1153      * order 24 bits are zero when an instance is serialized,
1154      * and they are ignored when an instance is deserialized.
1155      * They can thus be used by future implementations without
1156      * causing compatibility issues.
1157      *
1158      * <p>The tag value also determines the interpretation of the
1159      * transient {@code Object[] array} field.
1160      * For {@code List} and {@code Set}, the array's length is the size
1161      * of the collection, and the array contains the elements of the collection.
1162      * Null elements are not allowed. For {@code Set}, duplicate elements
1163      * are not allowed.
1164      *
1165      * <p>For {@code Map}, the array's length is twice the number of mappings
1166      * present in the map. The array length is necessarily even.
1167      * The array contains a succession of key and value pairs:
1168      * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed,
1169      * and duplicate keys are not allowed.
1170      *
1171      * @serial
1172      * @since 9
1173      */
1174     private final int tag;
1175 
1176     /**
1177      * @serial
1178      * @since 9
1179      */
1180     private transient Object[] array;
1181 
1182     CollSer(int t, Object... a) {
1183         tag = t;
1184         array = a;
1185     }
1186 
1187     /**
1188      * Reads objects from the stream and stores them
1189      * in the transient {@code Object[] array} field.
1190      *
1191      * @serialData
1192      * A nonnegative int, indicating the count of objects,
1193      * followed by that many objects.
1194      *
1195      * @param ois the ObjectInputStream from which data is read
1196      * @throws IOException if an I/O error occurs
1197      * @throws ClassNotFoundException if a serialized class cannot be loaded
1198      * @throws InvalidObjectException if the count is negative
1199      * @since 9
1200      */
1201     private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1202         ois.defaultReadObject();
1203         int len = ois.readInt();
1204 
1205         if (len < 0) {
1206             throw new InvalidObjectException("negative length " + len);
1207         }
1208 
1209         SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, len);
1210         Object[] a = new Object[len];
1211         for (int i = 0; i < len; i++) {
1212             a[i] = ois.readObject();
1213         }
1214 
1215         array = a;
1216     }
1217 
1218     /**
1219      * Writes objects to the stream from
1220      * the transient {@code Object[] array} field.
1221      *
1222      * @serialData
1223      * A nonnegative int, indicating the count of objects,
1224      * followed by that many objects.
1225      *
1226      * @param oos the ObjectOutputStream to which data is written
1227      * @throws IOException if an I/O error occurs
1228      * @since 9
1229      */
1230     private void writeObject(ObjectOutputStream oos) throws IOException {
1231         oos.defaultWriteObject();
1232         oos.writeInt(array.length);
1233         for (int i = 0; i < array.length; i++) {
1234             oos.writeObject(array[i]);
1235         }
1236     }
1237 
1238     /**
1239      * Creates and returns an immutable collection from this proxy class.
1240      * The instance returned is created as if by calling one of the
1241      * static factory methods for
1242      * <a href="List.html#unmodifiable">List</a>,
1243      * <a href="Map.html#unmodifiable">Map</a>, or
1244      * <a href="Set.html#unmodifiable">Set</a>.
1245      * This proxy class is the serial form for all immutable collection instances,
1246      * regardless of implementation type. This is necessary to ensure that the
1247      * existence of any particular implementation type is kept out of the
1248      * serialized form.
1249      *
1250      * @return a collection created from this proxy object
1251      * @throws InvalidObjectException if the tag value is illegal or if an exception
1252      *         is thrown during creation of the collection
1253      * @throws ObjectStreamException if another serialization error has occurred
1254      * @since 9
1255      */
1256     private Object readResolve() throws ObjectStreamException {
1257         try {
1258             if (array == null) {
1259                 throw new InvalidObjectException("null array");
1260             }
1261 
1262             // use low order 8 bits to indicate "kind"
1263             // ignore high order 24 bits
1264             switch (tag & 0xff) {
1265                 case IMM_LIST:
1266                     return List.of(array);
1267                 case IMM_SET:
1268                     return Set.of(array);
1269                 case IMM_MAP:
1270                     if (array.length == 0) {
1271                         return ImmutableCollections.MapN.EMPTY_MAP;
1272                     } else if (array.length == 2) {
1273                         return new ImmutableCollections.Map1<>(array[0], array[1]);
1274                     } else {
1275                         return new ImmutableCollections.MapN<>(array);
1276                     }
1277                 default:
1278                     throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
1279             }
1280         } catch (NullPointerException|IllegalArgumentException ex) {
1281             InvalidObjectException ioe = new InvalidObjectException("invalid object");
1282             ioe.initCause(ex);
1283             throw ioe;
1284         }
1285     }
1286 }