# HG changeset patch # User sspitsyn # Date 1462566972 0 # Node ID 6a5f9d068fc59f2228712a9cf5321df808a42e75 # Parent 78e5cb21ca13f19441dcfa5f9f07b3338683e36a# Parent 91fc9ac7b8b3a1477e49bbb4ccc0755a59003c42 Merge diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java Fri May 06 20:36:12 2016 +0000 @@ -1527,12 +1527,9 @@ * ss 2 appendValue(ChronoField.SECOND_OF_MINUTE, 2) * * S..S 1..n appendFraction(ChronoField.NANO_OF_SECOND, n, n, false) - * A 1 appendValue(ChronoField.MILLI_OF_DAY) - * A..A 2..n appendValue(ChronoField.MILLI_OF_DAY, n) - * n 1 appendValue(ChronoField.NANO_OF_SECOND) - * n..n 2..n appendValue(ChronoField.NANO_OF_SECOND, n) - * N 1 appendValue(ChronoField.NANO_OF_DAY) - * N..N 2..n appendValue(ChronoField.NANO_OF_DAY, n) + * A..A 1..n appendValue(ChronoField.MILLI_OF_DAY, n, 19, SignStyle.NOT_NEGATIVE) + * n..n 1..n appendValue(ChronoField.NANO_OF_SECOND, n, 19, SignStyle.NOT_NEGATIVE) + * N..N 1..n appendValue(ChronoField.NANO_OF_DAY, n, 19, SignStyle.NOT_NEGATIVE) * *

* Zone ID: Pattern letters to output {@code ZoneId}. @@ -1850,6 +1847,11 @@ case 'g': appendValue(field, count, 19, SignStyle.NORMAL); break; + case 'A': + case 'n': + case 'N': + appendValue(field, count, 19, SignStyle.NOT_NEGATIVE); + break; default: if (count == 1) { appendValue(field); diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.base/share/classes/java/util/ImmutableCollections.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java Fri May 06 20:36:12 2016 +0000 @@ -0,0 +1,657 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; + +/** + * Container class for immutable collections. Not part of the public API. + * Mainly for namespace management and shared infrastructure. + * + * Serial warnings are suppressed throughout because all implementation + * classes use a serial proxy and thus have no need to declare serialVersionUID. + */ +@SuppressWarnings("serial") +class ImmutableCollections { + /** + * A "salt" value used for randomizing iteration order. This is initialized once + * and stays constant for the lifetime of the JVM. It need not be truly random, but + * it needs to vary sufficiently from one run to the next so that iteration order + * will vary between JVM runs. + */ + static final int SALT; + static { + SALT = new Random().nextInt(); + } + + /** No instances. */ + private ImmutableCollections() { } + + /** + * The reciprocal of load factor. Given a number of elements + * to store, multiply by this factor to get the table size. + */ + static final double EXPAND_FACTOR = 2.0; + + // ---------- List Implementations ---------- + + static final class List0 extends AbstractList implements RandomAccess, Serializable { + 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 + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + private Object writeReplace() { + return new CollSer(CollSer.IMM_LIST); + } + } + + static final class List1 extends AbstractList implements RandomAccess, Serializable { + 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); + // assert index == 0 + 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); + } + } + + static final class List2 extends AbstractList implements RandomAccess, Serializable { + private final E e0; + 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; + } + } + + 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 extends AbstractList implements RandomAccess, Serializable { + 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]; + } + + 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 ---------- + + static final class Set0 extends AbstractSet implements Serializable { + Set0() { } + + @Override + public int size() { + return 0; + } + + @Override + public boolean contains(Object o) { + return super.contains(Objects.requireNonNull(o)); + } + + @Override + public Iterator 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); + } + } + + static final class Set1 extends AbstractSet implements Serializable { + private final E e0; + + Set1(E e0) { + this.e0 = Objects.requireNonNull(e0); + } + + @Override + public int size() { + return 1; + } + + @Override + public boolean contains(Object o) { + return super.contains(Objects.requireNonNull(o)); + } + + @Override + public Iterator iterator() { + return Collections.singletonIterator(e0); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + private Object writeReplace() { + return new CollSer(CollSer.IMM_SET, e0); + } + } + + static final class Set2 extends AbstractSet implements Serializable { + private final E e0; + private final E e1; + + Set2(E e0, E e1) { + Objects.requireNonNull(e0); + Objects.requireNonNull(e1); + + if (e0.equals(e1)) { + throw new IllegalArgumentException("duplicate element: " + e0); + } + + if (SALT >= 0) { + this.e0 = e0; + this.e1 = e1; + } else { + this.e0 = e1; + this.e1 = e0; + } + } + + @Override + public int size() { + return 2; + } + + @Override + public boolean contains(Object o) { + return super.contains(Objects.requireNonNull(o)); + } + + @Override + public Iterator iterator() { + return new Iterator() { + 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(); + } + } + }; + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + private Object writeReplace() { + return new CollSer(CollSer.IMM_SET, e0, e1); + } + } + + /** + * An array-based Set implementation. The element array must be strictly + * larger than the size (the number of contained elements) so that at + * least one null is always present. + * @param the element type + */ + static final class SetN extends AbstractSet implements Serializable { + private final E[] elements; + private final int size; + + @SafeVarargs + @SuppressWarnings("unchecked") + SetN(E... input) { + size = input.length; // implicit nullcheck of input + + elements = (E[])new Object[(int)Math.ceil(EXPAND_FACTOR * input.length)]; + for (int i = 0; i < input.length; i++) { + E e = Objects.requireNonNull(input[i]); + int idx = probe(e); + if (idx >= 0) { + throw new IllegalArgumentException("duplicate element: " + e); + } else { + elements[-(idx + 1)] = e; + } + } + } + + @Override + public int size() { + return size; + } + + @Override + public boolean contains(Object o) { + Objects.requireNonNull(o); + return probe(o) >= 0; + } + + @Override + public Iterator iterator() { + return new Iterator() { + private int idx = 0; + + @Override + public boolean hasNext() { + while (idx < elements.length) { + if (elements[idx] != null) + return true; + idx++; + } + return false; + } + + @Override + public E next() { + if (! hasNext()) { + throw new NoSuchElementException(); + } + return elements[idx++]; + } + }; + } + + // returns index at which element is present; or if absent, + // (-i - 1) where i is location where element should be inserted + private int probe(Object pe) { + int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length); + while (true) { + E ee = elements[idx]; + if (ee == null) { + return -idx - 1; + } else if (pe.equals(ee)) { + return idx; + } else if (++idx == elements.length) { + idx = 0; + } + } + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + private Object writeReplace() { + Object[] array = new Object[size]; + int dest = 0; + for (Object o : elements) { + if (o != null) { + array[dest++] = o; + } + } + return new CollSer(CollSer.IMM_SET, array); + } + } + + // ---------- Map Implementations ---------- + + static final class Map0 extends AbstractMap implements Serializable { + Map0() { } + + @Override + public Set> entrySet() { + return Set.of(); + } + + @Override + public boolean containsKey(Object o) { + return super.containsKey(Objects.requireNonNull(o)); + } + + @Override + public boolean containsValue(Object o) { + return super.containsValue(Objects.requireNonNull(o)); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + private Object writeReplace() { + return new CollSer(CollSer.IMM_MAP); + } + } + + static final class Map1 extends AbstractMap implements Serializable { + private final K k0; + private final V v0; + + Map1(K k0, V v0) { + this.k0 = Objects.requireNonNull(k0); + this.v0 = Objects.requireNonNull(v0); + } + + @Override + public Set> entrySet() { + return Set.of(new KeyValueHolder<>(k0, v0)); + } + + @Override + public boolean containsKey(Object o) { + return super.containsKey(Objects.requireNonNull(o)); + } + + @Override + public boolean containsValue(Object o) { + return super.containsValue(Objects.requireNonNull(o)); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + private Object writeReplace() { + return new CollSer(CollSer.IMM_MAP, k0, v0); + } + } + + /** + * An array-based Map implementation. There is a single array "table" that + * contains keys and values interleaved: table[0] is kA, table[1] is vA, + * table[2] is kB, table[3] is vB, etc. The table size must be even. It must + * also be strictly larger than the size (the number of key-value pairs contained + * in the map) so that at least one null key is always present. + * @param the key type + * @param the value type + */ + static final class MapN extends AbstractMap implements Serializable { + private final Object[] table; // pairs of key, value + private final int size; // number of pairs + + MapN(Object... input) { + Objects.requireNonNull(input); + if ((input.length & 1) != 0) { + throw new InternalError("length is odd"); + } + size = input.length >> 1; + + int len = (int)Math.ceil(EXPAND_FACTOR * input.length); + len = (len + 1) & ~1; // ensure table is even length + table = new Object[len]; + + for (int i = 0; i < input.length; i += 2) { + @SuppressWarnings("unchecked") + K k = Objects.requireNonNull((K)input[i]); + @SuppressWarnings("unchecked") + V v = Objects.requireNonNull((V)input[i+1]); + int idx = probe(k); + if (idx >= 0) { + throw new IllegalArgumentException("duplicate key: " + k); + } else { + int dest = -(idx + 1); + table[dest] = k; + table[dest+1] = v; + } + } + } + + @Override + public boolean containsKey(Object o) { + return probe(Objects.requireNonNull(o)) >= 0; + } + + @Override + public boolean containsValue(Object o) { + return super.containsValue(Objects.requireNonNull(o)); + } + + @Override + @SuppressWarnings("unchecked") + public V get(Object o) { + int i = probe(o); + if (i >= 0) { + return (V)table[i+1]; + } else { + return null; + } + } + + @Override + public int size() { + return size; + } + + @Override + public Set> entrySet() { + return new AbstractSet>() { + @Override + public int size() { + return MapN.this.size; + } + + @Override + public Iterator> iterator() { + return new Iterator>() { + int idx = 0; + + @Override + public boolean hasNext() { + while (idx < table.length) { + if (table[idx] != null) + return true; + idx += 2; + } + return false; + } + + @Override + public Map.Entry next() { + if (hasNext()) { + @SuppressWarnings("unchecked") + Map.Entry e = + new KeyValueHolder<>((K)table[idx], (V)table[idx+1]); + idx += 2; + return e; + } else { + throw new NoSuchElementException(); + } + } + }; + } + }; + } + + // returns index at which the probe key is present; or if absent, + // (-i - 1) where i is location where element should be inserted + private int probe(Object pk) { + int idx = Math.floorMod(pk.hashCode() ^ SALT, table.length >> 1) << 1; + while (true) { + @SuppressWarnings("unchecked") + K ek = (K)table[idx]; + if (ek == null) { + return -idx - 1; + } else if (pk.equals(ek)) { + return idx; + } else if ((idx += 2) == table.length) { + idx = 0; + } + } + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + private Object writeReplace() { + Object[] array = new Object[2 * size]; + int len = table.length; + int dest = 0; + for (int i = 0; i < len; i += 2) { + if (table[i] != null) { + array[dest++] = table[i]; + array[dest++] = table[i+1]; + } + } + return new CollSer(CollSer.IMM_MAP, array); + } + } +} + +// ---------- Serialization Proxy ---------- + +/** + * Serialization proxy class for immutable collections. + */ +final class CollSer implements Serializable { + private static final long serialVersionUID = 6309168927139932177L; + + static final int IMM_LIST = 1; + static final int IMM_SET = 2; + static final int IMM_MAP = 3; + + private final int flags; + private final Object[] array; + + CollSer(int f, Object... a) { + flags = f; + array = a; + } + + private Object readResolve() throws ObjectStreamException { + try { + if (array == null) { + throw new InvalidObjectException("null array"); + } + + // use low order 8 bits to indicate "kind" + // ignore high order bits + switch (flags & 0xff) { + case IMM_LIST: + return List.of(array); + case IMM_SET: + return Set.of(array); + case IMM_MAP: + if (array.length == 0) { + return new ImmutableCollections.Map0<>(); + } else if (array.length == 2) { + return new ImmutableCollections.Map1<>(array[0], array[1]); + } else { + return new ImmutableCollections.MapN<>(array); + } + default: + throw new InvalidObjectException(String.format("invalid flags 0x%x", flags)); + } + } catch (NullPointerException|IllegalArgumentException ex) { + InvalidObjectException ioe = new InvalidObjectException("invalid object"); + ioe.initCause(ex); + throw ioe; + } + } +} diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.base/share/classes/java/util/List.java --- a/jdk/src/java.base/share/classes/java/util/List.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/util/List.java Fri May 06 20:36:12 2016 +0000 @@ -765,7 +765,7 @@ * @since 9 */ static List of() { - return Collections.emptyList(); + return new ImmutableCollections.List0<>(); } /** @@ -781,7 +781,7 @@ * @since 9 */ static List of(E e1) { - return Collections.singletonList(Objects.requireNonNull(e1)); + return new ImmutableCollections.List1<>(e1); } /** @@ -798,9 +798,7 @@ * @since 9 */ static List of(E e1, E e2) { - return Collections.unmodifiableList( - Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2))); + return new ImmutableCollections.List2<>(e1, e2); } /** @@ -818,10 +816,7 @@ * @since 9 */ static List of(E e1, E e2, E e3) { - return Collections.unmodifiableList( - Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3))); + return new ImmutableCollections.ListN<>(e1, e2, e3); } /** @@ -840,11 +835,7 @@ * @since 9 */ static List of(E e1, E e2, E e3, E e4) { - return Collections.unmodifiableList( - Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4))); + return new ImmutableCollections.ListN<>(e1, e2, e3, e4); } /** @@ -864,12 +855,7 @@ * @since 9 */ static List of(E e1, E e2, E e3, E e4, E e5) { - return Collections.unmodifiableList( - Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5))); + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5); } /** @@ -890,13 +876,8 @@ * @since 9 */ static List of(E e1, E e2, E e3, E e4, E e5, E e6) { - return Collections.unmodifiableList( - Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6))); + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6); } /** @@ -918,14 +899,8 @@ * @since 9 */ static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) { - return Collections.unmodifiableList( - Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6), - Objects.requireNonNull(e7))); + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6, e7); } /** @@ -948,15 +923,8 @@ * @since 9 */ static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { - return Collections.unmodifiableList( - Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6), - Objects.requireNonNull(e7), - Objects.requireNonNull(e8))); + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6, e7, e8); } /** @@ -980,16 +948,8 @@ * @since 9 */ static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { - return Collections.unmodifiableList( - Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6), - Objects.requireNonNull(e7), - Objects.requireNonNull(e8), - Objects.requireNonNull(e9))); + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6, e7, e8, e9); } /** @@ -1014,17 +974,8 @@ * @since 9 */ static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) { - return Collections.unmodifiableList( - Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6), - Objects.requireNonNull(e7), - Objects.requireNonNull(e8), - Objects.requireNonNull(e9), - Objects.requireNonNull(e10))); + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6, e7, e8, e9, e10); } /** @@ -1055,10 +1006,16 @@ @SafeVarargs @SuppressWarnings("varargs") static List of(E... elements) { - elements = elements.clone(); // throws NPE if es is null - for (E e : elements) { - Objects.requireNonNull(e); + Objects.requireNonNull(elements); + switch (elements.length) { + case 0: + return new ImmutableCollections.List0<>(); + case 1: + return new ImmutableCollections.List1<>(elements[0]); + case 2: + return new ImmutableCollections.List2<>(elements[0], elements[1]); + default: + return new ImmutableCollections.ListN<>(elements); } - return Collections.unmodifiableList(Arrays.asList(elements)); } } diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.base/share/classes/java/util/Map.java --- a/jdk/src/java.base/share/classes/java/util/Map.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/util/Map.java Fri May 06 20:36:12 2016 +0000 @@ -1282,7 +1282,7 @@ * @since 9 */ static Map of() { - return Collections.emptyMap(); + return new ImmutableCollections.Map0<>(); } /** @@ -1299,7 +1299,7 @@ * @since 9 */ static Map of(K k1, V v1) { - return Collections.singletonMap(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); + return new ImmutableCollections.Map1<>(k1, v1); } /** @@ -1319,13 +1319,7 @@ * @since 9 */ static Map of(K k1, V v1, K k2, V v2) { - Map map = new HashMap<>(3); // specify number of buckets to avoid resizing - map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); - map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2)); - if (map.size() != 2) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); + return new ImmutableCollections.MapN<>(k1, v1, k2, v2); } /** @@ -1347,14 +1341,7 @@ * @since 9 */ static Map of(K k1, V v1, K k2, V v2, K k3, V v3) { - Map map = new HashMap<>(5); // specify number of buckets to avoid resizing - map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); - map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2)); - map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3)); - if (map.size() != 3) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3); } /** @@ -1378,15 +1365,7 @@ * @since 9 */ static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { - Map map = new HashMap<>(6); // specify number of buckets to avoid resizing - map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); - map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2)); - map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3)); - map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4)); - if (map.size() != 4) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4); } /** @@ -1412,16 +1391,7 @@ * @since 9 */ static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { - Map map = new HashMap<>(7); // specify number of buckets to avoid resizing - map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); - map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2)); - map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3)); - map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4)); - map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5)); - if (map.size() != 5) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); } /** @@ -1450,17 +1420,8 @@ */ static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) { - Map map = new HashMap<>(9); // specify number of buckets to avoid resizing - map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); - map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2)); - map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3)); - map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4)); - map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5)); - map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6)); - if (map.size() != 6) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6); } /** @@ -1491,18 +1452,8 @@ */ static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) { - Map map = new HashMap<>(10); // specify number of buckets to avoid resizing - map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); - map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2)); - map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3)); - map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4)); - map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5)); - map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6)); - map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7)); - if (map.size() != 7) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6, k7, v7); } /** @@ -1535,19 +1486,8 @@ */ static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) { - Map map = new HashMap<>(11); // specify number of buckets to avoid resizing - map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); - map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2)); - map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3)); - map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4)); - map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5)); - map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6)); - map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7)); - map.put(Objects.requireNonNull(k8), Objects.requireNonNull(v8)); - if (map.size() != 8) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6, k7, v7, k8, v8); } /** @@ -1582,20 +1522,8 @@ */ static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) { - Map map = new HashMap<>(13); // specify number of buckets to avoid resizing - map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); - map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2)); - map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3)); - map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4)); - map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5)); - map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6)); - map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7)); - map.put(Objects.requireNonNull(k8), Objects.requireNonNull(v8)); - map.put(Objects.requireNonNull(k9), Objects.requireNonNull(v9)); - if (map.size() != 9) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6, k7, v7, k8, v8, k9, v9); } /** @@ -1632,21 +1560,8 @@ */ static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) { - Map map = new HashMap<>(14); // specify number of buckets to avoid resizing - map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); - map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2)); - map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3)); - map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4)); - map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5)); - map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6)); - map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7)); - map.put(Objects.requireNonNull(k8), Objects.requireNonNull(v8)); - map.put(Objects.requireNonNull(k9), Objects.requireNonNull(v9)); - map.put(Objects.requireNonNull(k10), Objects.requireNonNull(v10)); - if (map.size() != 10) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6, k7, v7, k8, v8, k9, v9, k10, v10); } /** @@ -1683,15 +1598,21 @@ @SafeVarargs @SuppressWarnings("varargs") static Map ofEntries(Entry... entries) { - Map map = new HashMap<>(entries.length * 4 / 3 + 1); // throws NPE if entries is null - for (Entry e : entries) { - // next line throws NPE if e is null - map.put(Objects.requireNonNull(e.getKey()), Objects.requireNonNull(e.getValue())); + Objects.requireNonNull(entries); + if (entries.length == 0) { + return new ImmutableCollections.Map0<>(); + } else if (entries.length == 1) { + return new ImmutableCollections.Map1<>(entries[0].getKey(), + entries[0].getValue()); + } else { + Object[] kva = new Object[entries.length << 1]; + int a = 0; + for (Entry entry : entries) { + kva[a++] = entry.getKey(); + kva[a++] = entry.getValue(); + } + return new ImmutableCollections.MapN<>(kva); } - if (map.size() != entries.length) { - throw new IllegalArgumentException("duplicate keys"); - } - return Collections.unmodifiableMap(map); } /** diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.base/share/classes/java/util/Set.java --- a/jdk/src/java.base/share/classes/java/util/Set.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.base/share/classes/java/util/Set.java Fri May 06 20:36:12 2016 +0000 @@ -444,7 +444,7 @@ * @since 9 */ static Set of() { - return Collections.emptySet(); + return new ImmutableCollections.Set0<>(); } /** @@ -459,7 +459,7 @@ * @since 9 */ static Set of(E e1) { - return Collections.singleton(Objects.requireNonNull(e1)); + return new ImmutableCollections.Set1<>(e1); } /** @@ -476,12 +476,7 @@ * @since 9 */ static Set of(E e1, E e2) { - Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2))); - if (set.size() != 2) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); + return new ImmutableCollections.Set2<>(e1, e2); } /** @@ -499,13 +494,7 @@ * @since 9 */ static Set of(E e1, E e2, E e3) { - Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3))); - if (set.size() != 3) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); + return new ImmutableCollections.SetN<>(e1, e2, e3); } /** @@ -524,14 +513,7 @@ * @since 9 */ static Set of(E e1, E e2, E e3, E e4) { - Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4))); - if (set.size() != 4) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); + return new ImmutableCollections.SetN<>(e1, e2, e3, e4); } /** @@ -551,15 +533,7 @@ * @since 9 */ static Set of(E e1, E e2, E e3, E e4, E e5) { - Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5))); - if (set.size() != 5) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5); } /** @@ -580,16 +554,8 @@ * @since 9 */ static Set of(E e1, E e2, E e3, E e4, E e5, E e6) { - Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6))); - if (set.size() != 6) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6); } /** @@ -611,17 +577,8 @@ * @since 9 */ static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) { - Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6), - Objects.requireNonNull(e7))); - if (set.size() != 7) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6, e7); } /** @@ -644,18 +601,8 @@ * @since 9 */ static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { - Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6), - Objects.requireNonNull(e7), - Objects.requireNonNull(e8))); - if (set.size() != 8) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6, e7, e8); } /** @@ -679,19 +626,8 @@ * @since 9 */ static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { - Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6), - Objects.requireNonNull(e7), - Objects.requireNonNull(e8), - Objects.requireNonNull(e9))); - if (set.size() != 9) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6, e7, e8, e9); } /** @@ -716,20 +652,8 @@ * @since 9 */ static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) { - Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), - Objects.requireNonNull(e2), - Objects.requireNonNull(e3), - Objects.requireNonNull(e4), - Objects.requireNonNull(e5), - Objects.requireNonNull(e6), - Objects.requireNonNull(e7), - Objects.requireNonNull(e8), - Objects.requireNonNull(e9), - Objects.requireNonNull(e10))); - if (set.size() != 10) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6, e7, e8, e9, e10); } /** @@ -759,15 +683,18 @@ * @since 9 */ @SafeVarargs + @SuppressWarnings("varargs") static Set of(E... elements) { - for (E e : elements) { // throws NPE if es is null - Objects.requireNonNull(e); + Objects.requireNonNull(elements); + switch (elements.length) { + case 0: + return new ImmutableCollections.Set0<>(); + case 1: + return new ImmutableCollections.Set1<>(elements[0]); + case 2: + return new ImmutableCollections.Set2<>(elements[0], elements[1]); + default: + return new ImmutableCollections.SetN<>(elements); } - @SuppressWarnings("varargs") - Set set = new HashSet<>(Arrays.asList(elements)); - if (set.size() != elements.length) { - throw new IllegalArgumentException("duplicate elements"); - } - return Collections.unmodifiableSet(set); } } diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.desktop/share/native/libawt/java2d/loops/FourByteAbgr.h --- a/jdk/src/java.desktop/share/native/libawt/java2d/loops/FourByteAbgr.h Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.desktop/share/native/libawt/java2d/loops/FourByteAbgr.h Fri May 06 20:36:12 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,4 +191,11 @@ COMP_PREFIX ## A, COMP_PREFIX ## R, \ COMP_PREFIX ## G, COMP_PREFIX ## B) +/* + * SrcOver ## TYPE ## BlendFactor + * Returns appropriate blend value for use in blending calculations. + */ +#define SrcOverFourByteAbgrBlendFactor(dF, dA) \ + (dA) + #endif /* FourByteAbgr_h_Included */ diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.desktop/share/native/libawt/java2d/loops/FourByteAbgrPre.h --- a/jdk/src/java.desktop/share/native/libawt/java2d/loops/FourByteAbgrPre.h Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.desktop/share/native/libawt/java2d/loops/FourByteAbgrPre.h Fri May 06 20:36:12 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -217,4 +217,11 @@ (pRas)[4*(x)+3] = (jubyte) COMP_PREFIX ## R; \ } while (0) +/* + * SrcOver ## TYPE ## BlendFactor + * Returns appropriate blend value for use in blending calculations. + */ +#define SrcOverFourByteAbgrPreBlendFactor(dF, dA) \ + (dF) + #endif /* FourByteAbgrPre_h_Included */ diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.desktop/share/native/libawt/java2d/loops/IntArgb.h --- a/jdk/src/java.desktop/share/native/libawt/java2d/loops/IntArgb.h Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.desktop/share/native/libawt/java2d/loops/IntArgb.h Fri May 06 20:36:12 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,4 +208,11 @@ COMP_PREFIX ## A = (COMP_PREFIX ## A << 8) + COMP_PREFIX ## A; \ } while (0) +/* + * SrcOver ## TYPE ## BlendFactor + * Returns appropriate blend value for use in blending calculations. + */ +#define SrcOverIntArgbBlendFactor(dF, dA) \ + (dA) + #endif /* IntArgb_h_Included */ diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.desktop/share/native/libawt/java2d/loops/IntArgbBm.h --- a/jdk/src/java.desktop/share/native/libawt/java2d/loops/IntArgbBm.h Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.desktop/share/native/libawt/java2d/loops/IntArgbBm.h Fri May 06 20:36:12 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,4 +206,11 @@ COMP_PREFIX ## A = (COMP_PREFIX ## A << 8) + COMP_PREFIX ## A; \ } while (0) +/* + * SrcOver ## TYPE ## BlendFactor + * Returns appropriate blend value for use in blending calculations. + */ +#define SrcOverIntArgbBmBlendFactor(dF, dA) \ + (dA) + #endif /* IntArgbBm_h_Included */ diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.desktop/share/native/libawt/java2d/loops/IntArgbPre.h --- a/jdk/src/java.desktop/share/native/libawt/java2d/loops/IntArgbPre.h Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.desktop/share/native/libawt/java2d/loops/IntArgbPre.h Fri May 06 20:36:12 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -216,4 +216,11 @@ COMP_PREFIX ## G, \ COMP_PREFIX ## B) +/* + * SrcOver ## TYPE ## BlendFactor + * Returns appropriate blend value for use in blending calculations. + */ +#define SrcOverIntArgbPreBlendFactor(dF, dA) \ + (dF) + #endif /* IntArgbPre_h_Included */ diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.desktop/share/native/libawt/java2d/loops/LoopMacros.h --- a/jdk/src/java.desktop/share/native/libawt/java2d/loops/LoopMacros.h Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.desktop/share/native/libawt/java2d/loops/LoopMacros.h Fri May 06 20:36:12 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1668,31 +1668,83 @@ } \ } while (0); +/* + * Antialiased glyph drawing results in artifacts around the character edges + * when text is drawn ontop of translucent background color. The standard + * blending equation for two colors: + * destColor = srcColor * glyphAlpha + destColor * (1 - glyphAlpha) + * works only when srcColor and destColor are opaque. For translucent srcColor + * and destColor, the respective alpha components in each color will influence + * the visibility of the color and the visibility of the color below it. Hence + * the equation for blending is given as: + * resA = srcAlpha + dstAlpha * (1 - srcAlpha) + * resCol = (srcColor * srcAlpha + destColor * destAlpha * (1- srcAlpha))/resA + * In addition, srcAlpha is multiplied with the glyphAlpha- that indicates the + * grayscale mask value of the glyph being drawn. The combined result provides + * smooth antialiased text on the buffer without any artifacts. Since the + * logic is executed for every pixel in a glyph, the implementation is further + * optimized to reduce computation and improve execution time. + */ #define GlyphListAABlend4ByteArgb(DST, GLYPH_PIXELS, PIXEL_INDEX, DST_PTR, \ FG_PIXEL, PREFIX, SRC_PREFIX) \ - do { \ - DeclareAlphaVarFor4ByteArgb(dstA) \ - DeclareCompVarsFor4ByteArgb(dst) \ + do { \ + DeclareAlphaVarFor4ByteArgb(resA) \ + DeclareCompVarsFor4ByteArgb(res) \ jint mixValSrc = GLYPH_PIXELS[PIXEL_INDEX]; \ if (mixValSrc) { \ - if (mixValSrc < 255) { \ - jint mixValDst = 255 - mixValSrc; \ - Load ## DST ## To4ByteArgb(DST_PTR, pix, PIXEL_INDEX, \ - dstA, dstR, dstG, dstB); \ - dstA = MUL8(dstA, mixValDst) + \ - MUL8(SRC_PREFIX ## A, mixValSrc); \ - MultMultAddAndStore4ByteArgbComps(dst, mixValDst, dst, \ - mixValSrc, SRC_PREFIX); \ - if (!(DST ## IsOpaque) && \ - !(DST ## IsPremultiplied) && dstA && dstA < 255) { \ - DivideAndStore4ByteArgbComps(dst, dst, dstA); \ + if (mixValSrc != 0xff) { \ + PromoteByteAlphaFor4ByteArgb(mixValSrc); \ + resA = MultiplyAlphaFor4ByteArgb(mixValSrc, SRC_PREFIX ## A); \ + } else { \ + resA = SRC_PREFIX ## A; \ + } \ + if (resA != MaxValFor4ByteArgb) { \ + DeclareAndInvertAlphaVarFor4ByteArgb(dstF, resA) \ + DeclareAndClearAlphaVarFor4ByteArgb(dstA) \ + DeclareCompVarsFor4ByteArgb(dst) \ + DeclareCompVarsFor4ByteArgb(tmp) \ + MultiplyAndStore4ByteArgbComps(res, resA, SRC_PREFIX); \ + if (!(DST ## IsPremultiplied)) { \ + Load ## DST ## To4ByteArgb(DST_PTR, pix, PIXEL_INDEX, \ + dstA, dstR, dstG, dstB); \ + Store4ByteArgbCompsUsingOp(tmp, =, dst); \ + } else { \ + Declare ## DST ## AlphaLoadData(DstPix) \ + jint pixelOffset = PIXEL_INDEX * (DST ## PixelStride); \ + DST ## DataType *pixelAddress = PtrAddBytes(DST_PTR, \ + pixelOffset); \ + LoadAlphaFrom ## DST ## For4ByteArgb(pixelAddress, \ + DstPix, \ + dst); \ + Postload4ByteArgbFrom ## DST(pixelAddress, \ + DstPix, \ + tmp); \ } \ - Store ## DST ## From4ByteArgbComps(DST_PTR, pix, \ - PIXEL_INDEX, dst); \ + if (dstA) { \ + DeclareAlphaVarFor4ByteArgb(blendF) \ + dstA = MultiplyAlphaFor4ByteArgb(dstF, dstA); \ + resA += dstA; \ + blendF = SrcOver ## DST ## BlendFactor(dstF, dstA); \ + if (blendF != MaxValFor4ByteArgb) { \ + MultiplyAndStore4ByteArgbComps(tmp, \ + blendF, \ + tmp); \ + } \ + Store4ByteArgbCompsUsingOp(res, +=, tmp); \ + } \ } else { \ Store ## DST ## PixelData(DST_PTR, PIXEL_INDEX, \ FG_PIXEL, PREFIX); \ + break; \ } \ + if (!(DST ## IsOpaque) && \ + !(DST ## IsPremultiplied) && resA && \ + resA < MaxValFor4ByteArgb) \ + { \ + DivideAndStore4ByteArgbComps(res, res, resA); \ + } \ + Store ## DST ## From4ByteArgbComps(DST_PTR, pix, \ + PIXEL_INDEX, res); \ } \ } while (0); diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java --- a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java Fri May 06 20:36:12 2016 +0000 @@ -144,13 +144,9 @@ sslParameters = Utils.copySSLParameters(sslp); if (alpn != null) { sslParameters.setApplicationProtocols(alpn); - Log.logSSL("Setting application protocols: " + Arrays.toString(alpn)); - } else { - Log.logSSL("No application protocols proposed"); } + logParams(sslParameters); engine.setSSLParameters(sslParameters); - engine.setEnabledCipherSuites(sslp.getCipherSuites()); - engine.setEnabledProtocols(sslp.getProtocols()); this.lowerOutput = lowerOutput; this.client = client; this.channelInputQ = new Queue<>(); @@ -560,24 +556,26 @@ return sslParameters; } - static void printParams(SSLParameters p) { - System.out.println("SSLParameters:"); + static void logParams(SSLParameters p) { + if (!Log.ssl()) + return; + Log.logSSL("SSLParameters:"); if (p == null) { - System.out.println("Null params"); + Log.logSSL("Null params"); return; } for (String cipher : p.getCipherSuites()) { - System.out.printf("cipher: %s\n", cipher); + Log.logSSL("cipher: {0}\n", cipher); } for (String approto : p.getApplicationProtocols()) { - System.out.printf("application protocol: %s\n", approto); + Log.logSSL("application protocol: {0}\n", approto); } for (String protocol : p.getProtocols()) { - System.out.printf("protocol: %s\n", protocol); + Log.logSSL("protocol: {0}\n", protocol); } if (p.getServerNames() != null) - for (SNIServerName sname : p.getServerNames()) { - System.out.printf("server name: %s\n", sname.toString()); + for (SNIServerName sname : p.getServerNames()) { + Log.logSSL("server name: {0}\n", sname.toString()); } } diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java --- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java Fri May 06 20:36:12 2016 +0000 @@ -110,7 +110,10 @@ this.proxySelector = builder.proxy; authenticator = builder.authenticator; version = builder.version; - sslParams = builder.sslParams; + if (builder.sslParams == null) + sslParams = getDefaultParams(sslContext); + else + sslParams = builder.sslParams; connections = new ConnectionPool(); connections.start(); timeouts = new LinkedList<>(); @@ -129,6 +132,12 @@ selmgr.start(); } + private static SSLParameters getDefaultParams(SSLContext ctx) { + SSLParameters params = ctx.getSupportedSSLParameters(); + params.setProtocols(new String[]{"TLSv1.2"}); + return params; + } + /** * Wait for activity on given exchange (assuming blocking = false). * It's a no-op if blocking = true. In particular, the following occurs diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java --- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java Fri May 06 20:36:12 2016 +0000 @@ -66,8 +66,6 @@ Log.logSSL("No application protocols proposed"); } engine.setSSLParameters(sslParameters); - engine.setEnabledCipherSuites(sslp.getCipherSuites()); - engine.setEnabledProtocols(sslp.getProtocols()); wrapper = new EngineWrapper(chan, engine); this.chan = chan; this.client = client; diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/test/java/awt/Graphics2D/DrawString/AntialiasedTextArtifact.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Graphics2D/DrawString/AntialiasedTextArtifact.java Fri May 06 20:36:12 2016 +0000 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8015070 + * @summary Tests for artifacts around the edges of anti-aliased text + * drawn over translucent background color. + */ +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.io.IOException; + +public class AntialiasedTextArtifact { + /* Image dimensions */ + private static final int TEST_IMAGE_WIDTH = 2800; + private static final int TEST_IMAGE_HEIGHT = 100; + private static final String TEST_STRING = + "The quick brown fox jumps over the lazy dog. 0123456789."; + + /* + * The artifacts appear when text is drawn ontop of translucent + * background. In other words, a background with alpha channel. + * Hence we test the algorithm for image types that contain either + * straight alpha channel or pre-multiplied alpha channel. In + * addition we test the images with other common pixel formats. + */ + private static final int[] TYPES = {BufferedImage.TYPE_INT_ARGB, + BufferedImage.TYPE_INT_ARGB_PRE, + BufferedImage.TYPE_4BYTE_ABGR, + BufferedImage.TYPE_4BYTE_ABGR_PRE, + BufferedImage.TYPE_INT_RGB, + BufferedImage.TYPE_INT_BGR, + BufferedImage.TYPE_3BYTE_BGR}; + + public static void main(String[] args) throws IOException { + /* Iterate over different image types */ + for (int type : TYPES) { + BufferedImage testImg = getBufferedImage(type); + + /* Draw anti-aliased string and check for artifacts */ + drawAntialiasedString(testImg); + checkArtifact(testImg); + } + } + + private static BufferedImage getBufferedImage(int imageType) { + /* Create a Graphics2D object from the given image type */ + BufferedImage image = new BufferedImage(TEST_IMAGE_WIDTH, + TEST_IMAGE_HEIGHT, + imageType); + return image; + } + + private static void drawAntialiasedString(BufferedImage image) { + /* Create Graphics2D object */ + Graphics2D graphics = (Graphics2D) image.getGraphics(); + + /* Fill the image with translucent color */ + graphics.setColor(new Color(127, 127, 127, 127)); + graphics.fillRect(0, 0, TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT); + + /* Drawstring with Antialiasing hint */ + graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + Font font = new Font("Verdana" , Font.PLAIN, 60); + graphics.setFont(font); + graphics.setColor(new Color(255, 0, 0)); + graphics.drawString(TEST_STRING, 10, 75); + graphics.dispose(); + } + + private static void checkArtifact(BufferedImage image) throws IOException { + int componentMask = 0xff; + int colorThreshold = 200; + int rowIndex = 0; + int colIndex = 0; + + /* Loop through every pixel to check for possible artifact */ + for (rowIndex = 0; rowIndex < image.getHeight(); rowIndex++) { + for (colIndex = 0; colIndex < image.getWidth(); colIndex++) { + /* + * API: getRGB(x,y) returns color in INT_ARGB color space. + * Extract individual color components with a simple mask. + */ + int colorValue = image.getRGB(colIndex, rowIndex); + int colorComponent1 = colorValue & componentMask; + int colorComponent2 = (colorValue>>8) & componentMask; + int colorComponent3 = (colorValue>>16) & componentMask; + + /* + * Artifacts are predominantly a subjective decision based on + * the quality of the rendered image content. However, in the + * current use-case, the artifacts around the edges of the anti + * aliased text appear like spots of white pixels without any + * relation to the color of foreground text or the background + * translucent shape. + * + * To identify the artifact pixels, each color component from + * the testImage is compared with a constant threshold. The + * component threshold has been set based on observation from + * different experiments on mulitple Java versions. + */ + if (colorComponent1 >= colorThreshold + && colorComponent2 >= colorThreshold + && colorComponent3 >= colorThreshold) { + /* Artifact has been noticed. Report error. */ + throw new RuntimeException("Test Failed."); + } + } + } + } +} diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/test/java/net/httpclient/http2/BasicTest.java --- a/jdk/test/java/net/httpclient/http2/BasicTest.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/test/java/net/httpclient/http2/BasicTest.java Fri May 06 20:36:12 2016 +0000 @@ -98,6 +98,7 @@ simpleTest(true); streamTest(false); streamTest(true); + paramsTest(); Thread.sleep(1000 * 4); } finally { httpServer.stop(); @@ -180,6 +181,30 @@ System.err.println("DONE"); } + static void paramsTest() throws Exception { + Http2TestServer server = new Http2TestServer(true, 0, (t -> { + SSLSession s = t.getSSLSession(); + String prot = s.getProtocol(); + if (prot.equals("TLSv1.2")) { + t.sendResponseHeaders(200, -1); + } else { + System.err.printf("Protocols =%s\n", prot); + t.sendResponseHeaders(500, -1); + } + }), exec, sslContext); + server.start(); + int port = server.getAddress().getPort(); + URI u = new URI("https://127.0.0.1:"+port+"/foo"); + HttpClient client = getClient(); + HttpRequest req = client.request(u) + .GET(); + HttpResponse resp = req.response(); + int stat = resp.statusCode(); + if (stat != 200) { + throw new RuntimeException("paramsTest failed " + + Integer.toString(stat)); + } + } static void simpleTest(boolean secure) throws Exception { URI uri = getURI(secure); diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestExchange.java --- a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestExchange.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestExchange.java Fri May 06 20:36:12 2016 +0000 @@ -5,6 +5,7 @@ import java.io.IOException; import java.net.URI; import java.net.InetSocketAddress; +import javax.net.ssl.SSLSession; public class Http2TestExchange { @@ -14,6 +15,7 @@ final String method; final InputStream is; final BodyOutputStream os; + final SSLSession sslSession; final int streamid; final boolean pushAllowed; final Http2TestServerConnection conn; @@ -24,6 +26,7 @@ Http2TestExchange(int streamid, String method, HttpHeadersImpl reqheaders, HttpHeadersImpl rspheaders, URI uri, InputStream is, + SSLSession sslSession, BodyOutputStream os, Http2TestServerConnection conn, boolean pushAllowed) { this.reqheaders = reqheaders; this.rspheaders = rspheaders; @@ -32,6 +35,7 @@ this.is = is; this.streamid = streamid; this.os = os; + this.sslSession = sslSession; this.pushAllowed = pushAllowed; this.conn = conn; this.server = conn.server; @@ -53,6 +57,10 @@ return method; } + public SSLSession getSSLSession() { + return sslSession; + } + public void close() { try { is.close(); diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServerConnection.java --- a/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServerConnection.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServerConnection.java Fri May 06 20:36:12 2016 +0000 @@ -31,6 +31,8 @@ import java.io.OutputStream; import java.net.Socket; import java.net.URI; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; import java.net.URISyntaxException; import static java.net.http.SettingsFrame.HEADER_TABLE_SIZE; import java.nio.ByteBuffer; @@ -355,7 +357,8 @@ URI uri = new URI(us); boolean pushAllowed = clientSettings.getParameter(SettingsFrame.ENABLE_PUSH) == 1; Http2TestExchange exchange = new Http2TestExchange(streamid, method, - headers, rspheaders, uri, bis, bos, this, pushAllowed); + headers, rspheaders, uri, bis, getSSLSession(), + bos, this, pushAllowed); // give to user handler.handle(exchange); @@ -368,6 +371,12 @@ } } + private SSLSession getSSLSession() { + if (! (socket instanceof SSLSocket)) + return null; + SSLSocket ssl = (SSLSocket)socket; + return ssl.getSession(); + } // Runs in own thread @SuppressWarnings({"rawtypes","unchecked"}) diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java Fri May 06 20:36:12 2016 +0000 @@ -72,6 +72,7 @@ import java.text.ParsePosition; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.YearMonth; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; @@ -794,6 +795,54 @@ assertEquals(LocalDate.of(y, m, d).format(df), expected); } + //----------------------------------------------------------------------- + @DataProvider(name="secondsPattern") + Object[][] data_secondsPattern() { + return new Object[][] { + {"A", "1", LocalTime.ofNanoOfDay(1_000_000)}, + {"A", "100000", LocalTime.ofSecondOfDay(100)}, + {"AA", "01", LocalTime.ofNanoOfDay(1_000_000)}, + {"AA", "100000", LocalTime.ofSecondOfDay(100)}, + {"AAAAAA", "100000", LocalTime.ofSecondOfDay(100)}, + {"HHmmssn", "0000001", LocalTime.ofNanoOfDay(1)}, + {"HHmmssn", "000000111", LocalTime.ofNanoOfDay(111)}, + {"HHmmssnn", "00000001", LocalTime.ofNanoOfDay(1)}, + {"HHmmssnn", "0000001111", LocalTime.ofNanoOfDay(1111)}, + {"HHmmssnnnnnn", "000000111111", LocalTime.ofNanoOfDay(111_111)}, + {"N", "1", LocalTime.ofNanoOfDay(1)}, + {"N", "100000", LocalTime.ofNanoOfDay(100_000)}, + {"NN", "01", LocalTime.ofNanoOfDay(1)}, + {"NN", "100000", LocalTime.ofNanoOfDay(100_000)}, + {"NNNNNN", "100000", LocalTime.ofNanoOfDay(100_000)}, + }; + } + + @Test(dataProvider="secondsPattern") + public void test_secondsPattern(String pattern, String input, LocalTime expected) throws Exception { + DateTimeFormatter df = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(); + assertEquals(LocalTime.parse(input, df), expected); + } + + @DataProvider(name="secondsValues") + Object[][] data_secondsValues() { + return new Object[][] { + {"A", 1, "1000"}, + {"n", 1, "0"}, + {"N", 1, "1000000000"}, + }; + } + + @Test(dataProvider="secondsValues") + public void test_secondsValues(String pattern, int seconds , String expected) throws Exception { + DateTimeFormatter df = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(); + assertEquals(LocalTime.ofSecondOfDay(seconds).format(df), expected); + } + + @Test(expectedExceptions = DateTimeParseException.class) + public void test_secondsPatternInvalidAdacentValueParsingPattern() { + // patterns A*, N*, n* will not take part in adjacent value parsing + DateTimeFormatter.ofPattern("yyyyAA").parse("201610"); + } //----------------------------------------------------------------------- @Test diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java --- a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java Fri May 06 12:45:04 2016 -0700 +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java Fri May 06 20:36:12 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -746,17 +746,17 @@ {"SSS", "Fraction(NanoOfSecond,3,3)"}, {"SSSSSSSSS", "Fraction(NanoOfSecond,9,9)"}, - {"A", "Value(MilliOfDay)"}, - {"AA", "Value(MilliOfDay,2)"}, - {"AAA", "Value(MilliOfDay,3)"}, + {"A", "Value(MilliOfDay,1,19,NOT_NEGATIVE)"}, + {"AA", "Value(MilliOfDay,2,19,NOT_NEGATIVE)"}, + {"AAA", "Value(MilliOfDay,3,19,NOT_NEGATIVE)"}, - {"n", "Value(NanoOfSecond)"}, - {"nn", "Value(NanoOfSecond,2)"}, - {"nnn", "Value(NanoOfSecond,3)"}, + {"n", "Value(NanoOfSecond,1,19,NOT_NEGATIVE)"}, + {"nn", "Value(NanoOfSecond,2,19,NOT_NEGATIVE)"}, + {"nnn", "Value(NanoOfSecond,3,19,NOT_NEGATIVE)"}, - {"N", "Value(NanoOfDay)"}, - {"NN", "Value(NanoOfDay,2)"}, - {"NNN", "Value(NanoOfDay,3)"}, + {"N", "Value(NanoOfDay,1,19,NOT_NEGATIVE)"}, + {"NN", "Value(NanoOfDay,2,19,NOT_NEGATIVE)"}, + {"NNN", "Value(NanoOfDay,3,19,NOT_NEGATIVE)"}, {"z", "ZoneText(SHORT)"}, {"zz", "ZoneText(SHORT)"}, diff -r 78e5cb21ca13 -r 6a5f9d068fc5 jdk/test/java/util/Map/EntrySetIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/Map/EntrySetIterator.java Fri May 06 20:36:12 2016 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8139233 + * @summary ensure entry set's iterator doesn't have side effects on the entry set + * @run testng EntrySetIterator + */ + +import java.util.*; +import org.testng.annotations.Test; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; + +public class EntrySetIterator { + @Test + public void main() { + Map map = Map.of("a", "1", "b", "2", "c", "3"); + Set> entrySet = map.entrySet(); + Iterator> iterator = entrySet.iterator(); + + assertTrue(iterator.hasNext()); + + // copying implicitly iterates an iterator + Set> copy1 = new HashSet<>(entrySet); + Set> copy2 = new HashSet<>(entrySet); + + assertEquals(copy2, copy1); + assertTrue(iterator.hasNext()); + } +}