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