1 /* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util; 27 28 import java.io.IOException; 29 import java.io.InvalidObjectException; 30 import java.io.ObjectInputStream; 31 import java.io.ObjectOutputStream; 32 import java.io.ObjectStreamException; 33 import java.io.Serializable; 34 import java.util.function.BiFunction; 35 import java.util.function.Function; 36 import java.util.function.Predicate; 37 import java.util.function.UnaryOperator; 38 import jdk.internal.misc.SharedSecrets; 39 import jdk.internal.vm.annotation.Stable; 40 41 /** 42 * Container class for immutable collections. Not part of the public API. 43 * Mainly for namespace management and shared infrastructure. 44 * 45 * Serial warnings are suppressed throughout because all implementation 46 * classes use a serial proxy and thus have no need to declare serialVersionUID. 47 */ 48 @SuppressWarnings("serial") 49 class ImmutableCollections { 50 /** 51 * A "salt" value used for randomizing iteration order. This is initialized once 52 * and stays constant for the lifetime of the JVM. It need not be truly random, but 53 * it needs to vary sufficiently from one run to the next so that iteration order 54 * will vary between JVM runs. 55 */ 56 static final int SALT; 57 static { 58 long nt = System.nanoTime(); 59 SALT = (int)((nt >>> 32) ^ nt); 60 } 61 62 /** No instances. */ 63 private ImmutableCollections() { } 64 65 /** 66 * The reciprocal of load factor. Given a number of elements 67 * to store, multiply by this factor to get the table size. 68 */ 69 static final int EXPAND_FACTOR = 2; 70 71 static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); } 72 73 // ---------- List Implementations ---------- 74 75 static final List<?> EMPTY_LIST = new ListN<>(); 76 77 @SuppressWarnings("unchecked") 78 static <E> List<E> emptyList() { 79 return (List<E>) EMPTY_LIST; 80 } 81 82 static abstract class AbstractImmutableList<E> extends AbstractCollection<E> 83 implements List<E>, RandomAccess { 84 85 // all mutating methods throw UnsupportedOperationException 86 @Override public boolean add(E e) { throw uoe(); } 87 @Override public void add(int index, E element) { throw uoe(); } 88 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); } 89 @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); } 90 @Override public void clear() { throw uoe(); } 91 @Override public boolean remove(Object o) { throw uoe(); } 92 @Override public E remove(int index) { throw uoe(); } 93 @Override public boolean removeAll(Collection<?> c) { throw uoe(); } 94 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); } 95 @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); } 96 @Override public boolean retainAll(Collection<?> c) { throw uoe(); } 97 @Override public E set(int index, E element) { throw uoe(); } 98 @Override public void sort(Comparator<? super E> c) { throw uoe(); } 99 100 @Override 101 public int indexOf(Object o) { 102 // Input should be checked for null, but this needs a CSR. See JDK-8191418 103 if (o == null) { 104 return -1; 105 } 106 // Objects.requireNonNull(o); 107 ListIterator<E> it = listIterator(); 108 while (it.hasNext()) { 109 if (o.equals(it.next())) { 110 return it.previousIndex(); 111 } 112 } 113 return -1; 114 } 115 116 @Override 117 public int lastIndexOf(Object o) { 118 // Input should be checked for null, but this needs a CSR. See JDK-8191418 119 if (o == null) { 120 return -1; 121 } 122 // Objects.requireNonNull(o); 123 124 ListIterator<E> it = listIterator(); 125 while (it.hasNext()) { 126 if (o.equals(it.next())) { 127 return it.previousIndex(); 128 } 129 } 130 return -1; 131 } 132 133 @Override 134 public boolean isEmpty() { 135 return size() == 0; 136 } 137 138 @Override 139 public List<E> subList(int fromIndex, int toIndex) { 140 int size = size(); 141 subListRangeCheck(fromIndex, toIndex, size); 142 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()) { 650 throw new NoSuchElementException(); 651 } 652 return elements[idx++]; 653 } 654 }; 655 } 656 657 @Override 658 public int hashCode() { 659 int h = 0; 660 for (E e : elements) { 661 if (e != null) { 662 h += e.hashCode(); 663 } 664 } 665 return h; 666 } 667 668 // returns index at which element is present; or if absent, 669 // (-i - 1) where i is location where element should be inserted. 670 // Callers are relying on this method to perform an implicit nullcheck 671 // of pe 672 private int probe(Object pe) { 673 int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length); 674 while (true) { 675 E ee = elements[idx]; 676 if (ee == null) { 677 return -idx - 1; 678 } else if (pe.equals(ee)) { 679 return idx; 680 } else if (++idx == elements.length) { 681 idx = 0; 682 } 683 } 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 } 747 748 @Override 749 public boolean containsValue(Object o) { 750 return o.equals(v0); // implicit nullcheck of o 751 } 752 753 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 754 throw new InvalidObjectException("not serial proxy"); 755 } 756 757 private Object writeReplace() { 758 return new CollSer(CollSer.IMM_MAP, k0, v0); 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 } 864 865 @Override 866 public Iterator<Map.Entry<K,V>> iterator() { 867 return new Iterator<Map.Entry<K,V>>() { 868 int idx = 0; 869 870 @Override 871 public boolean hasNext() { 872 while (idx < table.length) { 873 if (table[idx] != null) 874 return true; 875 idx += 2; 876 } 877 return false; 878 } 879 880 @Override 881 public Map.Entry<K,V> next() { 882 if (hasNext()) { 883 @SuppressWarnings("unchecked") 884 Map.Entry<K,V> e = 885 new KeyValueHolder<>((K)table[idx], (V)table[idx+1]); 886 idx += 2; 887 return e; 888 } else { 889 throw new NoSuchElementException(); 890 } 891 } 892 }; 893 } 894 }; 895 } 896 897 // returns index at which the probe key is present; or if absent, 898 // (-i - 1) where i is location where element should be inserted. 899 // Callers are relying on this method to perform an implicit nullcheck 900 // of pk. 901 private int probe(Object pk) { 902 int idx = Math.floorMod(pk.hashCode() ^ SALT, table.length >> 1) << 1; 903 while (true) { 904 @SuppressWarnings("unchecked") 905 K ek = (K)table[idx]; 906 if (ek == null) { 907 return -idx - 1; 908 } else if (pk.equals(ek)) { 909 return idx; 910 } else if ((idx += 2) == table.length) { 911 idx = 0; 912 } 913 } 914 } 915 916 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 917 throw new InvalidObjectException("not serial proxy"); 918 } 919 920 private Object writeReplace() { 921 Object[] array = new Object[2 * size]; 922 int len = table.length; 923 int dest = 0; 924 for (int i = 0; i < len; i += 2) { 925 if (table[i] != null) { 926 array[dest++] = table[i]; 927 array[dest++] = table[i+1]; 928 } 929 } 930 return new CollSer(CollSer.IMM_MAP, array); 931 } 932 } 933 } 934 935 // ---------- Serialization Proxy ---------- 936 937 /** 938 * A unified serialization proxy class for the immutable collections. 939 * 940 * @serial 941 * @since 9 942 */ 943 final class CollSer implements Serializable { 944 private static final long serialVersionUID = 6309168927139932177L; 945 946 static final int IMM_LIST = 1; 947 static final int IMM_SET = 2; 948 static final int IMM_MAP = 3; 949 950 /** 951 * Indicates the type of collection that is serialized. 952 * The low order 8 bits have the value 1 for an immutable 953 * {@code List}, 2 for an immutable {@code Set}, and 3 for 954 * an immutable {@code Map}. Any other value causes an 955 * {@link InvalidObjectException} to be thrown. The high 956 * order 24 bits are zero when an instance is serialized, 957 * and they are ignored when an instance is deserialized. 958 * They can thus be used by future implementations without 959 * causing compatibility issues. 960 * 961 * <p>The tag value also determines the interpretation of the 962 * transient {@code Object[] array} field. 963 * For {@code List} and {@code Set}, the array's length is the size 964 * of the collection, and the array contains the elements of the collection. 965 * Null elements are not allowed. For {@code Set}, duplicate elements 966 * are not allowed. 967 * 968 * <p>For {@code Map}, the array's length is twice the number of mappings 969 * present in the map. The array length is necessarily even. 970 * The array contains a succession of key and value pairs: 971 * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed, 972 * and duplicate keys are not allowed. 973 * 974 * @serial 975 * @since 9 976 */ 977 private final int tag; 978 979 /** 980 * @serial 981 * @since 9 982 */ 983 private transient Object[] array; 984 985 CollSer(int t, Object... a) { 986 tag = t; 987 array = a; 988 } 989 990 /** 991 * Reads objects from the stream and stores them 992 * in the transient {@code Object[] array} field. 993 * 994 * @serialData 995 * A nonnegative int, indicating the count of objects, 996 * followed by that many objects. 997 * 998 * @param ois the ObjectInputStream from which data is read 999 * @throws IOException if an I/O error occurs 1000 * @throws ClassNotFoundException if a serialized class cannot be loaded 1001 * @throws InvalidObjectException if the count is negative 1002 * @since 9 1003 */ 1004 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 1005 ois.defaultReadObject(); 1006 int len = ois.readInt(); 1007 1008 if (len < 0) { 1009 throw new InvalidObjectException("negative length " + len); 1010 } 1011 1012 SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, len); 1013 Object[] a = new Object[len]; 1014 for (int i = 0; i < len; i++) { 1015 a[i] = ois.readObject(); 1016 } 1017 1018 array = a; 1019 } 1020 1021 /** 1022 * Writes objects to the stream from 1023 * the transient {@code Object[] array} field. 1024 * 1025 * @serialData 1026 * A nonnegative int, indicating the count of objects, 1027 * followed by that many objects. 1028 * 1029 * @param oos the ObjectOutputStream to which data is written 1030 * @throws IOException if an I/O error occurs 1031 * @since 9 1032 */ 1033 private void writeObject(ObjectOutputStream oos) throws IOException { 1034 oos.defaultWriteObject(); 1035 oos.writeInt(array.length); 1036 for (int i = 0; i < array.length; i++) { 1037 oos.writeObject(array[i]); 1038 } 1039 } 1040 1041 /** 1042 * Creates and returns an immutable collection from this proxy class. 1043 * The instance returned is created as if by calling one of the 1044 * static factory methods for 1045 * <a href="List.html#immutable">List</a>, 1046 * <a href="Map.html#immutable">Map</a>, or 1047 * <a href="Set.html#immutable">Set</a>. 1048 * This proxy class is the serial form for all immutable collection instances, 1049 * regardless of implementation type. This is necessary to ensure that the 1050 * existence of any particular implementation type is kept out of the 1051 * serialized form. 1052 * 1053 * @return a collection created from this proxy object 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 }