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