|
1 | 1 | /* |
2 | | - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | 4 | * |
5 | 5 | * This code is free software; you can redistribute it and/or modify it |
|
36 | 36 | import java.util.function.BiFunction; |
37 | 37 | import java.util.function.Consumer; |
38 | 38 | import java.util.function.Function; |
| 39 | +import java.util.function.IntFunction; |
39 | 40 | import java.util.function.Predicate; |
| 41 | +import java.util.function.Supplier; |
40 | 42 | import java.util.function.UnaryOperator; |
| 43 | + |
41 | 44 | import jdk.internal.access.JavaUtilCollectionAccess; |
42 | 45 | import jdk.internal.access.SharedSecrets; |
| 46 | +import jdk.internal.lang.stable.StableUtil; |
| 47 | +import jdk.internal.lang.stable.StableValueImpl; |
43 | 48 | import jdk.internal.misc.CDS; |
| 49 | +import jdk.internal.util.ArraysSupport; |
| 50 | +import jdk.internal.util.NullableKeyValueHolder; |
| 51 | +import jdk.internal.vm.annotation.ForceInline; |
44 | 52 | import jdk.internal.vm.annotation.Stable; |
45 | 53 |
|
46 | 54 | /** |
@@ -128,6 +136,12 @@ public <E> List<E> listFromTrustedArray(Object[] array) { |
128 | 136 | public <E> List<E> listFromTrustedArrayNullsAllowed(Object[] array) { |
129 | 137 | return ImmutableCollections.listFromTrustedArrayNullsAllowed(array); |
130 | 138 | } |
| 139 | + public <E> List<E> stableList(int size, IntFunction<? extends E> mapper) { |
| 140 | + return ImmutableCollections.stableList(size, mapper); |
| 141 | + } |
| 142 | + public <K, V> Map<K, V> stableMap(Set<K> keys, Function<? super K, ? extends V> mapper) { |
| 143 | + return new StableMap<>(keys, mapper); |
| 144 | + } |
131 | 145 | }); |
132 | 146 | } |
133 | 147 | } |
@@ -250,6 +264,11 @@ static <E> List<E> listFromTrustedArrayNullsAllowed(Object... input) { |
250 | 264 | } |
251 | 265 | } |
252 | 266 |
|
| 267 | + static <E> List<E> stableList(int size, IntFunction<? extends E> mapper) { |
| 268 | + // A lazy list is not Serializable so, we cannot return `List.of()` if size == 0 |
| 269 | + return new StableList<>(size, mapper); |
| 270 | + } |
| 271 | + |
253 | 272 | // ---------- List Implementations ---------- |
254 | 273 |
|
255 | 274 | @jdk.internal.ValueBased |
@@ -448,7 +467,7 @@ static final class SubList<E> extends AbstractImmutableList<E> |
448 | 467 | private final int size; |
449 | 468 |
|
450 | 469 | private SubList(AbstractImmutableList<E> root, int offset, int size) { |
451 | | - assert root instanceof List12 || root instanceof ListN; |
| 470 | + assert root instanceof List12 || root instanceof ListN || root instanceof StableList; |
452 | 471 | this.root = root; |
453 | 472 | this.offset = offset; |
454 | 473 | this.size = size; |
@@ -499,7 +518,8 @@ private void rangeCheck(int index) { |
499 | 518 | } |
500 | 519 |
|
501 | 520 | private boolean allowNulls() { |
502 | | - return root instanceof ListN && ((ListN<?>)root).allowNulls; |
| 521 | + return root instanceof ListN<?> listN && listN.allowNulls |
| 522 | + || root instanceof StableList<E>; |
503 | 523 | } |
504 | 524 |
|
505 | 525 | @Override |
@@ -551,6 +571,15 @@ public <T> T[] toArray(T[] a) { |
551 | 571 | } |
552 | 572 | return array; |
553 | 573 | } |
| 574 | + |
| 575 | + @Override |
| 576 | + public String toString() { |
| 577 | + if (root instanceof StableList<E> stableList) { |
| 578 | + return StableUtil.renderElements(root, "StableList", stableList.delegates, offset, size); |
| 579 | + } else { |
| 580 | + return super.toString(); |
| 581 | + } |
| 582 | + } |
554 | 583 | } |
555 | 584 |
|
556 | 585 | @jdk.internal.ValueBased |
@@ -768,6 +797,116 @@ public int lastIndexOf(Object o) { |
768 | 797 | } |
769 | 798 | } |
770 | 799 |
|
| 800 | + @jdk.internal.ValueBased |
| 801 | + static final class StableList<E> extends AbstractImmutableList<E> { |
| 802 | + |
| 803 | + @Stable |
| 804 | + private final IntFunction<? extends E> mapper; |
| 805 | + @Stable |
| 806 | + final StableValueImpl<E>[] delegates; |
| 807 | + |
| 808 | + StableList(int size, IntFunction<? extends E> mapper) { |
| 809 | + this.mapper = mapper; |
| 810 | + this.delegates = StableUtil.array(size); |
| 811 | + } |
| 812 | + |
| 813 | + @Override public boolean isEmpty() { return delegates.length == 0;} |
| 814 | + @Override public int size() { return delegates.length; } |
| 815 | + @Override public Object[] toArray() { return copyInto(new Object[size()]); } |
| 816 | + |
| 817 | + @ForceInline |
| 818 | + @Override |
| 819 | + public E get(int i) { |
| 820 | + final StableValueImpl<E> delegate; |
| 821 | + try { |
| 822 | + delegate = delegates[i]; |
| 823 | + } catch (ArrayIndexOutOfBoundsException aioobe) { |
| 824 | + throw new IndexOutOfBoundsException(i); |
| 825 | + } |
| 826 | + return delegate.orElseSet(new Supplier<E>() { |
| 827 | + @Override public E get() { return mapper.apply(i); }}); |
| 828 | + } |
| 829 | + |
| 830 | + @Override |
| 831 | + @SuppressWarnings("unchecked") |
| 832 | + public <T> T[] toArray(T[] a) { |
| 833 | + final int size = delegates.length; |
| 834 | + if (a.length < size) { |
| 835 | + // Make a new array of a's runtime type, but my contents: |
| 836 | + T[] n = (T[])Array.newInstance(a.getClass().getComponentType(), size); |
| 837 | + return copyInto(n); |
| 838 | + } |
| 839 | + copyInto(a); |
| 840 | + if (a.length > size) { |
| 841 | + a[size] = null; // null-terminate |
| 842 | + } |
| 843 | + return a; |
| 844 | + } |
| 845 | + |
| 846 | + @Override |
| 847 | + public int indexOf(Object o) { |
| 848 | + final int size = size(); |
| 849 | + for (int i = 0; i < size; i++) { |
| 850 | + if (Objects.equals(o, get(i))) { |
| 851 | + return i; |
| 852 | + } |
| 853 | + } |
| 854 | + return -1; |
| 855 | + } |
| 856 | + |
| 857 | + @Override |
| 858 | + public int lastIndexOf(Object o) { |
| 859 | + for (int i = size() - 1; i >= 0; i--) { |
| 860 | + if (Objects.equals(o, get(i))) { |
| 861 | + return i; |
| 862 | + } |
| 863 | + } |
| 864 | + return -1; |
| 865 | + } |
| 866 | + |
| 867 | + @SuppressWarnings("unchecked") |
| 868 | + private <T> T[] copyInto(Object[] a) { |
| 869 | + final int len = delegates.length; |
| 870 | + for (int i = 0; i < len; i++) { |
| 871 | + a[i] = get(i); |
| 872 | + } |
| 873 | + return (T[]) a; |
| 874 | + } |
| 875 | + |
| 876 | + @Override |
| 877 | + public List<E> reversed() { |
| 878 | + return new StableReverseOrderListView<>(this); |
| 879 | + } |
| 880 | + |
| 881 | + @Override |
| 882 | + public String toString() { |
| 883 | + return StableUtil.renderElements(this, "StableList", delegates); |
| 884 | + } |
| 885 | + |
| 886 | + private static final class StableReverseOrderListView<E> extends ReverseOrderListView.Rand<E> { |
| 887 | + |
| 888 | + private StableReverseOrderListView(List<E> base) { |
| 889 | + super(base, false); |
| 890 | + } |
| 891 | + |
| 892 | + // This method does not evaluate the elements |
| 893 | + @Override |
| 894 | + public String toString() { |
| 895 | + final StableValueImpl<E>[] delegates = ((StableList<E>)base).delegates; |
| 896 | + final StableValueImpl<E>[] reversed = ArraysSupport.reverse( |
| 897 | + Arrays.copyOf(delegates, delegates.length)); |
| 898 | + return StableUtil.renderElements(base, "Collection", reversed); |
| 899 | + } |
| 900 | + |
| 901 | + @Override |
| 902 | + public List<E> reversed() { |
| 903 | + return base; |
| 904 | + } |
| 905 | + |
| 906 | + } |
| 907 | + |
| 908 | + } |
| 909 | + |
771 | 910 | // ---------- Set Implementations ---------- |
772 | 911 |
|
773 | 912 | @jdk.internal.ValueBased |
@@ -1112,7 +1251,7 @@ public <T> T[] toArray(T[] a) { |
1112 | 1251 | // ---------- Map Implementations ---------- |
1113 | 1252 |
|
1114 | 1253 | // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap |
1115 | | - abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable { |
| 1254 | + abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> { |
1116 | 1255 | @Override public void clear() { throw uoe(); } |
1117 | 1256 | @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); } |
1118 | 1257 | @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); } |
@@ -1143,7 +1282,7 @@ public V getOrDefault(Object key, V defaultValue) { |
1143 | 1282 | } |
1144 | 1283 |
|
1145 | 1284 | // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap |
1146 | | - static final class Map1<K,V> extends AbstractImmutableMap<K,V> { |
| 1285 | + static final class Map1<K,V> extends AbstractImmutableMap<K,V> implements Serializable { |
1147 | 1286 | @Stable |
1148 | 1287 | private final K k0; |
1149 | 1288 | @Stable |
@@ -1215,7 +1354,7 @@ public void forEach(BiConsumer<? super K, ? super V> action) { |
1215 | 1354 | * @param <V> the value type |
1216 | 1355 | */ |
1217 | 1356 | // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap |
1218 | | - static final class MapN<K,V> extends AbstractImmutableMap<K,V> { |
| 1357 | + static final class MapN<K,V> extends AbstractImmutableMap<K,V> implements Serializable { |
1219 | 1358 |
|
1220 | 1359 | @Stable |
1221 | 1360 | final Object[] table; // pairs of key, value |
@@ -1405,6 +1544,130 @@ private Object writeReplace() { |
1405 | 1544 | return new CollSer(CollSer.IMM_MAP, array); |
1406 | 1545 | } |
1407 | 1546 | } |
| 1547 | + |
| 1548 | + static final class StableMap<K, V> |
| 1549 | + extends AbstractImmutableMap<K, V> { |
| 1550 | + |
| 1551 | + @Stable |
| 1552 | + private final Function<? super K, ? extends V> mapper; |
| 1553 | + @Stable |
| 1554 | + private final Map<K, StableValueImpl<V>> delegate; |
| 1555 | + |
| 1556 | + StableMap(Set<K> keys, Function<? super K, ? extends V> mapper) { |
| 1557 | + this.mapper = mapper; |
| 1558 | + this.delegate = StableUtil.map(keys); |
| 1559 | + } |
| 1560 | + |
| 1561 | + @Override public boolean containsKey(Object o) { return delegate.containsKey(o); } |
| 1562 | + @Override public int size() { return delegate.size(); } |
| 1563 | + @Override public Set<Map.Entry<K, V>> entrySet() { return new StableMapEntrySet(); } |
| 1564 | + |
| 1565 | + @ForceInline |
| 1566 | + @Override |
| 1567 | + public V get(Object key) { |
| 1568 | + return getOrDefault(key, null); |
| 1569 | + } |
| 1570 | + |
| 1571 | + @ForceInline |
| 1572 | + @Override |
| 1573 | + public V getOrDefault(Object key, V defaultValue) { |
| 1574 | + final StableValueImpl<V> stable = delegate.get(key); |
| 1575 | + if (stable == null) { |
| 1576 | + return defaultValue; |
| 1577 | + } |
| 1578 | + @SuppressWarnings("unchecked") |
| 1579 | + final K k = (K) key; |
| 1580 | + return stable.orElseSet(new Supplier<V>() { |
| 1581 | + @Override public V get() { return mapper.apply(k); }}); |
| 1582 | + } |
| 1583 | + |
| 1584 | + @jdk.internal.ValueBased |
| 1585 | + final class StableMapEntrySet extends AbstractImmutableSet<Map.Entry<K, V>> { |
| 1586 | + |
| 1587 | + @Stable |
| 1588 | + private final Set<Map.Entry<K, StableValueImpl<V>>> delegateEntrySet; |
| 1589 | + |
| 1590 | + StableMapEntrySet() { |
| 1591 | + this.delegateEntrySet = delegate.entrySet(); |
| 1592 | + } |
| 1593 | + |
| 1594 | + @Override public Iterator<Map.Entry<K, V>> iterator() { return new LazyMapIterator(); } |
| 1595 | + @Override public int size() { return delegateEntrySet.size(); } |
| 1596 | + @Override public int hashCode() { return StableMap.this.hashCode(); } |
| 1597 | + |
| 1598 | + @Override |
| 1599 | + public String toString() { |
| 1600 | + return StableUtil.renderMappings(this, "StableSet", delegateEntrySet, false); |
| 1601 | + } |
| 1602 | + |
| 1603 | + @jdk.internal.ValueBased |
| 1604 | + final class LazyMapIterator implements Iterator<Map.Entry<K, V>> { |
| 1605 | + |
| 1606 | + @Stable |
| 1607 | + private final Iterator<Map.Entry<K, StableValueImpl<V>>> delegateIterator; |
| 1608 | + |
| 1609 | + LazyMapIterator() { |
| 1610 | + this.delegateIterator = delegateEntrySet.iterator(); |
| 1611 | + } |
| 1612 | + |
| 1613 | + @Override public boolean hasNext() { return delegateIterator.hasNext(); } |
| 1614 | + |
| 1615 | + @Override |
| 1616 | + public Entry<K, V> next() { |
| 1617 | + final Map.Entry<K, StableValueImpl<V>> inner = delegateIterator.next(); |
| 1618 | + final K k = inner.getKey(); |
| 1619 | + return new NullableKeyValueHolder<>(k, inner.getValue().orElseSet(new Supplier<V>() { |
| 1620 | + @Override public V get() { return mapper.apply(k); }})); |
| 1621 | + } |
| 1622 | + |
| 1623 | + @Override |
| 1624 | + public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) { |
| 1625 | + final Consumer<? super Map.Entry<K, StableValueImpl<V>>> innerAction = |
| 1626 | + new Consumer<>() { |
| 1627 | + @Override |
| 1628 | + public void accept(Entry<K, StableValueImpl<V>> inner) { |
| 1629 | + final K k = inner.getKey(); |
| 1630 | + action.accept(new NullableKeyValueHolder<>(k, inner.getValue().orElseSet(new Supplier<V>() { |
| 1631 | + @Override public V get() { return mapper.apply(k); }}))); |
| 1632 | + } |
| 1633 | + }; |
| 1634 | + delegateIterator.forEachRemaining(innerAction); |
| 1635 | + } |
| 1636 | + } |
| 1637 | + } |
| 1638 | + |
| 1639 | + @Override |
| 1640 | + public Collection<V> values() { |
| 1641 | + return new StableMapValues(); |
| 1642 | + } |
| 1643 | + |
| 1644 | + final class StableMapValues extends AbstractImmutableCollection<V> { |
| 1645 | + @Override public Iterator<V> iterator() { return new ValueIterator(); } |
| 1646 | + @Override public int size() { return StableMap.this.size(); } |
| 1647 | + @Override public boolean isEmpty() { return StableMap.this.isEmpty();} |
| 1648 | + @Override public boolean contains(Object v) { return StableMap.this.containsValue(v); } |
| 1649 | + |
| 1650 | + private static final IntFunction<StableValueImpl<?>[]> GENERATOR = new IntFunction<StableValueImpl<?>[]>() { |
| 1651 | + @Override |
| 1652 | + public StableValueImpl<?>[] apply(int len) { |
| 1653 | + return new StableValueImpl<?>[len]; |
| 1654 | + } |
| 1655 | + }; |
| 1656 | + |
| 1657 | + @Override |
| 1658 | + public String toString() { |
| 1659 | + final StableValueImpl<?>[] values = delegate.values().toArray(GENERATOR); |
| 1660 | + return StableUtil.renderElements(StableMap.this, "StableMap", values); |
| 1661 | + } |
| 1662 | + } |
| 1663 | + |
| 1664 | + @Override |
| 1665 | + public String toString() { |
| 1666 | + return StableUtil.renderMappings(this, "StableMap", delegate.entrySet(), true); |
| 1667 | + } |
| 1668 | + |
| 1669 | + } |
| 1670 | + |
1408 | 1671 | } |
1409 | 1672 |
|
1410 | 1673 | // ---------- Serialization Proxy ---------- |
|
0 commit comments