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