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