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