< prev index next >

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

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

*** 35,44 **** --- 35,45 ---- import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; import jdk.internal.misc.SharedSecrets; import jdk.internal.vm.annotation.Stable; + import sun.security.action.GetPropertyAction; /** * Container class for immutable collections. Not part of the public API. * Mainly for namespace management and shared infrastructure. *
*** 70,265 **** static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); } // ---------- List Implementations ---------- ! abstract static class AbstractImmutableList<E> extends AbstractList<E> ! implements RandomAccess, Serializable { @Override public boolean add(E e) { throw uoe(); } @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); } @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); } @Override public void clear() { throw uoe(); } @Override public boolean remove(Object o) { throw uoe(); } @Override public boolean removeAll(Collection<?> c) { throw uoe(); } @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); } @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); } @Override public boolean retainAll(Collection<?> c) { throw uoe(); } @Override public void sort(Comparator<? super E> c) { throw uoe(); } - } - - static final class List0<E> extends AbstractImmutableList<E> { - private static final List0<?> INSTANCE = new List0<>(); ! @SuppressWarnings("unchecked") ! static <T> List0<T> instance() { ! return (List0<T>) INSTANCE; } ! private List0() { } @Override ! public int size() { ! return 0; } @Override public E get(int index) { ! Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException ! return null; // but the compiler doesn't know this } - @Override public Iterator<E> iterator() { ! return Collections.emptyIterator(); } ! private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { ! throw new InvalidObjectException("not serial proxy"); } ! private Object writeReplace() { ! return new CollSer(CollSer.IMM_LIST); } @Override ! public boolean contains(Object o) { ! Objects.requireNonNull(o); ! return false; } @Override ! public boolean containsAll(Collection<?> o) { ! return o.isEmpty(); // implicit nullcheck of o } @Override ! public int hashCode() { ! return 1; } } static final class List1<E> extends AbstractImmutableList<E> { @Stable private final E e0; ! List1(E e0) { ! this.e0 = Objects.requireNonNull(e0); } @Override public int size() { return 1; } @Override public E get(int index) { Objects.checkIndex(index, 1); return e0; } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - throw new InvalidObjectException("not serial proxy"); - } - - private Object writeReplace() { - return new CollSer(CollSer.IMM_LIST, e0); - } - @Override public boolean contains(Object o) { ! return o.equals(e0); // implicit nullcheck of o } @Override public int hashCode() { return 31 + e0.hashCode(); } } - static final class List2<E> extends AbstractImmutableList<E> { @Stable private final E e0; @Stable private final E e1; ! List2(E e0, E e1) { this.e0 = Objects.requireNonNull(e0); this.e1 = Objects.requireNonNull(e1); } @Override public int size() { ! return 2; } @Override public E get(int index) { - Objects.checkIndex(index, 2); if (index == 0) { return e0; ! } else { // index == 1 return e1; } } @Override public boolean contains(Object o) { ! return o.equals(e0) || o.equals(e1); // implicit nullcheck of o } @Override public int hashCode() { int hash = 31 + e0.hashCode(); ! return 31 * hash + e1.hashCode(); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } private Object writeReplace() { return new CollSer(CollSer.IMM_LIST, e0, e1); } } static final class ListN<E> extends AbstractImmutableList<E> { @Stable private final E[] elements; @SafeVarargs ListN(E... input) { // copy and check manually to avoid TOCTOU @SuppressWarnings("unchecked") E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input for (int i = 0; i < input.length; i++) { tmp[i] = Objects.requireNonNull(input[i]); } ! this.elements = tmp; } @Override public int size() { return elements.length; } @Override public E get(int index) { - Objects.checkIndex(index, elements.length); return elements[index]; } @Override public boolean contains(Object o) { for (E e : elements) { ! if (o.equals(e)) { // implicit nullcheck of o return true; } } return false; } @Override public int hashCode() { int hash = 1; for (E e : elements) { hash = 31 * hash + e.hashCode(); } --- 71,593 ---- static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); } // ---------- List Implementations ---------- ! static abstract class AbstractImmutableList<E> extends AbstractCollection<E> ! implements List<E>, RandomAccess, Serializable { ! ! /** ! * The number of collection specializations to use; numbers 0, 1 and 2 are supported. ! * ! * 0: Only a single, generic class, e.g., ListN, will be used. This removes footprint ! * benefits of having smaller specializations, but may help make call-sites ! * monomorphic, which may improve performance. ! * 1: Single element collections will be specialized, gaining back some of the ! * footprint gains, while pushing call-sites towards being either mono- or ! * bimorphic that would otherwise be megamorphic. ! * 2: Both single and two element lists will be specialized. Best setting for ! * footprint. ! * ! * Defined here rather at top-level to get around a bootstrapping issue ! * due to ImmutableCollections (but not any of the List classes) being ! * initialized before System properties are initialized. ! */ ! static final int SPECIALIZATIONS; ! static { ! int specializations = Integer.parseInt( ! GetPropertyAction.privilegedGetProperty( ! "jdk.ImmutableCollections.specializations", "2")); ! SPECIALIZATIONS = Math.min(2, Math.max(0, specializations)); ! } ! static final List<?> EMPTY_LIST = new ListN<>(); ! ! @SuppressWarnings("unchecked") ! static <E> List<E> emptyList() { ! return (List<E>) EMPTY_LIST; ! } ! ! static <E> List<E> of(E[] elements) { ! switch (elements.length) { // implicit null check of elements ! case 0: ! return emptyList(); ! case 1: ! return of(elements[0]); ! case 2: ! return of(elements[0], elements[1]); ! default: ! return new ListN<>(elements); ! } ! } ! ! static <E> List<E> of(E e1) { ! switch (SPECIALIZATIONS) { ! case 1: ! return new List1<>(e1); ! case 2: ! return new List12<>(e1); ! default: ! return new ListN<>(e1); ! } ! } ! ! static <E> List<E> of(E e0, E e1) { ! switch (SPECIALIZATIONS) { ! case 2: ! return new List12<>(e0, e1); ! default: ! return new ListN<>(e0, e1); ! } ! } ! ! // all mutating methods throw UnsupportedOperationException @Override public boolean add(E e) { throw uoe(); } + @Override public void add(int index, E element) { throw uoe(); } @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); } @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); } @Override public void clear() { throw uoe(); } @Override public boolean remove(Object o) { throw uoe(); } + @Override public E remove(int index) { throw uoe(); } @Override public boolean removeAll(Collection<?> c) { throw uoe(); } @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); } @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); } @Override public boolean retainAll(Collection<?> c) { throw uoe(); } + @Override public E set(int index, E element) { throw uoe(); } @Override public void sort(Comparator<? super E> c) { throw uoe(); } ! @Override ! public int indexOf(Object o) { ! // Should be checked for null, needs a CSR. See ! // Objects.requireNonNull(o); ! ListIterator<E> it = listIterator(); ! while (it.hasNext()) { ! if (o.equals(it.next())) { ! return it.previousIndex(); ! } ! } ! return -1; } ! @Override ! public int lastIndexOf(Object o) { ! Objects.requireNonNull(o); ! ListIterator<E> it = listIterator(); ! while (it.hasNext()) { ! if (o.equals(it.next())) { ! return it.previousIndex(); ! } ! } ! return -1; ! } @Override ! public boolean isEmpty() { ! return size() == 0; } @Override + public List<E> subList(int fromIndex, int toIndex) { + int size = size(); + Objects.checkFromToIndex(fromIndex, toIndex, size); + if (size == 0 || fromIndex == toIndex) { + return ListN.emptyList(); + } else if (size == 1) { + // checks above deal with corner cases subList(0,0) and subList(1,1) + // that would return the empty list + assert(fromIndex == 0 && toIndex == 1); + return this; + } else { + return new SubList<E>(this, fromIndex, toIndex); + } + } + + private static class SubList<E> extends AbstractList<E> implements RandomAccess { + private final List<E> root; + private final int offset; + int size; + + // all mutating methods throw UnsupportedOperationException + @Override public boolean add(E e) { throw uoe(); } + @Override public void add(int index, E element) { throw uoe(); } + @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); } + @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); } + @Override public void clear() { throw uoe(); } + @Override public boolean remove(Object o) { throw uoe(); } + @Override public E remove(int index) { throw uoe(); } + @Override public boolean removeAll(Collection<?> c) { throw uoe(); } + @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); } + @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); } + @Override public boolean retainAll(Collection<?> c) { throw uoe(); } + @Override public E set(int index, E element) { throw uoe(); } + @Override public void sort(Comparator<? super E> c) { throw uoe(); } + + /** + * Constructs a sublist of an arbitrary AbstractList, which is + * not a SubList itself. + */ + public SubList(List<E> root, int fromIndex, int toIndex) { + this.root = root; + this.offset = fromIndex; + this.size = toIndex - fromIndex; + } + + /** + * Constructs a sublist of another SubList. + */ + protected SubList(SubList<E> parent, int fromIndex, int toIndex) { + this.root = parent.root; + this.offset = parent.offset + fromIndex; + this.size = toIndex - fromIndex; + } + public E get(int index) { ! Objects.checkIndex(index, size); ! return root.get(offset + index); ! } ! ! public int size() { ! return size; ! } ! ! protected void removeRange(int fromIndex, int toIndex) { ! throw uoe(); } public Iterator<E> iterator() { ! return listIterator(); } ! public ListIterator<E> listIterator(int index) { ! rangeCheck(index); ! ! return new ListIterator<E>() { ! private final ListIterator<E> i = ! root.listIterator(offset + index); ! ! public boolean hasNext() { ! return nextIndex() < size; } ! public E next() { ! if (hasNext()) ! return i.next(); ! else ! throw new NoSuchElementException(); ! } ! ! public boolean hasPrevious() { ! return previousIndex() >= 0; ! } ! ! public E previous() { ! if (hasPrevious()) ! return i.previous(); ! else ! throw new NoSuchElementException(); ! } ! ! public int nextIndex() { ! return i.nextIndex() - offset; ! } ! ! public int previousIndex() { ! return i.previousIndex() - offset; ! } ! ! public void remove() { throw uoe(); } ! public void set(E e) { throw uoe(); } ! public void add(E e) { throw uoe(); } ! }; ! } ! ! public List<E> subList(int fromIndex, int toIndex) { ! subListRangeCheck(fromIndex, toIndex, size); ! return new SubList<>(this, fromIndex, toIndex); ! } ! ! private void rangeCheck(int index) { ! if (index < 0 || index > size) ! throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); ! } ! ! private String outOfBoundsMsg(int index) { ! return "Index: "+index+", Size: "+size; ! } } @Override ! public Iterator<E> iterator() { ! return new Itr(); } @Override ! public ListIterator<E> listIterator() { ! return listIterator(0); } @Override ! public ListIterator<E> listIterator(final int index) { ! Objects.checkIndex(index, size()); ! return new ListItr(index); ! } ! ! private class Itr implements Iterator<E> { ! Itr() { ! size = size(); ! } ! ! int cursor = 0; ! ! private final int size; ! ! public boolean hasNext() { ! return cursor != size; ! } ! ! public E next() { ! try { ! int i = cursor; ! E next = get(i); ! cursor = i + 1; ! return next; ! } catch (IndexOutOfBoundsException e) { ! throw new NoSuchElementException(); ! } ! } ! ! public void remove() { ! throw uoe(); ! } ! } ! ! private class ListItr extends Itr implements ListIterator<E> { ! ListItr(int index) { ! cursor = index; ! } ! ! public boolean hasPrevious() { ! return cursor != 0; ! } ! ! public E previous() { ! try { ! int i = cursor - 1; ! E previous = get(i); ! cursor = i; ! return previous; ! } catch (IndexOutOfBoundsException e) { ! throw new NoSuchElementException(); ! } } + + public int nextIndex() { + return cursor; + } + + public int previousIndex() { + return cursor - 1; + } + + public void set(E e) { + throw uoe(); + } + + public void add(E e) { + throw uoe(); + } + } + + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof List)) { + return false; + } + + Iterator<E> e1 = iterator(); + Iterator<?> e2 = ((List<?>) o).iterator(); + while (e1.hasNext() && e2.hasNext()) { + E o1 = e1.next(); + Object o2 = e2.next(); + if (!(o1==null ? o2==null : o1.equals(o2))) + return false; + } + return !(e1.hasNext() || e2.hasNext()); + } + + IndexOutOfBoundsException outOfBounds(int index) { + return new IndexOutOfBoundsException("Index: " + index + " Size: " + size()); + } + } static final class List1<E> extends AbstractImmutableList<E> { + @Stable private final E e0; ! List1(E input) { ! e0 = Objects.requireNonNull(input); } @Override + @SuppressWarnings("unchecked") public int size() { return 1; } @Override + @SuppressWarnings("unchecked") public E get(int index) { Objects.checkIndex(index, 1); return e0; } @Override + @SuppressWarnings("unchecked") public boolean contains(Object o) { ! return o.equals(e0); // implicit null check of o } @Override + @SuppressWarnings("unchecked") public int hashCode() { return 31 + e0.hashCode(); } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + @SuppressWarnings("unchecked") + private Object writeReplace() { + return new CollSer(CollSer.IMM_LIST, e0); } + } + + static final class List12<E> extends AbstractImmutableList<E> { @Stable private final E e0; + @Stable private final E e1; ! List12(E e0) { ! this.e0 = Objects.requireNonNull(e0); ! this.e1 = null; ! } ! ! List12(E e0, E e1) { this.e0 = Objects.requireNonNull(e0); this.e1 = Objects.requireNonNull(e1); } @Override + @SuppressWarnings("unchecked") public int size() { ! return e1 != null ? 2 : 1; } @Override + @SuppressWarnings("unchecked") public E get(int index) { if (index == 0) { return e0; ! } else if (e1 != null && index == 1) { return e1; } + throw outOfBounds(index); } @Override + @SuppressWarnings("unchecked") public boolean contains(Object o) { ! return o.equals(e0) || o.equals(e1); // implicit null check of o } @Override + @SuppressWarnings("unchecked") public int hashCode() { int hash = 31 + e0.hashCode(); ! if (e1 != null) { ! hash = 31 * hash + e1.hashCode(); ! } ! return hash; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } + @SuppressWarnings("unchecked") private Object writeReplace() { return new CollSer(CollSer.IMM_LIST, e0, e1); } } static final class ListN<E> extends AbstractImmutableList<E> { + @Stable private final E[] elements; + @SuppressWarnings("unchecked") + ListN(E e0) { + elements = (E[])new Object[] { e0 }; + } + + @SuppressWarnings("unchecked") + ListN(E e0, E e1) { + elements = (E[])new Object[] { e0, e1 }; + } + @SafeVarargs ListN(E... input) { // copy and check manually to avoid TOCTOU @SuppressWarnings("unchecked") E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input for (int i = 0; i < input.length; i++) { tmp[i] = Objects.requireNonNull(input[i]); } ! elements = tmp; ! } ! ! @Override ! public boolean isEmpty() { ! return size() == 0; } @Override + @SuppressWarnings("unchecked") public int size() { return elements.length; } @Override + @SuppressWarnings("unchecked") public E get(int index) { return elements[index]; } @Override + @SuppressWarnings("unchecked") public boolean contains(Object o) { + Objects.requireNonNull(o); for (E e : elements) { ! if (o.equals(e)) { return true; } } return false; } @Override + @SuppressWarnings("unchecked") public int hashCode() { int hash = 1; for (E e : elements) { hash = 31 * hash + e.hashCode(); }
*** 268,336 **** private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } private Object writeReplace() { return new CollSer(CollSer.IMM_LIST, elements); } } // ---------- Set Implementations ---------- abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable { @Override public boolean add(E e) { throw uoe(); } @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); } @Override public void clear() { throw uoe(); } @Override public boolean remove(Object o) { throw uoe(); } @Override public boolean removeAll(Collection<?> c) { throw uoe(); } @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); } @Override public boolean retainAll(Collection<?> c) { throw uoe(); } - } - - static final class Set0<E> extends AbstractImmutableSet<E> { - private static final Set0<?> INSTANCE = new Set0<>(); @SuppressWarnings("unchecked") ! static <T> Set0<T> instance() { ! return (Set0<T>) INSTANCE; } - - private Set0() { } - - @Override - public int size() { - return 0; } ! @Override ! public boolean contains(Object o) { ! Objects.requireNonNull(o); ! return false; } - - @Override - public boolean containsAll(Collection<?> o) { - return o.isEmpty(); // implicit nullcheck of o - } - - @Override - public Iterator<E> iterator() { - return Collections.emptyIterator(); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - throw new InvalidObjectException("not serial proxy"); } ! private Object writeReplace() { ! return new CollSer(CollSer.IMM_SET); } - - @Override - public int hashCode() { - return 0; } } static final class Set1<E> extends AbstractImmutableSet<E> { @Stable --- 596,661 ---- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } + @SuppressWarnings("unchecked") private Object writeReplace() { return new CollSer(CollSer.IMM_LIST, elements); } } // ---------- Set Implementations ---------- + static final Set<?> EMPTY_SET = new SetN<>(); + + @SuppressWarnings("unchecked") + static <E> Set<E> emptySet() { + return (Set<E>) EMPTY_SET; + } + abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable { @Override public boolean add(E e) { throw uoe(); } @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); } @Override public void clear() { throw uoe(); } @Override public boolean remove(Object o) { throw uoe(); } @Override public boolean removeAll(Collection<?> c) { throw uoe(); } @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); } @Override public boolean retainAll(Collection<?> c) { throw uoe(); } @SuppressWarnings("unchecked") ! static <E> Set<E> of(E[] elements) { ! switch (elements.length) { // implicit null check of elements ! case 0: ! return emptySet(); ! case 1: ! return of(elements[0]); ! case 2: ! return of(elements[0], elements[1]); ! default: ! return new SetN<>(elements); } } ! static <E> Set<E> of(E e1) { ! switch (AbstractImmutableList.SPECIALIZATIONS) { ! case 1: ! return new Set1<>(e1); ! case 2: ! return new Set12<>(e1); ! default: ! return new SetN<>(e1); } } ! static <E> Set<E> of(E e0, E e1) { ! switch (AbstractImmutableList.SPECIALIZATIONS) { ! case 2: ! return new Set12<>(e0, e1); ! default: ! return new SetN<>(e0, e1); } } } static final class Set1<E> extends AbstractImmutableSet<E> { @Stable
*** 367,383 **** public int hashCode() { return e0.hashCode(); } } ! static final class Set2<E> extends AbstractImmutableSet<E> { @Stable final E e0; @Stable final E e1; ! Set2(E e0, E e1) { if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0 throw new IllegalArgumentException("duplicate element: " + e0); } if (SALT >= 0) { --- 692,713 ---- public int hashCode() { return e0.hashCode(); } } ! static final class Set12<E> extends AbstractImmutableSet<E> { @Stable final E e0; @Stable final E e1; ! Set12(E e0) { ! this.e0 = Objects.requireNonNull(e0); ! this.e1 = null; ! } ! ! Set12(E e0, E e1) { if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0 throw new IllegalArgumentException("duplicate element: " + e0); } if (SALT >= 0) {
*** 389,428 **** } } @Override public int size() { ! return 2; } @Override public boolean contains(Object o) { return o.equals(e0) || o.equals(e1); // implicit nullcheck of o } @Override public int hashCode() { ! return e0.hashCode() + e1.hashCode(); } @Override public Iterator<E> iterator() { return new Iterator<E>() { ! private int idx = 0; @Override public boolean hasNext() { ! return idx < 2; } @Override public E next() { ! if (idx == 0) { ! idx = 1; return e0; ! } else if (idx == 1) { ! idx = 2; return e1; } else { throw new NoSuchElementException(); } } --- 719,758 ---- } } @Override public int size() { ! return (e1 == null) ? 1 : 2; } @Override public boolean contains(Object o) { return o.equals(e0) || o.equals(e1); // implicit nullcheck of o } @Override public int hashCode() { ! return e0.hashCode() + (e1 == null ? 0 : e1.hashCode()); } @Override public Iterator<E> iterator() { return new Iterator<E>() { ! private int idx = size(); @Override public boolean hasNext() { ! return idx > 0; } @Override public E next() { ! if (idx == 1) { ! idx = 0; return e0; ! } else if (idx == 2) { ! idx = 1; return e1; } else { throw new NoSuchElementException(); } }
*** 472,482 **** return size; } @Override public boolean contains(Object o) { ! return probe(o) >= 0; // implicit nullcheck of o } @Override public Iterator<E> iterator() { return new Iterator<E>() { --- 802,813 ---- return size; } @Override public boolean contains(Object o) { ! Objects.requireNonNull(0); ! return size > 0 && probe(o) >= 0; // implicit nullcheck of o } @Override public Iterator<E> iterator() { return new Iterator<E>() {
*** 547,556 **** --- 878,894 ---- } } // ---------- Map Implementations ---------- + static final Map<?,?> EMPTY_MAP = new MapN<>(); + + @SuppressWarnings("unchecked") + static <K,V> Map<K,V> emptyMap() { + return (Map<K,V>) EMPTY_MAP; + } + abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable { @Override public void clear() { throw uoe(); } @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); } @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); } @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
*** 561,610 **** @Override public V remove(Object key) { throw uoe(); } @Override public boolean remove(Object key, Object value) { throw uoe(); } @Override public V replace(K key, V value) { throw uoe(); } @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); } @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); } - } ! static final class Map0<K,V> extends AbstractImmutableMap<K,V> { ! private static final Map0<?,?> INSTANCE = new Map0<>(); ! ! @SuppressWarnings("unchecked") ! static <K,V> Map0<K,V> instance() { ! return (Map0<K,V>) INSTANCE; } - - private Map0() { } - - @Override - public Set<Map.Entry<K,V>> entrySet() { - return Set.of(); } ! @Override ! public boolean containsKey(Object o) { ! Objects.requireNonNull(o); ! return false; ! } ! ! @Override ! public boolean containsValue(Object o) { ! Objects.requireNonNull(o); ! return false; ! } ! ! private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { ! throw new InvalidObjectException("not serial proxy"); } ! ! private Object writeReplace() { ! return new CollSer(CollSer.IMM_MAP); } - - @Override - public int hashCode() { - return 0; } } static final class Map1<K,V> extends AbstractImmutableMap<K,V> { @Stable --- 899,936 ---- @Override public V remove(Object key) { throw uoe(); } @Override public boolean remove(Object key, Object value) { throw uoe(); } @Override public V replace(K key, V value) { throw uoe(); } @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); } @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); } ! static <K, V> Map<K, V> of(K k1, V v1) { ! if (AbstractImmutableList.SPECIALIZATIONS > 0) { ! return new ImmutableCollections.Map1<>(k1, v1); ! } else { ! return new ImmutableCollections.MapN<>(k1, v1); } } ! @SafeVarargs ! @SuppressWarnings("varargs") ! static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) { ! if (entries.length == 0) { // implicit null check of entries array ! return ImmutableCollections.emptyMap(); ! } else if (AbstractImmutableList.SPECIALIZATIONS > 0 && entries.length == 1) { ! // implicit null check of the array slot ! return new ImmutableCollections.Map1<>(entries[0].getKey(), ! entries[0].getValue()); ! } else { ! Object[] kva = new Object[entries.length << 1]; ! int a = 0; ! for (Entry<? extends K, ? extends V> entry : entries) { ! // implicit null checks of each array slot ! kva[a++] = entry.getKey(); ! kva[a++] = entry.getValue(); } ! return new ImmutableCollections.MapN<>(kva); } } } static final class Map1<K,V> extends AbstractImmutableMap<K,V> { @Stable
*** 656,668 **** * @param <V> the value type */ static final class MapN<K,V> extends AbstractImmutableMap<K,V> { @Stable final Object[] table; // pairs of key, value - @Stable final int size; // number of pairs MapN(Object... input) { if ((input.length & 1) != 0) { // implicit nullcheck of input throw new InternalError("length is odd"); } size = input.length >> 1; --- 982,1000 ---- * @param <V> the value type */ static final class MapN<K,V> extends AbstractImmutableMap<K,V> { @Stable final Object[] table; // pairs of key, value final int size; // number of pairs + MapN(K key, V value) { + table = new Object[2]; + table[0] = key; + table[1] = value; + size = 1; + } + MapN(Object... input) { if ((input.length & 1) != 0) { // implicit nullcheck of input throw new InternalError("length is odd"); } size = input.length >> 1;
*** 687,697 **** } } @Override public boolean containsKey(Object o) { ! return probe(o) >= 0; // implicit nullcheck of o } @Override public boolean containsValue(Object o) { for (int i = 1; i < table.length; i += 2) { --- 1019,1030 ---- } } @Override public boolean containsKey(Object o) { ! Objects.requireNonNull(0); ! return size > 0 && probe(o) >= 0; } @Override public boolean containsValue(Object o) { for (int i = 1; i < table.length; i += 2) {
*** 716,725 **** --- 1049,1061 ---- } @Override @SuppressWarnings("unchecked") public V get(Object o) { + if (size == 0) { + return null; + } int i = probe(o); if (i >= 0) { return (V)table[i+1]; } else { return null;
*** 946,956 **** return List.of(array); case IMM_SET: return Set.of(array); case IMM_MAP: if (array.length == 0) { ! return ImmutableCollections.Map0.instance(); } else if (array.length == 2) { return new ImmutableCollections.Map1<>(array[0], array[1]); } else { return new ImmutableCollections.MapN<>(array); } --- 1282,1292 ---- return List.of(array); case IMM_SET: return Set.of(array); case IMM_MAP: if (array.length == 0) { ! return ImmutableCollections.emptyMap(); } else if (array.length == 2) { return new ImmutableCollections.Map1<>(array[0], array[1]); } else { return new ImmutableCollections.MapN<>(array); }
< prev index next >