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