< prev index next >

src/java.base/share/classes/java/util/ImmutableCollections.java

Print this page
rev 48077 : 8193128: Reduce number of implementation classes returned by List/Set/Map.of()
Reviewed-by: smarks


  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     abstract static class AbstractImmutableList<E> extends AbstractList<E>
  76                                                 implements RandomAccess, Serializable {









  77         @Override public boolean add(E e) { throw uoe(); }

  78         @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
  79         @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
  80         @Override public void    clear() { throw uoe(); }
  81         @Override public boolean remove(Object o) { throw uoe(); }

  82         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
  83         @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
  84         @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
  85         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }

  86         @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
  87     }
  88 
  89     static final class List0<E> extends AbstractImmutableList<E> {
  90         private static final List0<?> INSTANCE = new List0<>();













  91 
  92         @SuppressWarnings("unchecked")
  93         static <T> List0<T> instance() {
  94             return (List0<T>) INSTANCE;


  95         }

  96 
  97         private List0() { }







  98 
  99         @Override
 100         public int size() {
 101             return 0;
 102         }
 103 
 104         @Override






























 105         public E get(int index) {
 106             Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
 107             return null;                  // but the compiler doesn't know this




 108         }
 109 
 110         @Override
 111         public Iterator<E> iterator() {
 112             return Collections.emptyIterator();
 113         }
 114 
 115         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 116             throw new InvalidObjectException("not serial proxy");







 117         }
 118 
 119         private Object writeReplace() {
 120             return new CollSer(CollSer.IMM_LIST);




















































 121         }
 122 
 123         @Override
 124         public boolean contains(Object o) {
 125             Objects.requireNonNull(o);
 126             return false;
 127         }
 128 
 129         @Override
 130         public boolean containsAll(Collection<?> o) {
 131             return o.isEmpty(); // implicit nullcheck of o
 132         }
 133 
 134         @Override
 135         public int hashCode() {
 136             return 1;


 137         }

 138     }
 139 
 140     static final class List1<E> extends AbstractImmutableList<E> {
 141         @Stable
 142         private final E e0;
 143 
 144         List1(E e0) {
 145             this.e0 = Objects.requireNonNull(e0);




 146         }
 147 
 148         @Override
 149         public int size() {
 150             return 1;
 151         }
 152 
 153         @Override
 154         public E get(int index) {
 155             Objects.checkIndex(index, 1);
 156             return e0;





 157         }
 158 
 159         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 160             throw new InvalidObjectException("not serial proxy");

 161         }
 162 
 163         private Object writeReplace() {
 164             return new CollSer(CollSer.IMM_LIST, e0);



 165         }
 166 
 167         @Override
 168         public boolean contains(Object o) {
 169             return o.equals(e0); // implicit nullcheck of o










 170         }
 171 


















 172         @Override
 173         public int hashCode() {
 174             return 31 + e0.hashCode();

 175         }



 176     }
 177 
 178     static final class List2<E> extends AbstractImmutableList<E> {


















 179         @Stable
 180         private final E e0;

 181         @Stable
 182         private final E e1;
 183 
 184         List2(E e0, E e1) {





 185             this.e0 = Objects.requireNonNull(e0);
 186             this.e1 = Objects.requireNonNull(e1);
 187         }
 188 
 189         @Override
 190         public int size() {
 191             return 2;
 192         }
 193 
 194         @Override
 195         public E get(int index) {
 196             Objects.checkIndex(index, 2);
 197             if (index == 0) {
 198                 return e0;
 199             } else { // index == 1
 200                 return e1;
 201             }

 202         }
 203 
 204         @Override
 205         public boolean contains(Object o) {
 206             return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
 207         }
 208 
 209         @Override
 210         public int hashCode() {
 211             int hash = 31 + e0.hashCode();
 212             return 31 * hash + e1.hashCode();



 213         }
 214 
 215         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 216             throw new InvalidObjectException("not serial proxy");
 217         }
 218 
 219         private Object writeReplace() {



 220             return new CollSer(CollSer.IMM_LIST, e0, e1);
 221         }
 222     }



 223 
 224     static final class ListN<E> extends AbstractImmutableList<E> {
 225         @Stable
 226         private final E[] elements;
 227 










 228         @SafeVarargs
 229         ListN(E... input) {
 230             // copy and check manually to avoid TOCTOU
 231             @SuppressWarnings("unchecked")
 232             E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
 233             for (int i = 0; i < input.length; i++) {
 234                 tmp[i] = Objects.requireNonNull(input[i]);
 235             }
 236             this.elements = tmp;





 237         }
 238 
 239         @Override
 240         public int size() {
 241             return elements.length;
 242         }
 243 
 244         @Override
 245         public E get(int index) {
 246             Objects.checkIndex(index, elements.length);
 247             return elements[index];
 248         }
 249 
 250         @Override
 251         public boolean contains(Object o) {

 252             for (E e : elements) {
 253                 if (o.equals(e)) { // implicit nullcheck of o
 254                     return true;
 255                 }
 256             }
 257             return false;
 258         }
 259 
 260         @Override
 261         public int hashCode() {
 262             int hash = 1;
 263             for (E e : elements) {
 264                 hash = 31 * hash + e.hashCode();
 265             }
 266             return hash;
 267         }
 268 
 269         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 270             throw new InvalidObjectException("not serial proxy");
 271         }
 272 
 273         private Object writeReplace() {
 274             return new CollSer(CollSer.IMM_LIST, elements);
 275         }
 276     }
 277 
 278     // ---------- Set Implementations ----------
 279 







 280     abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
 281         @Override public boolean add(E e) { throw uoe(); }
 282         @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
 283         @Override public void    clear() { throw uoe(); }
 284         @Override public boolean remove(Object o) { throw uoe(); }
 285         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
 286         @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
 287         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
 288     }
 289 
 290     static final class Set0<E> extends AbstractImmutableSet<E> {
 291         private static final Set0<?> INSTANCE = new Set0<>();
 292 
 293         @SuppressWarnings("unchecked")
 294         static <T> Set0<T> instance() {
 295             return (Set0<T>) INSTANCE;
 296         }
 297 
 298         private Set0() { }
 299 
 300         @Override
 301         public int size() {
 302             return 0;
 303         }
 304 
 305         @Override
 306         public boolean contains(Object o) {
 307             Objects.requireNonNull(o);
 308             return false;
 309         }
 310 
 311         @Override
 312         public boolean containsAll(Collection<?> o) {
 313             return o.isEmpty(); // implicit nullcheck of o
 314         }
 315 
 316         @Override
 317         public Iterator<E> iterator() {
 318             return Collections.emptyIterator();
 319         }
 320 
 321         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 322             throw new InvalidObjectException("not serial proxy");
 323         }
 324 
 325         private Object writeReplace() {
 326             return new CollSer(CollSer.IMM_SET);
 327         }
 328 
 329         @Override
 330         public int hashCode() {
 331             return 0;
 332         }
 333     }
 334 
 335     static final class Set1<E> extends AbstractImmutableSet<E> {
 336         @Stable
 337         private final E e0;
 338 
 339         Set1(E e0) {
 340             this.e0 = Objects.requireNonNull(e0);
 341         }
 342 
 343         @Override
 344         public int size() {
 345             return 1;
 346         }
 347 
 348         @Override
 349         public boolean contains(Object o) {
 350             return o.equals(e0); // implicit nullcheck of o
 351         }
 352 
 353         @Override
 354         public Iterator<E> iterator() {
 355             return Collections.singletonIterator(e0);
 356         }
 357 
 358         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 359             throw new InvalidObjectException("not serial proxy");
 360         }
 361 
 362         private Object writeReplace() {
 363             return new CollSer(CollSer.IMM_SET, e0);
 364         }
 365 
 366         @Override
 367         public int hashCode() {
 368             return e0.hashCode();
 369         }
 370     }
 371 
 372     static final class Set2<E> extends AbstractImmutableSet<E> {
 373         @Stable
 374         final E e0;
 375         @Stable
 376         final E e1;
 377 
 378         Set2(E e0, E e1) {





 379             if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
 380                 throw new IllegalArgumentException("duplicate element: " + e0);
 381             }
 382 
 383             if (SALT >= 0) {
 384                 this.e0 = e0;
 385                 this.e1 = e1;
 386             } else {
 387                 this.e0 = e1;
 388                 this.e1 = e0;
 389             }
 390         }
 391 
 392         @Override
 393         public int size() {
 394             return 2;
 395         }
 396 
 397         @Override
 398         public boolean contains(Object o) {
 399             return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
 400         }
 401 
 402         @Override
 403         public int hashCode() {
 404             return e0.hashCode() + e1.hashCode();
 405         }
 406 
 407         @Override
 408         public Iterator<E> iterator() {
 409             return new Iterator<E>() {
 410                 private int idx = 0;
 411 
 412                 @Override
 413                 public boolean hasNext() {
 414                     return idx < 2;
 415                 }
 416 
 417                 @Override
 418                 public E next() {
 419                     if (idx == 0) {
 420                         idx = 1;
 421                         return e0;
 422                     } else if (idx == 1) {
 423                         idx = 2;
 424                         return e1;
 425                     } else {
 426                         throw new NoSuchElementException();
 427                     }
 428                 }
 429             };
 430         }
 431 
 432         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 433             throw new InvalidObjectException("not serial proxy");
 434         }
 435 
 436         private Object writeReplace() {



 437             return new CollSer(CollSer.IMM_SET, e0, e1);
 438         }
 439     }

 440 
 441     /**
 442      * An array-based Set implementation. The element array must be strictly
 443      * larger than the size (the number of contained elements) so that at
 444      * least one null is always present.
 445      * @param <E> the element type
 446      */
 447     static final class SetN<E> extends AbstractImmutableSet<E> {
 448         @Stable
 449         final E[] elements;
 450         @Stable
 451         final int size;
 452 
 453         @SafeVarargs
 454         @SuppressWarnings("unchecked")
 455         SetN(E... input) {
 456             size = input.length; // implicit nullcheck of input
 457 
 458             elements = (E[])new Object[EXPAND_FACTOR * input.length];
 459             for (int i = 0; i < input.length; i++) {
 460                 E e = input[i];
 461                 int idx = probe(e); // implicit nullcheck of e
 462                 if (idx >= 0) {
 463                     throw new IllegalArgumentException("duplicate element: " + e);
 464                 } else {
 465                     elements[-(idx + 1)] = e;
 466                 }
 467             }
 468         }
 469 
 470         @Override
 471         public int size() {
 472             return size;
 473         }
 474 
 475         @Override
 476         public boolean contains(Object o) {
 477             return probe(o) >= 0; // implicit nullcheck of o

 478         }
 479 
 480         @Override
 481         public Iterator<E> iterator() {
 482             return new Iterator<E>() {
 483                 private int idx = 0;
 484 
 485                 @Override
 486                 public boolean hasNext() {
 487                     while (idx < elements.length) {
 488                         if (elements[idx] != null)
 489                             return true;
 490                         idx++;
 491                     }
 492                     return false;
 493                 }
 494 
 495                 @Override
 496                 public E next() {
 497                     if (! hasNext()) {


 532         }
 533 
 534         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 535             throw new InvalidObjectException("not serial proxy");
 536         }
 537 
 538         private Object writeReplace() {
 539             Object[] array = new Object[size];
 540             int dest = 0;
 541             for (Object o : elements) {
 542                 if (o != null) {
 543                     array[dest++] = o;
 544                 }
 545             }
 546             return new CollSer(CollSer.IMM_SET, array);
 547         }
 548     }
 549 
 550     // ---------- Map Implementations ----------
 551 







 552     abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
 553         @Override public void clear() { throw uoe(); }
 554         @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 555         @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
 556         @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 557         @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
 558         @Override public V put(K key, V value) { throw uoe(); }
 559         @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
 560         @Override public V putIfAbsent(K key, V value) { throw uoe(); }
 561         @Override public V remove(Object key) { throw uoe(); }
 562         @Override public boolean remove(Object key, Object value) { throw uoe(); }
 563         @Override public V replace(K key, V value) { throw uoe(); }
 564         @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
 565         @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
 566     }
 567 
 568     static final class Map0<K,V> extends AbstractImmutableMap<K,V> {
 569         private static final Map0<?,?> INSTANCE = new Map0<>();
 570 
 571         @SuppressWarnings("unchecked")
 572         static <K,V> Map0<K,V> instance() {
 573             return (Map0<K,V>) INSTANCE;
 574         }
 575 
 576         private Map0() { }
 577 
 578         @Override
 579         public Set<Map.Entry<K,V>> entrySet() {
 580             return Set.of();
 581         }
 582 
 583         @Override
 584         public boolean containsKey(Object o) {
 585             Objects.requireNonNull(o);
 586             return false;
 587         }
 588 
 589         @Override
 590         public boolean containsValue(Object o) {
 591             Objects.requireNonNull(o);
 592             return false;
 593         }
 594 
 595         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 596             throw new InvalidObjectException("not serial proxy");
 597         }
 598 
 599         private Object writeReplace() {
 600             return new CollSer(CollSer.IMM_MAP);
 601         }
 602 
 603         @Override
 604         public int hashCode() {
 605             return 0;
 606         }
 607     }
 608 
 609     static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
 610         @Stable
 611         private final K k0;
 612         @Stable
 613         private final V v0;
 614 
 615         Map1(K k0, V v0) {
 616             this.k0 = Objects.requireNonNull(k0);
 617             this.v0 = Objects.requireNonNull(v0);
 618         }
 619 
 620         @Override
 621         public Set<Map.Entry<K,V>> entrySet() {
 622             return Set.of(new KeyValueHolder<>(k0, v0));
 623         }
 624 
 625         @Override
 626         public boolean containsKey(Object o) {
 627             return o.equals(k0); // implicit nullcheck of o
 628         }


 641         }
 642 
 643         @Override
 644         public int hashCode() {
 645             return k0.hashCode() ^ v0.hashCode();
 646         }
 647     }
 648 
 649     /**
 650      * An array-based Map implementation. There is a single array "table" that
 651      * contains keys and values interleaved: table[0] is kA, table[1] is vA,
 652      * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
 653      * also be strictly larger than the size (the number of key-value pairs contained
 654      * in the map) so that at least one null key is always present.
 655      * @param <K> the key type
 656      * @param <V> the value type
 657      */
 658     static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
 659         @Stable
 660         final Object[] table; // pairs of key, value

 661         @Stable
 662         final int size; // number of pairs
 663 
 664         MapN(Object... input) {
 665             if ((input.length & 1) != 0) { // implicit nullcheck of input
 666                 throw new InternalError("length is odd");
 667             }
 668             size = input.length >> 1;
 669 
 670             int len = EXPAND_FACTOR * input.length;
 671             len = (len + 1) & ~1; // ensure table is even length
 672             table = new Object[len];
 673 
 674             for (int i = 0; i < input.length; i += 2) {
 675                 @SuppressWarnings("unchecked")
 676                     K k = Objects.requireNonNull((K)input[i]);
 677                 @SuppressWarnings("unchecked")
 678                     V v = Objects.requireNonNull((V)input[i+1]);
 679                 int idx = probe(k);
 680                 if (idx >= 0) {
 681                     throw new IllegalArgumentException("duplicate key: " + k);
 682                 } else {
 683                     int dest = -(idx + 1);
 684                     table[dest] = k;
 685                     table[dest+1] = v;
 686                 }
 687             }
 688         }
 689 
 690         @Override
 691         public boolean containsKey(Object o) {
 692             return probe(o) >= 0; // implicit nullcheck of o

 693         }
 694 
 695         @Override
 696         public boolean containsValue(Object o) {
 697             for (int i = 1; i < table.length; i += 2) {
 698                 Object v = table[i];
 699                 if (v != null && o.equals(v)) { // implicit nullcheck of o
 700                     return true;
 701                 }
 702             }
 703             return false;
 704         }
 705 
 706         @Override
 707         public int hashCode() {
 708             int hash = 0;
 709             for (int i = 0; i < table.length; i += 2) {
 710                 Object k = table[i];
 711                 if (k != null) {
 712                     hash += k.hashCode() ^ table[i + 1].hashCode();
 713                 }
 714             }
 715             return hash;
 716         }
 717 
 718         @Override
 719         @SuppressWarnings("unchecked")
 720         public V get(Object o) {



 721             int i = probe(o);
 722             if (i >= 0) {
 723                 return (V)table[i+1];
 724             } else {
 725                 return null;
 726             }
 727         }
 728 
 729         @Override
 730         public int size() {
 731             return size;
 732         }
 733 
 734         @Override
 735         public Set<Map.Entry<K,V>> entrySet() {
 736             return new AbstractSet<Map.Entry<K,V>>() {
 737                 @Override
 738                 public int size() {
 739                     return MapN.this.size;
 740                 }


 931      * @throws InvalidObjectException if the tag value is illegal or if an exception
 932      *         is thrown during creation of the collection
 933      * @throws ObjectStreamException if another serialization error has occurred
 934      * @since 9
 935      */
 936     private Object readResolve() throws ObjectStreamException {
 937         try {
 938             if (array == null) {
 939                 throw new InvalidObjectException("null array");
 940             }
 941 
 942             // use low order 8 bits to indicate "kind"
 943             // ignore high order 24 bits
 944             switch (tag & 0xff) {
 945                 case IMM_LIST:
 946                     return List.of(array);
 947                 case IMM_SET:
 948                     return Set.of(array);
 949                 case IMM_MAP:
 950                     if (array.length == 0) {
 951                         return ImmutableCollections.Map0.instance();
 952                     } else if (array.length == 2) {
 953                         return new ImmutableCollections.Map1<>(array[0], array[1]);
 954                     } else {
 955                         return new ImmutableCollections.MapN<>(array);
 956                     }
 957                 default:
 958                     throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
 959             }
 960         } catch (NullPointerException|IllegalArgumentException ex) {
 961             InvalidObjectException ioe = new InvalidObjectException("invalid object");
 962             ioe.initCause(ex);
 963             throw ioe;
 964         }
 965     }
 966 }


  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             return new SubList<E>(this, fromIndex, toIndex);
 143         }
 144 
 145         private static final class SubList<E> extends AbstractImmutableList<E> implements RandomAccess {
 146             private final List<E> root;
 147             final int offset;
 148             int size;
 149 
 150             /**
 151              * Constructs a sublist of an arbitrary AbstractList, which is
 152              * not a SubList itself.
 153              */
 154             SubList(List<E> root, int fromIndex, int toIndex) {
 155                 this.root = root;
 156                 this.offset = fromIndex;
 157                 this.size = toIndex - fromIndex;
 158             }
 159 
 160             /**
 161              * Constructs a sublist of another SubList.
 162              */
 163             SubList(SubList<E> parent, int fromIndex, int toIndex) {
 164                 this.root = parent.root;
 165                 this.offset = parent.offset + fromIndex;
 166                 this.size = toIndex - fromIndex;
 167             }
 168 
 169             public E get(int index) {
 170                 Objects.checkIndex(index, size);
 171                 return root.get(offset + index);
 172             }
 173 
 174             public int size() {
 175                 return size;
 176             }
 177 

 178             public Iterator<E> iterator() {
 179                 return listIterator();
 180             }
 181 
 182             public ListIterator<E> listIterator(int index) {
 183                 rangeCheck(index);
 184 
 185                 ListIterator<E> i = root.listIterator(offset + index);
 186 
 187                 return new ListIterator<>() {
 188 
 189                     public boolean hasNext() {
 190                         return nextIndex() < size;
 191                     }
 192 
 193                     public E next() {
 194                         if (hasNext()) {
 195                             return i.next();
 196                         } else {
 197                             throw new NoSuchElementException();
 198                         }
 199                     }
 200 
 201                     public boolean hasPrevious() {
 202                         return previousIndex() >= 0;
 203                     }
 204 
 205                     public E previous() {
 206                         if (hasPrevious()) {
 207                             return i.previous();
 208                         } else {
 209                             throw new NoSuchElementException();
 210                         }
 211                     }
 212 
 213                     public int nextIndex() {
 214                         return i.nextIndex() - offset;
 215                     }
 216 
 217                     public int previousIndex() {
 218                         return i.previousIndex() - offset;
 219                     }
 220 
 221                     public void remove() { throw uoe(); }
 222                     public void set(E e) { throw uoe(); }
 223                     public void add(E e) { throw uoe(); }
 224                 };
 225             }
 226 
 227             public List<E> subList(int fromIndex, int toIndex) {
 228                 subListRangeCheck(fromIndex, toIndex, size);
 229                 return new SubList<>(this, fromIndex, toIndex);
 230             }
 231 
 232             private void rangeCheck(int index) {
 233                 if (index < 0 || index > size) {
 234                     throw outOfBounds(index);
 235                 }
 236             }
 237         }
 238 
 239         static void subListRangeCheck(int fromIndex, int toIndex, int size) {
 240             if (fromIndex < 0)
 241                 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
 242             if (toIndex > size)
 243                 throw new IndexOutOfBoundsException("toIndex = " + toIndex);
 244             if (fromIndex > toIndex)
 245                 throw new IllegalArgumentException("fromIndex(" + fromIndex +
 246                         ") > toIndex(" + toIndex + ")");
 247         }
 248 
 249         @Override
 250         public Iterator<E> iterator() {
 251             return new Itr(size());

 252         }
 253 
 254         @Override
 255         public ListIterator<E> listIterator() {
 256             return listIterator(0);
 257         }
 258 
 259         @Override
 260         public ListIterator<E> listIterator(final int index) {
 261             int size = size();
 262             if (index < 0 || index > size) {
 263                 throw outOfBounds(index);
 264             }
 265             return new ListItr(index, size);
 266         }
 267 
 268         private class Itr implements Iterator<E> {


 269 
 270             int cursor;
 271 
 272             private final int size;
 273 
 274             Itr(int size) {
 275                 this.size = size;
 276             }
 277 
 278             public boolean hasNext() {
 279                 return cursor != size;

 280             }
 281 
 282             public E next() {
 283                 try {
 284                     int i = cursor;
 285                     E next = get(i);
 286                     cursor = i + 1;
 287                     return next;
 288                 } catch (IndexOutOfBoundsException e) {
 289                     throw new NoSuchElementException();
 290                 }
 291             }
 292 
 293             public void remove() {
 294                 throw uoe();
 295             }
 296         }
 297 
 298         private class ListItr extends Itr implements ListIterator<E> {
 299 
 300             ListItr(int index, int size) {
 301                 super(size);
 302                 cursor = index;
 303             }
 304 
 305             public boolean hasPrevious() {
 306                 return cursor != 0;
 307             }
 308 
 309             public E previous() {
 310                 try {
 311                     int i = cursor - 1;
 312                     E previous = get(i);
 313                     cursor = i;
 314                     return previous;
 315                 } catch (IndexOutOfBoundsException e) {
 316                     throw new NoSuchElementException();
 317                 }
 318             }
 319 
 320             public int nextIndex() {
 321                 return cursor;
 322             }
 323 
 324             public int previousIndex() {
 325                 return cursor - 1;
 326             }
 327 
 328             public void set(E e) {
 329                 throw uoe();
 330             }
 331 
 332             public void add(E e) {
 333                 throw uoe();
 334             }
 335         }
 336 
 337 
 338         @Override
 339         public boolean equals(Object o) {
 340             if (o == this) {
 341                 return true;
 342             }
 343 
 344             if (!(o instanceof List)) {
 345                 return false;
 346             }
 347 
 348             Iterator<?> e1 = iterator();
 349             Iterator<?> e2 = ((List<?>) o).iterator();
 350             while (e1.hasNext() && e2.hasNext()) {
 351                 Object o1 = e1.next(); // can't be null
 352                 Object o2 = e2.next();
 353                 if (o1.equals(o2)) {
 354                     return false;
 355                 }
 356             }
 357             return !(e1.hasNext() || e2.hasNext());
 358         }
 359 
 360         IndexOutOfBoundsException outOfBounds(int index) {
 361             return new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 362         }
 363     }
 364 
 365     static final class List12<E> extends AbstractImmutableList<E> implements Serializable {
 366 
 367         @Stable
 368         private final E e0;
 369 
 370         @Stable
 371         private final E e1;
 372 
 373         List12(E e0) {
 374             this.e0 = Objects.requireNonNull(e0);
 375             this.e1 = null;
 376         }
 377 
 378         List12(E e0, E e1) {
 379             this.e0 = Objects.requireNonNull(e0);
 380             this.e1 = Objects.requireNonNull(e1);
 381         }
 382 
 383         @Override
 384         public int size() {
 385             return e1 != null ? 2 : 1;
 386         }
 387 
 388         @Override
 389         public E get(int index) {

 390             if (index == 0) {
 391                 return e0;
 392             } else if (index == 1 && e1 != null) {
 393                 return e1;
 394             }
 395             throw outOfBounds(index);
 396         }
 397 
 398         @Override
 399         public boolean contains(Object o) {
 400             return o.equals(e0) || o.equals(e1); // implicit null check of o
 401         }
 402 
 403         @Override
 404         public int hashCode() {
 405             int hash = 31 + e0.hashCode();
 406             if (e1 != null) {
 407                 hash = 31 * hash + e1.hashCode();
 408             }
 409             return hash;
 410         }
 411 
 412         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 413             throw new InvalidObjectException("not serial proxy");
 414         }
 415 
 416         private Object writeReplace() {
 417             if (e1 == null) {
 418                 return new CollSer(CollSer.IMM_LIST, e0);
 419             } else {
 420                 return new CollSer(CollSer.IMM_LIST, e0, e1);
 421             }
 422         }
 423     }
 424 
 425     static final class ListN<E> extends AbstractImmutableList<E> implements Serializable {
 426 

 427         @Stable
 428         private final E[] elements;
 429 
 430         @SuppressWarnings("unchecked")
 431         ListN(E e0) {
 432             elements = (E[])new Object[] { e0 };
 433         }
 434 
 435         @SuppressWarnings("unchecked")
 436         ListN(E e0, E e1) {
 437             elements = (E[])new Object[] { e0, e1 };
 438         }
 439 
 440         @SafeVarargs
 441         ListN(E... input) {
 442             // copy and check manually to avoid TOCTOU
 443             @SuppressWarnings("unchecked")
 444             E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
 445             for (int i = 0; i < input.length; i++) {
 446                 tmp[i] = Objects.requireNonNull(input[i]);
 447             }
 448             elements = tmp;
 449         }
 450 
 451         @Override
 452         public boolean isEmpty() {
 453             return size() == 0;
 454         }
 455 
 456         @Override
 457         public int size() {
 458             return elements.length;
 459         }
 460 
 461         @Override
 462         public E get(int index) {

 463             return elements[index];
 464         }
 465 
 466         @Override
 467         public boolean contains(Object o) {
 468             Objects.requireNonNull(o);
 469             for (E e : elements) {
 470                 if (o.equals(e)) {
 471                     return true;
 472                 }
 473             }
 474             return false;
 475         }
 476 
 477         @Override
 478         public int hashCode() {
 479             int hash = 1;
 480             for (E e : elements) {
 481                 hash = 31 * hash + e.hashCode();
 482             }
 483             return hash;
 484         }
 485 
 486         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 487             throw new InvalidObjectException("not serial proxy");
 488         }
 489 
 490         private Object writeReplace() {
 491             return new CollSer(CollSer.IMM_LIST, elements);
 492         }
 493     }
 494 
 495     // ---------- Set Implementations ----------
 496 
 497     static final Set<?> EMPTY_SET = new SetN<>();
 498 
 499     @SuppressWarnings("unchecked")
 500     static <E> Set<E> emptySet() {
 501         return (Set<E>) EMPTY_SET;
 502     }
 503 
 504     abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
 505         @Override public boolean add(E e) { throw uoe(); }
 506         @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
 507         @Override public void    clear() { throw uoe(); }
 508         @Override public boolean remove(Object o) { throw uoe(); }
 509         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
 510         @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
 511         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
 512     }
 513 
 514     static final class Set12<E> extends AbstractImmutableSet<E> {


















































































 515         @Stable
 516         final E e0;
 517         @Stable
 518         final E e1;
 519 
 520         Set12(E e0) {
 521             this.e0 = Objects.requireNonNull(e0);
 522             this.e1 = null;
 523         }
 524 
 525         Set12(E e0, E e1) {
 526             if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
 527                 throw new IllegalArgumentException("duplicate element: " + e0);
 528             }
 529 
 530             if (SALT >= 0) {
 531                 this.e0 = e0;
 532                 this.e1 = e1;
 533             } else {
 534                 this.e0 = e1;
 535                 this.e1 = e0;
 536             }
 537         }
 538 
 539         @Override
 540         public int size() {
 541             return (e1 == null) ? 1 : 2;
 542         }
 543 
 544         @Override
 545         public boolean contains(Object o) {
 546             return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
 547         }
 548 
 549         @Override
 550         public int hashCode() {
 551             return e0.hashCode() + (e1 == null ? 0 : e1.hashCode());
 552         }
 553 
 554         @Override
 555         public Iterator<E> iterator() {
 556             return new Iterator<E>() {
 557                 private int idx = size();
 558 
 559                 @Override
 560                 public boolean hasNext() {
 561                     return idx > 0;
 562                 }
 563 
 564                 @Override
 565                 public E next() {
 566                     if (idx == 1) {
 567                         idx = 0;
 568                         return e0;
 569                     } else if (idx == 2) {
 570                         idx = 1;
 571                         return e1;
 572                     } else {
 573                         throw new NoSuchElementException();
 574                     }
 575                 }
 576             };
 577         }
 578 
 579         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 580             throw new InvalidObjectException("not serial proxy");
 581         }
 582 
 583         private Object writeReplace() {
 584             if (e1 == null) {
 585                 return new CollSer(CollSer.IMM_SET, e0);
 586             } else {
 587                 return new CollSer(CollSer.IMM_SET, e0, e1);
 588             }
 589         }
 590     }
 591 
 592     /**
 593      * An array-based Set implementation. The element array must be strictly
 594      * larger than the size (the number of contained elements) so that at
 595      * least one null is always present.
 596      * @param <E> the element type
 597      */
 598     static final class SetN<E> extends AbstractImmutableSet<E> {
 599         @Stable
 600         final E[] elements;
 601         @Stable
 602         final int size;
 603 
 604         @SafeVarargs
 605         @SuppressWarnings("unchecked")
 606         SetN(E... input) {
 607             size = input.length; // implicit nullcheck of input
 608 
 609             elements = (E[])new Object[EXPAND_FACTOR * input.length];
 610             for (int i = 0; i < input.length; i++) {
 611                 E e = input[i];
 612                 int idx = probe(e); // implicit nullcheck of e
 613                 if (idx >= 0) {
 614                     throw new IllegalArgumentException("duplicate element: " + e);
 615                 } else {
 616                     elements[-(idx + 1)] = e;
 617                 }
 618             }
 619         }
 620 
 621         @Override
 622         public int size() {
 623             return size;
 624         }
 625 
 626         @Override
 627         public boolean contains(Object o) {
 628             Objects.requireNonNull(o);
 629             return size > 0 && probe(o) >= 0; // implicit nullcheck of o
 630         }
 631 
 632         @Override
 633         public Iterator<E> iterator() {
 634             return new Iterator<E>() {
 635                 private int idx = 0;
 636 
 637                 @Override
 638                 public boolean hasNext() {
 639                     while (idx < elements.length) {
 640                         if (elements[idx] != null)
 641                             return true;
 642                         idx++;
 643                     }
 644                     return false;
 645                 }
 646 
 647                 @Override
 648                 public E next() {
 649                     if (! hasNext()) {


 684         }
 685 
 686         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 687             throw new InvalidObjectException("not serial proxy");
 688         }
 689 
 690         private Object writeReplace() {
 691             Object[] array = new Object[size];
 692             int dest = 0;
 693             for (Object o : elements) {
 694                 if (o != null) {
 695                     array[dest++] = o;
 696                 }
 697             }
 698             return new CollSer(CollSer.IMM_SET, array);
 699         }
 700     }
 701 
 702     // ---------- Map Implementations ----------
 703 
 704     static final Map<?,?> EMPTY_MAP = new MapN<>();
 705 
 706     @SuppressWarnings("unchecked")
 707     static <K,V> Map<K,V> emptyMap() {
 708         return (Map<K,V>) EMPTY_MAP;
 709     }
 710 
 711     abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
 712         @Override public void clear() { throw uoe(); }
 713         @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 714         @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
 715         @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 716         @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
 717         @Override public V put(K key, V value) { throw uoe(); }
 718         @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
 719         @Override public V putIfAbsent(K key, V value) { throw uoe(); }
 720         @Override public V remove(Object key) { throw uoe(); }
 721         @Override public boolean remove(Object key, Object value) { throw uoe(); }
 722         @Override public V replace(K key, V value) { throw uoe(); }
 723         @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
 724         @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
 725     }
 726 









































 727     static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
 728         @Stable
 729         private final K k0;
 730         @Stable
 731         private final V v0;
 732 
 733         Map1(K k0, V v0) {
 734             this.k0 = Objects.requireNonNull(k0);
 735             this.v0 = Objects.requireNonNull(v0);
 736         }
 737 
 738         @Override
 739         public Set<Map.Entry<K,V>> entrySet() {
 740             return Set.of(new KeyValueHolder<>(k0, v0));
 741         }
 742 
 743         @Override
 744         public boolean containsKey(Object o) {
 745             return o.equals(k0); // implicit nullcheck of o
 746         }


 759         }
 760 
 761         @Override
 762         public int hashCode() {
 763             return k0.hashCode() ^ v0.hashCode();
 764         }
 765     }
 766 
 767     /**
 768      * An array-based Map implementation. There is a single array "table" that
 769      * contains keys and values interleaved: table[0] is kA, table[1] is vA,
 770      * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
 771      * also be strictly larger than the size (the number of key-value pairs contained
 772      * in the map) so that at least one null key is always present.
 773      * @param <K> the key type
 774      * @param <V> the value type
 775      */
 776     static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
 777         @Stable
 778         final Object[] table; // pairs of key, value
 779 
 780         @Stable
 781         final int size; // number of pairs
 782 
 783         MapN(Object... input) {
 784             if ((input.length & 1) != 0) { // implicit nullcheck of input
 785                 throw new InternalError("length is odd");
 786             }
 787             size = input.length >> 1;
 788 
 789             int len = EXPAND_FACTOR * input.length;
 790             len = (len + 1) & ~1; // ensure table is even length
 791             table = new Object[len];
 792 
 793             for (int i = 0; i < input.length; i += 2) {
 794                 @SuppressWarnings("unchecked")
 795                     K k = Objects.requireNonNull((K)input[i]);
 796                 @SuppressWarnings("unchecked")
 797                     V v = Objects.requireNonNull((V)input[i+1]);
 798                 int idx = probe(k);
 799                 if (idx >= 0) {
 800                     throw new IllegalArgumentException("duplicate key: " + k);
 801                 } else {
 802                     int dest = -(idx + 1);
 803                     table[dest] = k;
 804                     table[dest+1] = v;
 805                 }
 806             }
 807         }
 808 
 809         @Override
 810         public boolean containsKey(Object o) {
 811             Objects.requireNonNull(o);
 812             return size > 0 && probe(o) >= 0;
 813         }
 814 
 815         @Override
 816         public boolean containsValue(Object o) {
 817             for (int i = 1; i < table.length; i += 2) {
 818                 Object v = table[i];
 819                 if (v != null && o.equals(v)) { // implicit nullcheck of o
 820                     return true;
 821                 }
 822             }
 823             return false;
 824         }
 825 
 826         @Override
 827         public int hashCode() {
 828             int hash = 0;
 829             for (int i = 0; i < table.length; i += 2) {
 830                 Object k = table[i];
 831                 if (k != null) {
 832                     hash += k.hashCode() ^ table[i + 1].hashCode();
 833                 }
 834             }
 835             return hash;
 836         }
 837 
 838         @Override
 839         @SuppressWarnings("unchecked")
 840         public V get(Object o) {
 841             if (size == 0) {
 842                 return null;
 843             }
 844             int i = probe(o);
 845             if (i >= 0) {
 846                 return (V)table[i+1];
 847             } else {
 848                 return null;
 849             }
 850         }
 851 
 852         @Override
 853         public int size() {
 854             return size;
 855         }
 856 
 857         @Override
 858         public Set<Map.Entry<K,V>> entrySet() {
 859             return new AbstractSet<Map.Entry<K,V>>() {
 860                 @Override
 861                 public int size() {
 862                     return MapN.this.size;
 863                 }


1054      * @throws InvalidObjectException if the tag value is illegal or if an exception
1055      *         is thrown during creation of the collection
1056      * @throws ObjectStreamException if another serialization error has occurred
1057      * @since 9
1058      */
1059     private Object readResolve() throws ObjectStreamException {
1060         try {
1061             if (array == null) {
1062                 throw new InvalidObjectException("null array");
1063             }
1064 
1065             // use low order 8 bits to indicate "kind"
1066             // ignore high order 24 bits
1067             switch (tag & 0xff) {
1068                 case IMM_LIST:
1069                     return List.of(array);
1070                 case IMM_SET:
1071                     return Set.of(array);
1072                 case IMM_MAP:
1073                     if (array.length == 0) {
1074                         return ImmutableCollections.emptyMap();
1075                     } else if (array.length == 2) {
1076                         return new ImmutableCollections.Map1<>(array[0], array[1]);
1077                     } else {
1078                         return new ImmutableCollections.MapN<>(array);
1079                     }
1080                 default:
1081                     throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
1082             }
1083         } catch (NullPointerException|IllegalArgumentException ex) {
1084             InvalidObjectException ioe = new InvalidObjectException("invalid object");
1085             ioe.initCause(ex);
1086             throw ioe;
1087         }
1088     }
1089 }
< prev index next >